diff options
Diffstat (limited to 'modules')
180 files changed, 16571 insertions, 8821 deletions
diff --git a/modules/SCsub b/modules/SCsub index f37c3a55c7..4b9c08cf78 100644 --- a/modules/SCsub +++ b/modules/SCsub @@ -1,21 +1,23 @@ +#!/usr/bin/env python + Import('env') env_modules = env.Clone() Export('env_modules') -env.modules_sources=[ - "register_module_types.cpp", +env.modules_sources = [ + "register_module_types.cpp", ] -#env.add_source_files(env.modules_sources,"*.cpp") +# env.add_source_files(env.modules_sources,"*.cpp") Export('env') for x in env.module_list: - if (x in env.disabled_modules): - continue - env_modules.Append(CPPFLAGS=["-DMODULE_"+x.upper()+"_ENABLED"]) - SConscript(x+"/SCsub") + if (x in env.disabled_modules): + continue + env_modules.Append(CPPFLAGS=["-DMODULE_" + x.upper() + "_ENABLED"]) + SConscript(x + "/SCsub") -lib = env_modules.Library("modules",env.modules_sources) +lib = env_modules.Library("modules", env.modules_sources) env.Prepend(LIBS=[lib]) diff --git a/modules/cscript/SCsub b/modules/cscript/SCsub index 403fe68f66..0882406761 100644 --- a/modules/cscript/SCsub +++ b/modules/cscript/SCsub @@ -1,5 +1,7 @@ +#!/usr/bin/env python + Import('env') -env.add_source_files(env.modules_sources,"*.cpp") +env.add_source_files(env.modules_sources, "*.cpp") Export('env') diff --git a/modules/cscript/config.py b/modules/cscript/config.py index ea7e83378a..5698a37295 100644 --- a/modules/cscript/config.py +++ b/modules/cscript/config.py @@ -1,11 +1,8 @@ def can_build(platform): - return True + return True def configure(env): - pass - - - + pass diff --git a/modules/cscript/godot_c.h b/modules/cscript/godot_c.h index b0465d8524..3bf86d1aeb 100644 --- a/modules/cscript/godot_c.h +++ b/modules/cscript/godot_c.h @@ -123,8 +123,8 @@ void GDAPI godot_array_free(godot_array p_array); #define INPUT_EVENT_TYPE_KEY 1 #define INPUT_EVENT_TYPE_MOUSE_MOTION 2 #define INPUT_EVENT_TYPE_MOUSE_BUTTON 3 -#define INPUT_EVENT_TYPE_JOYSTICK_MOTION 4 -#define INPUT_EVENT_TYPE_JOYSTICK_BUTTON 5 +#define INPUT_EVENT_TYPE_JOYPAD_MOTION 4 +#define INPUT_EVENT_TYPE_JOYPAD_BUTTON 5 #define INPUT_EVENT_TYPE_SCREEN_TOUCH 6 #define INPUT_EVENT_TYPE_SCREEN_DRAG 7 #define INPUT_EVENT_TYPE_ACTION 8 @@ -166,12 +166,12 @@ int GDAPI godot_input_event_mouse_motion_get_relative_y(godot_input_event p_even int GDAPI godot_input_event_mouse_motion_get_speed_x(godot_input_event p_event); int GDAPI godot_input_event_mouse_motion_get_speed_y(godot_input_event p_event); -int GDAPI godot_input_event_joystick_motion_get_axis(godot_input_event p_event); -float GDAPI godot_input_event_joystick_motion_get_axis_value(godot_input_event p_event); +int GDAPI godot_input_event_joypad_motion_get_axis(godot_input_event p_event); +float GDAPI godot_input_event_joypad_motion_get_axis_value(godot_input_event p_event); -int GDAPI godot_input_event_joystick_button_get_button_index(godot_input_event p_event); -godot_bool GDAPI godot_input_event_joystick_button_is_pressed(godot_input_event p_event); -float GDAPI godot_input_event_joystick_button_get_pressure(godot_input_event p_event); +int GDAPI godot_input_event_joypad_button_get_button_index(godot_input_event p_event); +godot_bool GDAPI godot_input_event_joypad_button_is_pressed(godot_input_event p_event); +float GDAPI godot_input_event_joypad_button_get_pressure(godot_input_event p_event); int GDAPI godot_input_event_screen_touch_get_index(godot_input_event p_event); diff --git a/modules/cscript/register_types.cpp b/modules/cscript/register_types.cpp index 267e5245ed..d2101bbd49 100644 --- a/modules/cscript/register_types.cpp +++ b/modules/cscript/register_types.cpp @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/modules/cscript/register_types.h b/modules/cscript/register_types.h index a0f41eee5d..6614ee3a19 100644 --- a/modules/cscript/register_types.h +++ b/modules/cscript/register_types.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/modules/dds/SCsub b/modules/dds/SCsub new file mode 100644 index 0000000000..3d92ff02d6 --- /dev/null +++ b/modules/dds/SCsub @@ -0,0 +1,8 @@ +#!/usr/bin/env python + +Import('env') +Import('env_modules') + +env_dds = env_modules.Clone() + +env_dds.add_source_files(env.modules_sources, "*.cpp") diff --git a/modules/ik/config.py b/modules/dds/config.py index f9bd7da08d..fb920482f5 100644 --- a/modules/ik/config.py +++ b/modules/dds/config.py @@ -1,11 +1,7 @@ - def can_build(platform): - return True - - + return True + + def configure(env): - pass - - - + pass diff --git a/modules/dds/register_types.cpp b/modules/dds/register_types.cpp new file mode 100644 index 0000000000..917305f543 --- /dev/null +++ b/modules/dds/register_types.cpp @@ -0,0 +1,44 @@ +/*************************************************************************/ +/* register_types.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#include "register_types.h" + +#include "texture_loader_dds.h" + +static ResourceFormatDDS *resource_loader_dds = NULL; + +void register_dds_types() { + + resource_loader_dds = memnew( ResourceFormatDDS ); + ResourceLoader::add_resource_format_loader(resource_loader_dds); +} + +void unregister_dds_types() { + + memdelete(resource_loader_dds); +} diff --git a/modules/ik/register_types.h b/modules/dds/register_types.h index 828917ade7..69f47006e2 100644 --- a/modules/ik/register_types.h +++ b/modules/dds/register_types.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -26,5 +26,5 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -void register_ik_types(); -void unregister_ik_types(); +void register_dds_types(); +void unregister_dds_types(); diff --git a/modules/dds/texture_loader_dds.cpp b/modules/dds/texture_loader_dds.cpp new file mode 100644 index 0000000000..600cae991e --- /dev/null +++ b/modules/dds/texture_loader_dds.cpp @@ -0,0 +1,484 @@ +/*************************************************************************/ +/* texture_loader_dds.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#include "texture_loader_dds.h" +#include "os/file_access.h" + + +enum { + DDS_MAGIC=0x20534444, + DDSD_CAPS=0x00000001, + DDSD_PIXELFORMAT=0x00001000, + DDSD_PITCH=0x00000008, + DDSD_LINEARSIZE=0x00080000, + DDSD_MIPMAPCOUNT=0x00020000, + DDPF_FOURCC=0x00000004, + DDPF_ALPHAPIXELS=0x00000001, + DDPF_INDEXED=0x00000020, + DDPF_RGB=0x00000040, +}; + +enum DDSFormat { + + DDS_DXT1, + DDS_DXT3, + DDS_DXT5, + DDS_ATI1, + DDS_ATI2, + DDS_BGRA8, + DDS_BGR8, + DDS_RGBA8, //flipped in dds + DDS_RGB8, //flipped in dds + DDS_BGR5A1, + DDS_BGR565, + DDS_BGR10A2, + DDS_INDEXED, + DDS_LUMINANCE, + DDS_LUMINANCE_ALPHA, + DDS_MAX +}; + +struct DDSFormatInfo { + const char *name; + bool compressed; + bool palette; + uint32_t divisor; + uint32_t block_size; + Image::Format format; +}; + + +static const DDSFormatInfo dds_format_info[DDS_MAX]={ + {"DXT1",true,false,4,8,Image::FORMAT_DXT1}, + {"DXT3",true,false,4,16,Image::FORMAT_DXT3}, + {"DXT5",true,false,4,16,Image::FORMAT_DXT5}, + {"ATI1",true,false,4,8,Image::FORMAT_ATI1}, + {"ATI2",true,false,4,16,Image::FORMAT_ATI2}, + {"BGRA8",false,false,1,4,Image::FORMAT_RGBA8}, + {"BGR8",false,false,1,3,Image::FORMAT_RGB8}, + {"RGBA8",false,false,1,4,Image::FORMAT_RGBA8}, + {"RGB8",false,false,1,3,Image::FORMAT_RGB8}, + {"BGR5A1",false,false,1,2,Image::FORMAT_RGBA8}, + {"BGR565",false,false,1,2,Image::FORMAT_RGB8}, + {"BGR10A2",false,false,1,4,Image::FORMAT_RGBA8}, + {"GRAYSCALE",false,false,1,1,Image::FORMAT_L8}, + {"GRAYSCALE_ALPHA",false,false,1,2,Image::FORMAT_LA8} +}; + + +RES ResourceFormatDDS::load(const String &p_path, const String& p_original_path, Error *r_error) { + + if (r_error) + *r_error=ERR_CANT_OPEN; + + Error err; + FileAccess *f = FileAccess::open(p_path,FileAccess::READ,&err); + if (!f) + return RES(); + + FileAccessRef fref(f); + if (r_error) + *r_error=ERR_FILE_CORRUPT; + + ERR_EXPLAIN("Unable to open DDS texture file: "+p_path); + ERR_FAIL_COND_V(err!=OK,RES()); + + uint32_t magic = f->get_32(); + uint32_t hsize = f->get_32(); + uint32_t flags = f->get_32(); + uint32_t width = f->get_32(); + uint32_t height = f->get_32(); + uint32_t pitch = f->get_32(); + /* uint32_t depth = */ f->get_32(); + uint32_t mipmaps = f->get_32(); + + //skip 11 + for(int i=0;i<11;i++) + f->get_32(); + + //validate + + if (magic!=DDS_MAGIC || hsize!=124 || !(flags&DDSD_PIXELFORMAT) || !(flags&DDSD_CAPS)) { + + ERR_EXPLAIN("Invalid or Unsupported DDS texture file: "+p_path); + ERR_FAIL_V(RES()); + } + + + /* uint32_t format_size = */ f->get_32(); + uint32_t format_flags = f->get_32(); + uint32_t format_fourcc = f->get_32(); + uint32_t format_rgb_bits = f->get_32(); + uint32_t format_red_mask = f->get_32(); + uint32_t format_green_mask = f->get_32(); + uint32_t format_blue_mask = f->get_32(); + uint32_t format_alpha_mask = f->get_32(); + + /* uint32_t caps_1 = */ f->get_32(); + /* uint32_t caps_2 = */ f->get_32(); + /* uint32_t caps_ddsx = */ f->get_32(); + + //reserved skip + f->get_32(); + f->get_32(); + + /*print_line("DDS width: "+itos(width)); + print_line("DDS height: "+itos(height)); + print_line("DDS mipmaps: "+itos(mipmaps));*/ + + //printf("fourcc: %x fflags: %x, rgbbits: %x, fsize: %x\n",format_fourcc,format_flags,format_rgb_bits,format_size); + //printf("rmask: %x gmask: %x, bmask: %x, amask: %x\n",format_red_mask,format_green_mask,format_blue_mask,format_alpha_mask); + + //must avoid this later + while(f->get_pos()<128) + f->get_8(); + + + DDSFormat dds_format; + + if (format_flags&DDPF_FOURCC && format_fourcc==0x31545844) { //'1TXD' + + dds_format=DDS_DXT1; + } else if (format_flags&DDPF_FOURCC && format_fourcc==0x33545844) { //'3TXD' + + dds_format=DDS_DXT3; + + } else if (format_flags&DDPF_FOURCC && format_fourcc==0x35545844) { //'5TXD' + + dds_format=DDS_DXT5; + } else if (format_flags&DDPF_FOURCC && format_fourcc==0x31495441) { //'1ITA' + + dds_format=DDS_ATI1; + } else if (format_flags&DDPF_FOURCC && format_fourcc==0x32495441) { //'2ITA' + + dds_format=DDS_ATI2; + + } else if (format_flags&DDPF_RGB && format_flags&DDPF_ALPHAPIXELS && format_rgb_bits==32 && format_red_mask==0xff0000 && format_green_mask==0xff00 && format_blue_mask==0xff && format_alpha_mask==0xff000000) { + + dds_format=DDS_BGRA8; + } else if (format_flags&DDPF_RGB && !(format_flags&DDPF_ALPHAPIXELS ) && format_rgb_bits==24 && format_red_mask==0xff0000 && format_green_mask==0xff00 && format_blue_mask==0xff) { + + dds_format=DDS_BGR8; + } else if (format_flags&DDPF_RGB && format_flags&DDPF_ALPHAPIXELS && format_rgb_bits==32 && format_red_mask==0xff && format_green_mask==0xff00 && format_blue_mask==0xff0000 && format_alpha_mask==0xff000000) { + + dds_format=DDS_RGBA8; + } else if (format_flags&DDPF_RGB && !(format_flags&DDPF_ALPHAPIXELS ) && format_rgb_bits==24 && format_red_mask==0xff && format_green_mask==0xff00 && format_blue_mask==0xff0000) { + + dds_format=DDS_RGB8; + + } else if (format_flags&DDPF_RGB && format_flags&DDPF_ALPHAPIXELS && format_rgb_bits==16 && format_red_mask==0x00007c00 && format_green_mask==0x000003e0 && format_blue_mask==0x0000001f && format_alpha_mask==0x00008000) { + + dds_format=DDS_BGR5A1; + } else if (format_flags&DDPF_RGB && format_flags&DDPF_ALPHAPIXELS && format_rgb_bits==32 && format_red_mask==0x3ff00000 && format_green_mask==0xffc00 && format_blue_mask==0x3ff && format_alpha_mask==0xc0000000) { + + dds_format=DDS_BGR10A2; + } else if (format_flags&DDPF_RGB && !(format_flags&DDPF_ALPHAPIXELS) && format_rgb_bits==16 && format_red_mask==0x0000f800 && format_green_mask==0x000007e0 && format_blue_mask==0x0000001f) { + + dds_format=DDS_BGR565; + } else if (!(format_flags&DDPF_ALPHAPIXELS) && format_rgb_bits==8 && format_red_mask==0xff && format_green_mask==0xff && format_blue_mask==0xff) { + + dds_format=DDS_LUMINANCE; + } else if ((format_flags&DDPF_ALPHAPIXELS) && format_rgb_bits==16 && format_red_mask==0xff && format_green_mask==0xff && format_blue_mask==0xff && format_alpha_mask==0xff00) { + + dds_format=DDS_LUMINANCE_ALPHA; + } else if (format_flags&DDPF_INDEXED && format_rgb_bits==8) { + + dds_format=DDS_BGR565; + } else { + + printf("unrecognized fourcc %x format_flags: %x - rgbbits %i - red_mask %x green mask %x blue mask %x alpha mask %x\n",format_fourcc,format_flags,format_rgb_bits,format_red_mask,format_green_mask,format_blue_mask,format_alpha_mask); + ERR_EXPLAIN("Unrecognized or Unsupported color layout in DDS: "+p_path); + + ERR_FAIL_V(RES()); + + } + + if (!(flags&DDSD_MIPMAPCOUNT)) + mipmaps=1; + + //print_line("found format: "+String(dds_format_info[dds_format].name)); + + PoolVector<uint8_t> src_data; + + const DDSFormatInfo &info=dds_format_info[dds_format]; + uint32_t w = width; + uint32_t h = height; + + + if (info.compressed) { + //compressed bc + + uint32_t size = MAX( info.divisor, w )/info.divisor * MAX( info.divisor, h )/info.divisor * info.block_size; + ERR_FAIL_COND_V( size!=pitch, RES() ); + ERR_FAIL_COND_V( !(flags&DDSD_LINEARSIZE), RES() ); + + for(uint32_t i=1;i<mipmaps;i++) { + + w=MAX(1,w>>1); + h=MAX(1,h>>1); + uint32_t bsize = MAX( info.divisor, w )/info.divisor * MAX( info.divisor, h )/info.divisor * info.block_size; + //printf("%i x %i - block: %i\n",w,h,bsize); + size+= bsize; + } + + src_data.resize(size); + PoolVector<uint8_t>::Write wb = src_data.write(); + f->get_buffer(wb.ptr(),size); + wb=PoolVector<uint8_t>::Write(); + + } else if (info.palette) { + + //indexed + ERR_FAIL_COND_V( !(flags&DDSD_PITCH), RES()); + ERR_FAIL_COND_V( format_rgb_bits!=8, RES() ); + + uint32_t size = pitch*height; + ERR_FAIL_COND_V( size != width*height * info.block_size, RES()); + + uint8_t pallete[256*4]; + f->get_buffer(pallete,256*4); + + int colsize=3; + for(int i=0;i<256;i++) { + + if (pallete[i*4+3]<255) + colsize=4; + } + + int w = width; + int h = height; + + for(uint32_t i=1;i<mipmaps;i++) { + + w=(w+1)>>1; + h=(h+1)>>1; + size+= w*h*info.block_size; + } + + src_data.resize(size + 256*colsize ); + PoolVector<uint8_t>::Write wb = src_data.write(); + f->get_buffer(wb.ptr(),size); + + for(int i=0;i<256;i++) { + + int dst_ofs = size+i*colsize; + int src_ofs = i*4; + wb[dst_ofs+0]=pallete[src_ofs+2]; + wb[dst_ofs+1]=pallete[src_ofs+1]; + wb[dst_ofs+2]=pallete[src_ofs+0]; + if (colsize==4) + wb[dst_ofs+3]=pallete[src_ofs+3]; + } + + + wb=PoolVector<uint8_t>::Write(); + } else { + //uncompressed generic... + + uint32_t size = width*height*info.block_size; + + + for(uint32_t i=1;i<mipmaps;i++) { + + w=(w+1)>>1; + h=(h+1)>>1; + size+= w*h*info.block_size; + } + + if (dds_format==DDS_BGR565) + size=size*3/2; + else if (dds_format==DDS_BGR5A1) + size=size*2; + + src_data.resize(size); + PoolVector<uint8_t>::Write wb = src_data.write(); + f->get_buffer(wb.ptr(),size); + + + switch(dds_format) { + + case DDS_BGR5A1: { + + // TO RGBA + int colcount = size/4; + + for(int i=colcount-1;i>=0;i--) { + + int src_ofs = i*2; + int dst_ofs = i*4; + + uint8_t a=wb[src_ofs+1]&0x80; + uint8_t b= wb[src_ofs]&0x1F; + uint8_t g= (wb[src_ofs]>>5) | ((wb[src_ofs+1]&0x3)<<3); + uint8_t r= (wb[src_ofs+1]>>2)&0x1F; + wb[dst_ofs+0]=r<<3; + wb[dst_ofs+1]=g<<3; + wb[dst_ofs+2]=b<<3; + wb[dst_ofs+3]=a?255:0; + } + } break; + case DDS_BGR565: { + + int colcount = size/3; + + for(int i=colcount-1;i>=0;i--) { + + int src_ofs = i*2; + int dst_ofs = i*3; + + uint8_t b= wb[src_ofs]&0x1F; + uint8_t g= (wb[src_ofs]>>5) | ((wb[src_ofs+1]&0x7)<<3); + uint8_t r= wb[src_ofs+1]>>3; + wb[dst_ofs+0]=r<<3; + wb[dst_ofs+1]=g<<2; + wb[dst_ofs+2]=b<<3;//b<<3; + + } + + } break; + case DDS_BGR10A2: { + + // TO RGBA + int colcount = size/4; + + for(int i=colcount-1;i>=0;i--) { + + int ofs = i*4; + + uint32_t w32 = uint32_t(wb[ofs+0]) | (uint32_t(wb[ofs+1])<<8) | (uint32_t(wb[ofs+2])<<16) | (uint32_t(wb[ofs+3])<<24); + + uint8_t a= (w32&0xc0000000) >> 24; + uint8_t r= (w32&0x3ff00000) >> 22; + uint8_t g= (w32&0xffc00) >> 12; + uint8_t b= (w32&0x3ff) >> 2; + + + wb[ofs+0]=r; + wb[ofs+1]=g; + wb[ofs+2]=b; + wb[ofs+3]=a==0xc0 ? 255 : a; //0xc0 should be opaque + + } + } break; + case DDS_BGRA8: { + + int colcount = size/4; + + for(int i=0;i<colcount;i++) { + + SWAP( wb[i*4+0],wb[i*4+2] ); + } + + } break; + case DDS_BGR8: { + + int colcount = size/3; + + for(int i=0;i<colcount;i++) { + + SWAP( wb[i*3+0],wb[i*3+2] ); + } + } break; + case DDS_RGBA8: { + + /* do nothing either + int colcount = size/4; + + for(int i=0;i<colcount;i++) { + + uint8_t r = wb[i*4+1]; + uint8_t g = wb[i*4+2]; + uint8_t b = wb[i*4+3]; + uint8_t a = wb[i*4+0]; + + wb[i*4+0]=r; + wb[i*4+1]=g; + wb[i*4+2]=b; + wb[i*4+3]=a; + } + */ + } break; + case DDS_RGB8: { + + // do nothing + /* + int colcount = size/3; + + for(int i=0;i<colcount;i++) { + + SWAP( wb[i*3+0],wb[i*3+2] ); + }*/ + } break; + case DDS_LUMINANCE: { + + // do nothing i guess? + + } break; + case DDS_LUMINANCE_ALPHA: { + + // do nothing i guess? + + } break; + + default: {} + + } + + wb=PoolVector<uint8_t>::Write(); + } + + + Image img(width,height,mipmaps-1,info.format,src_data); + + Ref<ImageTexture> texture = memnew( ImageTexture ); + texture->create_from_image(img); + + if (r_error) + *r_error=OK; + + + return texture; + +} + +void ResourceFormatDDS::get_recognized_extensions(List<String> *p_extensions) const { + + p_extensions->push_back("dds"); +} + +bool ResourceFormatDDS::handles_type(const String& p_type) const { + + return ClassDB::is_parent_class(p_type,"Texture"); +} + +String ResourceFormatDDS::get_resource_type(const String &p_path) const { + + if (p_path.get_extension().to_lower()=="dds") + return "ImageTexture"; + return ""; +} diff --git a/modules/dds/texture_loader_dds.h b/modules/dds/texture_loader_dds.h new file mode 100644 index 0000000000..d09af680c7 --- /dev/null +++ b/modules/dds/texture_loader_dds.h @@ -0,0 +1,46 @@ +/*************************************************************************/ +/* texture_loader_dds.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#ifndef TEXTURE_LOADER_DDS_H +#define TEXTURE_LOADER_DDS_H + +#include "scene/resources/texture.h" +#include "io/resource_loader.h" + +class ResourceFormatDDS : public ResourceFormatLoader{ +public: + + virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL); + virtual void get_recognized_extensions(List<String> *p_extensions) const; + virtual bool handles_type(const String& p_type) const; + virtual String get_resource_type(const String &p_path) const; + + virtual ~ResourceFormatDDS() {} +}; + +#endif // TEXTURE_LOADER_DDS_H diff --git a/modules/enet/SCsub b/modules/enet/SCsub index d2bc8801e4..fb22d1cff0 100644 --- a/modules/enet/SCsub +++ b/modules/enet/SCsub @@ -1,8 +1,28 @@ +#!/usr/bin/env python + Import('env') +Import('env_modules') + +# Thirdparty source files + +env_enet = env_modules.Clone() + +if (env['builtin_enet'] != 'no'): + thirdparty_dir = "#thirdparty/enet/" + thirdparty_sources = [ + "callbacks.c", + "compress.c", + "host.c", + "list.c", + "packet.c", + "peer.c", + "protocol.c", + "unix.c", + "win32.c", + ] + thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] -env.add_source_files(env.modules_sources,"*.cpp") -env.add_source_files(env.modules_sources,"*.c") -#TODO: Make it possible to build against system enet -env.Append(CPPPATH = ["#modules/enet"]) + env_enet.add_source_files(env.modules_sources, thirdparty_sources) + env_enet.Append(CPPPATH=[thirdparty_dir]) -Export('env') +env_enet.add_source_files(env.modules_sources, "*.cpp") diff --git a/modules/enet/callbacks.c b/modules/enet/callbacks.c deleted file mode 100644 index b3990af1fb..0000000000 --- a/modules/enet/callbacks.c +++ /dev/null @@ -1,53 +0,0 @@ -/** - @file callbacks.c - @brief ENet callback functions -*/ -#define ENET_BUILDING_LIB 1 -#include "enet/enet.h" - -static ENetCallbacks callbacks = { malloc, free, abort }; - -int -enet_initialize_with_callbacks (ENetVersion version, const ENetCallbacks * inits) -{ - if (version < ENET_VERSION_CREATE (1, 3, 0)) - return -1; - - if (inits -> malloc != NULL || inits -> free != NULL) - { - if (inits -> malloc == NULL || inits -> free == NULL) - return -1; - - callbacks.malloc = inits -> malloc; - callbacks.free = inits -> free; - } - - if (inits -> no_memory != NULL) - callbacks.no_memory = inits -> no_memory; - - return enet_initialize (); -} - -ENetVersion -enet_linked_version (void) -{ - return ENET_VERSION; -} - -void * -enet_malloc (size_t size) -{ - void * memory = callbacks.malloc (size); - - if (memory == NULL) - callbacks.no_memory (); - - return memory; -} - -void -enet_free (void * memory) -{ - callbacks.free (memory); -} - diff --git a/modules/enet/compress.c b/modules/enet/compress.c deleted file mode 100644 index 784489a787..0000000000 --- a/modules/enet/compress.c +++ /dev/null @@ -1,654 +0,0 @@ -/** - @file compress.c - @brief An adaptive order-2 PPM range coder -*/ -#define ENET_BUILDING_LIB 1 -#include <string.h> -#include "enet/enet.h" - -typedef struct _ENetSymbol -{ - /* binary indexed tree of symbols */ - enet_uint8 value; - enet_uint8 count; - enet_uint16 under; - enet_uint16 left, right; - - /* context defined by this symbol */ - enet_uint16 symbols; - enet_uint16 escapes; - enet_uint16 total; - enet_uint16 parent; -} ENetSymbol; - -/* adaptation constants tuned aggressively for small packet sizes rather than large file compression */ -enum -{ - ENET_RANGE_CODER_TOP = 1<<24, - ENET_RANGE_CODER_BOTTOM = 1<<16, - - ENET_CONTEXT_SYMBOL_DELTA = 3, - ENET_CONTEXT_SYMBOL_MINIMUM = 1, - ENET_CONTEXT_ESCAPE_MINIMUM = 1, - - ENET_SUBCONTEXT_ORDER = 2, - ENET_SUBCONTEXT_SYMBOL_DELTA = 2, - ENET_SUBCONTEXT_ESCAPE_DELTA = 5 -}; - -/* context exclusion roughly halves compression speed, so disable for now */ -#undef ENET_CONTEXT_EXCLUSION - -typedef struct _ENetRangeCoder -{ - /* only allocate enough symbols for reasonable MTUs, would need to be larger for large file compression */ - ENetSymbol symbols[4096]; -} ENetRangeCoder; - -void * -enet_range_coder_create (void) -{ - ENetRangeCoder * rangeCoder = (ENetRangeCoder *) enet_malloc (sizeof (ENetRangeCoder)); - if (rangeCoder == NULL) - return NULL; - - return rangeCoder; -} - -void -enet_range_coder_destroy (void * context) -{ - ENetRangeCoder * rangeCoder = (ENetRangeCoder *) context; - if (rangeCoder == NULL) - return; - - enet_free (rangeCoder); -} - -#define ENET_SYMBOL_CREATE(symbol, value_, count_) \ -{ \ - symbol = & rangeCoder -> symbols [nextSymbol ++]; \ - symbol -> value = value_; \ - symbol -> count = count_; \ - symbol -> under = count_; \ - symbol -> left = 0; \ - symbol -> right = 0; \ - symbol -> symbols = 0; \ - symbol -> escapes = 0; \ - symbol -> total = 0; \ - symbol -> parent = 0; \ -} - -#define ENET_CONTEXT_CREATE(context, escapes_, minimum) \ -{ \ - ENET_SYMBOL_CREATE (context, 0, 0); \ - (context) -> escapes = escapes_; \ - (context) -> total = escapes_ + 256*minimum; \ - (context) -> symbols = 0; \ -} - -static enet_uint16 -enet_symbol_rescale (ENetSymbol * symbol) -{ - enet_uint16 total = 0; - for (;;) - { - symbol -> count -= symbol->count >> 1; - symbol -> under = symbol -> count; - if (symbol -> left) - symbol -> under += enet_symbol_rescale (symbol + symbol -> left); - total += symbol -> under; - if (! symbol -> right) break; - symbol += symbol -> right; - } - return total; -} - -#define ENET_CONTEXT_RESCALE(context, minimum) \ -{ \ - (context) -> total = (context) -> symbols ? enet_symbol_rescale ((context) + (context) -> symbols) : 0; \ - (context) -> escapes -= (context) -> escapes >> 1; \ - (context) -> total += (context) -> escapes + 256*minimum; \ -} - -#define ENET_RANGE_CODER_OUTPUT(value) \ -{ \ - if (outData >= outEnd) \ - return 0; \ - * outData ++ = value; \ -} - -#define ENET_RANGE_CODER_ENCODE(under, count, total) \ -{ \ - encodeRange /= (total); \ - encodeLow += (under) * encodeRange; \ - encodeRange *= (count); \ - for (;;) \ - { \ - if((encodeLow ^ (encodeLow + encodeRange)) >= ENET_RANGE_CODER_TOP) \ - { \ - if(encodeRange >= ENET_RANGE_CODER_BOTTOM) break; \ - encodeRange = -encodeLow & (ENET_RANGE_CODER_BOTTOM - 1); \ - } \ - ENET_RANGE_CODER_OUTPUT (encodeLow >> 24); \ - encodeRange <<= 8; \ - encodeLow <<= 8; \ - } \ -} - -#define ENET_RANGE_CODER_FLUSH \ -{ \ - while (encodeLow) \ - { \ - ENET_RANGE_CODER_OUTPUT (encodeLow >> 24); \ - encodeLow <<= 8; \ - } \ -} - -#define ENET_RANGE_CODER_FREE_SYMBOLS \ -{ \ - if (nextSymbol >= sizeof (rangeCoder -> symbols) / sizeof (ENetSymbol) - ENET_SUBCONTEXT_ORDER ) \ - { \ - nextSymbol = 0; \ - ENET_CONTEXT_CREATE (root, ENET_CONTEXT_ESCAPE_MINIMUM, ENET_CONTEXT_SYMBOL_MINIMUM); \ - predicted = 0; \ - order = 0; \ - } \ -} - -#define ENET_CONTEXT_ENCODE(context, symbol_, value_, under_, count_, update, minimum) \ -{ \ - under_ = value*minimum; \ - count_ = minimum; \ - if (! (context) -> symbols) \ - { \ - ENET_SYMBOL_CREATE (symbol_, value_, update); \ - (context) -> symbols = symbol_ - (context); \ - } \ - else \ - { \ - ENetSymbol * node = (context) + (context) -> symbols; \ - for (;;) \ - { \ - if (value_ < node -> value) \ - { \ - node -> under += update; \ - if (node -> left) { node += node -> left; continue; } \ - ENET_SYMBOL_CREATE (symbol_, value_, update); \ - node -> left = symbol_ - node; \ - } \ - else \ - if (value_ > node -> value) \ - { \ - under_ += node -> under; \ - if (node -> right) { node += node -> right; continue; } \ - ENET_SYMBOL_CREATE (symbol_, value_, update); \ - node -> right = symbol_ - node; \ - } \ - else \ - { \ - count_ += node -> count; \ - under_ += node -> under - node -> count; \ - node -> under += update; \ - node -> count += update; \ - symbol_ = node; \ - } \ - break; \ - } \ - } \ -} - -#ifdef ENET_CONTEXT_EXCLUSION -static const ENetSymbol emptyContext = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - -#define ENET_CONTEXT_WALK(context, body) \ -{ \ - const ENetSymbol * node = (context) + (context) -> symbols; \ - const ENetSymbol * stack [256]; \ - size_t stackSize = 0; \ - while (node -> left) \ - { \ - stack [stackSize ++] = node; \ - node += node -> left; \ - } \ - for (;;) \ - { \ - body; \ - if (node -> right) \ - { \ - node += node -> right; \ - while (node -> left) \ - { \ - stack [stackSize ++] = node; \ - node += node -> left; \ - } \ - } \ - else \ - if (stackSize <= 0) \ - break; \ - else \ - node = stack [-- stackSize]; \ - } \ -} - -#define ENET_CONTEXT_ENCODE_EXCLUDE(context, value_, under, total, minimum) \ -ENET_CONTEXT_WALK(context, { \ - if (node -> value != value_) \ - { \ - enet_uint16 parentCount = rangeCoder -> symbols [node -> parent].count + minimum; \ - if (node -> value < value_) \ - under -= parentCount; \ - total -= parentCount; \ - } \ -}) -#endif - -size_t -enet_range_coder_compress (void * context, const ENetBuffer * inBuffers, size_t inBufferCount, size_t inLimit, enet_uint8 * outData, size_t outLimit) -{ - ENetRangeCoder * rangeCoder = (ENetRangeCoder *) context; - enet_uint8 * outStart = outData, * outEnd = & outData [outLimit]; - const enet_uint8 * inData, * inEnd; - enet_uint32 encodeLow = 0, encodeRange = ~0; - ENetSymbol * root; - enet_uint16 predicted = 0; - size_t order = 0, nextSymbol = 0; - - if (rangeCoder == NULL || inBufferCount <= 0 || inLimit <= 0) - return 0; - - inData = (const enet_uint8 *) inBuffers -> data; - inEnd = & inData [inBuffers -> dataLength]; - inBuffers ++; - inBufferCount --; - - ENET_CONTEXT_CREATE (root, ENET_CONTEXT_ESCAPE_MINIMUM, ENET_CONTEXT_SYMBOL_MINIMUM); - - for (;;) - { - ENetSymbol * subcontext, * symbol; -#ifdef ENET_CONTEXT_EXCLUSION - const ENetSymbol * childContext = & emptyContext; -#endif - enet_uint8 value; - enet_uint16 count, under, * parent = & predicted, total; - if (inData >= inEnd) - { - if (inBufferCount <= 0) - break; - inData = (const enet_uint8 *) inBuffers -> data; - inEnd = & inData [inBuffers -> dataLength]; - inBuffers ++; - inBufferCount --; - } - value = * inData ++; - - for (subcontext = & rangeCoder -> symbols [predicted]; - subcontext != root; -#ifdef ENET_CONTEXT_EXCLUSION - childContext = subcontext, -#endif - subcontext = & rangeCoder -> symbols [subcontext -> parent]) - { - ENET_CONTEXT_ENCODE (subcontext, symbol, value, under, count, ENET_SUBCONTEXT_SYMBOL_DELTA, 0); - * parent = symbol - rangeCoder -> symbols; - parent = & symbol -> parent; - total = subcontext -> total; -#ifdef ENET_CONTEXT_EXCLUSION - if (childContext -> total > ENET_SUBCONTEXT_SYMBOL_DELTA + ENET_SUBCONTEXT_ESCAPE_DELTA) - ENET_CONTEXT_ENCODE_EXCLUDE (childContext, value, under, total, 0); -#endif - if (count > 0) - { - ENET_RANGE_CODER_ENCODE (subcontext -> escapes + under, count, total); - } - else - { - if (subcontext -> escapes > 0 && subcontext -> escapes < total) - ENET_RANGE_CODER_ENCODE (0, subcontext -> escapes, total); - subcontext -> escapes += ENET_SUBCONTEXT_ESCAPE_DELTA; - subcontext -> total += ENET_SUBCONTEXT_ESCAPE_DELTA; - } - subcontext -> total += ENET_SUBCONTEXT_SYMBOL_DELTA; - if (count > 0xFF - 2*ENET_SUBCONTEXT_SYMBOL_DELTA || subcontext -> total > ENET_RANGE_CODER_BOTTOM - 0x100) - ENET_CONTEXT_RESCALE (subcontext, 0); - if (count > 0) goto nextInput; - } - - ENET_CONTEXT_ENCODE (root, symbol, value, under, count, ENET_CONTEXT_SYMBOL_DELTA, ENET_CONTEXT_SYMBOL_MINIMUM); - * parent = symbol - rangeCoder -> symbols; - parent = & symbol -> parent; - total = root -> total; -#ifdef ENET_CONTEXT_EXCLUSION - if (childContext -> total > ENET_SUBCONTEXT_SYMBOL_DELTA + ENET_SUBCONTEXT_ESCAPE_DELTA) - ENET_CONTEXT_ENCODE_EXCLUDE (childContext, value, under, total, ENET_CONTEXT_SYMBOL_MINIMUM); -#endif - ENET_RANGE_CODER_ENCODE (root -> escapes + under, count, total); - root -> total += ENET_CONTEXT_SYMBOL_DELTA; - if (count > 0xFF - 2*ENET_CONTEXT_SYMBOL_DELTA + ENET_CONTEXT_SYMBOL_MINIMUM || root -> total > ENET_RANGE_CODER_BOTTOM - 0x100) - ENET_CONTEXT_RESCALE (root, ENET_CONTEXT_SYMBOL_MINIMUM); - - nextInput: - if (order >= ENET_SUBCONTEXT_ORDER) - predicted = rangeCoder -> symbols [predicted].parent; - else - order ++; - ENET_RANGE_CODER_FREE_SYMBOLS; - } - - ENET_RANGE_CODER_FLUSH; - - return (size_t) (outData - outStart); -} - -#define ENET_RANGE_CODER_SEED \ -{ \ - if (inData < inEnd) decodeCode |= * inData ++ << 24; \ - if (inData < inEnd) decodeCode |= * inData ++ << 16; \ - if (inData < inEnd) decodeCode |= * inData ++ << 8; \ - if (inData < inEnd) decodeCode |= * inData ++; \ -} - -#define ENET_RANGE_CODER_READ(total) ((decodeCode - decodeLow) / (decodeRange /= (total))) - -#define ENET_RANGE_CODER_DECODE(under, count, total) \ -{ \ - decodeLow += (under) * decodeRange; \ - decodeRange *= (count); \ - for (;;) \ - { \ - if((decodeLow ^ (decodeLow + decodeRange)) >= ENET_RANGE_CODER_TOP) \ - { \ - if(decodeRange >= ENET_RANGE_CODER_BOTTOM) break; \ - decodeRange = -decodeLow & (ENET_RANGE_CODER_BOTTOM - 1); \ - } \ - decodeCode <<= 8; \ - if (inData < inEnd) \ - decodeCode |= * inData ++; \ - decodeRange <<= 8; \ - decodeLow <<= 8; \ - } \ -} - -#define ENET_CONTEXT_DECODE(context, symbol_, code, value_, under_, count_, update, minimum, createRoot, visitNode, createRight, createLeft) \ -{ \ - under_ = 0; \ - count_ = minimum; \ - if (! (context) -> symbols) \ - { \ - createRoot; \ - } \ - else \ - { \ - ENetSymbol * node = (context) + (context) -> symbols; \ - for (;;) \ - { \ - enet_uint16 after = under_ + node -> under + (node -> value + 1)*minimum, before = node -> count + minimum; \ - visitNode; \ - if (code >= after) \ - { \ - under_ += node -> under; \ - if (node -> right) { node += node -> right; continue; } \ - createRight; \ - } \ - else \ - if (code < after - before) \ - { \ - node -> under += update; \ - if (node -> left) { node += node -> left; continue; } \ - createLeft; \ - } \ - else \ - { \ - value_ = node -> value; \ - count_ += node -> count; \ - under_ = after - before; \ - node -> under += update; \ - node -> count += update; \ - symbol_ = node; \ - } \ - break; \ - } \ - } \ -} - -#define ENET_CONTEXT_TRY_DECODE(context, symbol_, code, value_, under_, count_, update, minimum, exclude) \ -ENET_CONTEXT_DECODE (context, symbol_, code, value_, under_, count_, update, minimum, return 0, exclude (node -> value, after, before), return 0, return 0) - -#define ENET_CONTEXT_ROOT_DECODE(context, symbol_, code, value_, under_, count_, update, minimum, exclude) \ -ENET_CONTEXT_DECODE (context, symbol_, code, value_, under_, count_, update, minimum, \ - { \ - value_ = code / minimum; \ - under_ = code - code%minimum; \ - ENET_SYMBOL_CREATE (symbol_, value_, update); \ - (context) -> symbols = symbol_ - (context); \ - }, \ - exclude (node -> value, after, before), \ - { \ - value_ = node->value + 1 + (code - after)/minimum; \ - under_ = code - (code - after)%minimum; \ - ENET_SYMBOL_CREATE (symbol_, value_, update); \ - node -> right = symbol_ - node; \ - }, \ - { \ - value_ = node->value - 1 - (after - before - code - 1)/minimum; \ - under_ = code - (after - before - code - 1)%minimum; \ - ENET_SYMBOL_CREATE (symbol_, value_, update); \ - node -> left = symbol_ - node; \ - }) \ - -#ifdef ENET_CONTEXT_EXCLUSION -typedef struct _ENetExclude -{ - enet_uint8 value; - enet_uint16 under; -} ENetExclude; - -#define ENET_CONTEXT_DECODE_EXCLUDE(context, total, minimum) \ -{ \ - enet_uint16 under = 0; \ - nextExclude = excludes; \ - ENET_CONTEXT_WALK (context, { \ - under += rangeCoder -> symbols [node -> parent].count + minimum; \ - nextExclude -> value = node -> value; \ - nextExclude -> under = under; \ - nextExclude ++; \ - }); \ - total -= under; \ -} - -#define ENET_CONTEXT_EXCLUDED(value_, after, before) \ -{ \ - size_t low = 0, high = nextExclude - excludes; \ - for(;;) \ - { \ - size_t mid = (low + high) >> 1; \ - const ENetExclude * exclude = & excludes [mid]; \ - if (value_ < exclude -> value) \ - { \ - if (low + 1 < high) \ - { \ - high = mid; \ - continue; \ - } \ - if (exclude > excludes) \ - after -= exclude [-1].under; \ - } \ - else \ - { \ - if (value_ > exclude -> value) \ - { \ - if (low + 1 < high) \ - { \ - low = mid; \ - continue; \ - } \ - } \ - else \ - before = 0; \ - after -= exclude -> under; \ - } \ - break; \ - } \ -} -#endif - -#define ENET_CONTEXT_NOT_EXCLUDED(value_, after, before) - -size_t -enet_range_coder_decompress (void * context, const enet_uint8 * inData, size_t inLimit, enet_uint8 * outData, size_t outLimit) -{ - ENetRangeCoder * rangeCoder = (ENetRangeCoder *) context; - enet_uint8 * outStart = outData, * outEnd = & outData [outLimit]; - const enet_uint8 * inEnd = & inData [inLimit]; - enet_uint32 decodeLow = 0, decodeCode = 0, decodeRange = ~0; - ENetSymbol * root; - enet_uint16 predicted = 0; - size_t order = 0, nextSymbol = 0; -#ifdef ENET_CONTEXT_EXCLUSION - ENetExclude excludes [256]; - ENetExclude * nextExclude = excludes; -#endif - - if (rangeCoder == NULL || inLimit <= 0) - return 0; - - ENET_CONTEXT_CREATE (root, ENET_CONTEXT_ESCAPE_MINIMUM, ENET_CONTEXT_SYMBOL_MINIMUM); - - ENET_RANGE_CODER_SEED; - - for (;;) - { - ENetSymbol * subcontext, * symbol, * patch; -#ifdef ENET_CONTEXT_EXCLUSION - const ENetSymbol * childContext = & emptyContext; -#endif - enet_uint8 value = 0; - enet_uint16 code, under, count, bottom, * parent = & predicted, total; - - for (subcontext = & rangeCoder -> symbols [predicted]; - subcontext != root; -#ifdef ENET_CONTEXT_EXCLUSION - childContext = subcontext, -#endif - subcontext = & rangeCoder -> symbols [subcontext -> parent]) - { - if (subcontext -> escapes <= 0) - continue; - total = subcontext -> total; -#ifdef ENET_CONTEXT_EXCLUSION - if (childContext -> total > 0) - ENET_CONTEXT_DECODE_EXCLUDE (childContext, total, 0); -#endif - if (subcontext -> escapes >= total) - continue; - code = ENET_RANGE_CODER_READ (total); - if (code < subcontext -> escapes) - { - ENET_RANGE_CODER_DECODE (0, subcontext -> escapes, total); - continue; - } - code -= subcontext -> escapes; -#ifdef ENET_CONTEXT_EXCLUSION - if (childContext -> total > 0) - { - ENET_CONTEXT_TRY_DECODE (subcontext, symbol, code, value, under, count, ENET_SUBCONTEXT_SYMBOL_DELTA, 0, ENET_CONTEXT_EXCLUDED); - } - else -#endif - { - ENET_CONTEXT_TRY_DECODE (subcontext, symbol, code, value, under, count, ENET_SUBCONTEXT_SYMBOL_DELTA, 0, ENET_CONTEXT_NOT_EXCLUDED); - } - bottom = symbol - rangeCoder -> symbols; - ENET_RANGE_CODER_DECODE (subcontext -> escapes + under, count, total); - subcontext -> total += ENET_SUBCONTEXT_SYMBOL_DELTA; - if (count > 0xFF - 2*ENET_SUBCONTEXT_SYMBOL_DELTA || subcontext -> total > ENET_RANGE_CODER_BOTTOM - 0x100) - ENET_CONTEXT_RESCALE (subcontext, 0); - goto patchContexts; - } - - total = root -> total; -#ifdef ENET_CONTEXT_EXCLUSION - if (childContext -> total > 0) - ENET_CONTEXT_DECODE_EXCLUDE (childContext, total, ENET_CONTEXT_SYMBOL_MINIMUM); -#endif - code = ENET_RANGE_CODER_READ (total); - if (code < root -> escapes) - { - ENET_RANGE_CODER_DECODE (0, root -> escapes, total); - break; - } - code -= root -> escapes; -#ifdef ENET_CONTEXT_EXCLUSION - if (childContext -> total > 0) - { - ENET_CONTEXT_ROOT_DECODE (root, symbol, code, value, under, count, ENET_CONTEXT_SYMBOL_DELTA, ENET_CONTEXT_SYMBOL_MINIMUM, ENET_CONTEXT_EXCLUDED); - } - else -#endif - { - ENET_CONTEXT_ROOT_DECODE (root, symbol, code, value, under, count, ENET_CONTEXT_SYMBOL_DELTA, ENET_CONTEXT_SYMBOL_MINIMUM, ENET_CONTEXT_NOT_EXCLUDED); - } - bottom = symbol - rangeCoder -> symbols; - ENET_RANGE_CODER_DECODE (root -> escapes + under, count, total); - root -> total += ENET_CONTEXT_SYMBOL_DELTA; - if (count > 0xFF - 2*ENET_CONTEXT_SYMBOL_DELTA + ENET_CONTEXT_SYMBOL_MINIMUM || root -> total > ENET_RANGE_CODER_BOTTOM - 0x100) - ENET_CONTEXT_RESCALE (root, ENET_CONTEXT_SYMBOL_MINIMUM); - - patchContexts: - for (patch = & rangeCoder -> symbols [predicted]; - patch != subcontext; - patch = & rangeCoder -> symbols [patch -> parent]) - { - ENET_CONTEXT_ENCODE (patch, symbol, value, under, count, ENET_SUBCONTEXT_SYMBOL_DELTA, 0); - * parent = symbol - rangeCoder -> symbols; - parent = & symbol -> parent; - if (count <= 0) - { - patch -> escapes += ENET_SUBCONTEXT_ESCAPE_DELTA; - patch -> total += ENET_SUBCONTEXT_ESCAPE_DELTA; - } - patch -> total += ENET_SUBCONTEXT_SYMBOL_DELTA; - if (count > 0xFF - 2*ENET_SUBCONTEXT_SYMBOL_DELTA || patch -> total > ENET_RANGE_CODER_BOTTOM - 0x100) - ENET_CONTEXT_RESCALE (patch, 0); - } - * parent = bottom; - - ENET_RANGE_CODER_OUTPUT (value); - - if (order >= ENET_SUBCONTEXT_ORDER) - predicted = rangeCoder -> symbols [predicted].parent; - else - order ++; - ENET_RANGE_CODER_FREE_SYMBOLS; - } - - return (size_t) (outData - outStart); -} - -/** @defgroup host ENet host functions - @{ -*/ - -/** Sets the packet compressor the host should use to the default range coder. - @param host host to enable the range coder for - @returns 0 on success, < 0 on failure -*/ -int -enet_host_compress_with_range_coder (ENetHost * host) -{ - ENetCompressor compressor; - memset (& compressor, 0, sizeof (compressor)); - compressor.context = enet_range_coder_create(); - if (compressor.context == NULL) - return -1; - compressor.compress = enet_range_coder_compress; - compressor.decompress = enet_range_coder_decompress; - compressor.destroy = enet_range_coder_destroy; - enet_host_compress (host, & compressor); - return 0; -} - -/** @} */ - - diff --git a/modules/enet/config.py b/modules/enet/config.py index ea7e83378a..fb920482f5 100644 --- a/modules/enet/config.py +++ b/modules/enet/config.py @@ -1,11 +1,7 @@ - def can_build(platform): - return True + return True def configure(env): - pass - - - + pass diff --git a/modules/enet/enet/callbacks.h b/modules/enet/enet/callbacks.h deleted file mode 100644 index 340a4a9896..0000000000 --- a/modules/enet/enet/callbacks.h +++ /dev/null @@ -1,27 +0,0 @@ -/** - @file callbacks.h - @brief ENet callbacks -*/ -#ifndef __ENET_CALLBACKS_H__ -#define __ENET_CALLBACKS_H__ - -#include <stdlib.h> - -typedef struct _ENetCallbacks -{ - void * (ENET_CALLBACK * malloc) (size_t size); - void (ENET_CALLBACK * free) (void * memory); - void (ENET_CALLBACK * no_memory) (void); -} ENetCallbacks; - -/** @defgroup callbacks ENet internal callbacks - @{ - @ingroup private -*/ -extern void * enet_malloc (size_t); -extern void enet_free (void *); - -/** @} */ - -#endif /* __ENET_CALLBACKS_H__ */ - diff --git a/modules/enet/enet/enet.h b/modules/enet/enet/enet.h deleted file mode 100644 index 650b199ee5..0000000000 --- a/modules/enet/enet/enet.h +++ /dev/null @@ -1,596 +0,0 @@ -/** - @file enet.h - @brief ENet public header file -*/ -#ifndef __ENET_ENET_H__ -#define __ENET_ENET_H__ - -#ifdef __cplusplus -extern "C" -{ -#endif - -#include <stdlib.h> - -#ifdef _WIN32 -#include "enet/win32.h" -#else -#include "enet/unix.h" -#endif - -#include "enet/types.h" -#include "enet/protocol.h" -#include "enet/list.h" -#include "enet/callbacks.h" - -#define ENET_VERSION_MAJOR 1 -#define ENET_VERSION_MINOR 3 -#define ENET_VERSION_PATCH 13 -#define ENET_VERSION_CREATE(major, minor, patch) (((major)<<16) | ((minor)<<8) | (patch)) -#define ENET_VERSION_GET_MAJOR(version) (((version)>>16)&0xFF) -#define ENET_VERSION_GET_MINOR(version) (((version)>>8)&0xFF) -#define ENET_VERSION_GET_PATCH(version) ((version)&0xFF) -#define ENET_VERSION ENET_VERSION_CREATE(ENET_VERSION_MAJOR, ENET_VERSION_MINOR, ENET_VERSION_PATCH) - -typedef enet_uint32 ENetVersion; - -struct _ENetHost; -struct _ENetEvent; -struct _ENetPacket; - -typedef enum _ENetSocketType -{ - ENET_SOCKET_TYPE_STREAM = 1, - ENET_SOCKET_TYPE_DATAGRAM = 2 -} ENetSocketType; - -typedef enum _ENetSocketWait -{ - ENET_SOCKET_WAIT_NONE = 0, - ENET_SOCKET_WAIT_SEND = (1 << 0), - ENET_SOCKET_WAIT_RECEIVE = (1 << 1), - ENET_SOCKET_WAIT_INTERRUPT = (1 << 2) -} ENetSocketWait; - -typedef enum _ENetSocketOption -{ - ENET_SOCKOPT_NONBLOCK = 1, - ENET_SOCKOPT_BROADCAST = 2, - ENET_SOCKOPT_RCVBUF = 3, - ENET_SOCKOPT_SNDBUF = 4, - ENET_SOCKOPT_REUSEADDR = 5, - ENET_SOCKOPT_RCVTIMEO = 6, - ENET_SOCKOPT_SNDTIMEO = 7, - ENET_SOCKOPT_ERROR = 8, - ENET_SOCKOPT_NODELAY = 9 -} ENetSocketOption; - -typedef enum _ENetSocketShutdown -{ - ENET_SOCKET_SHUTDOWN_READ = 0, - ENET_SOCKET_SHUTDOWN_WRITE = 1, - ENET_SOCKET_SHUTDOWN_READ_WRITE = 2 -} ENetSocketShutdown; - -#define ENET_HOST_ANY 0 -#define ENET_HOST_BROADCAST 0xFFFFFFFFU -#define ENET_PORT_ANY 0 - -/** - * Portable internet address structure. - * - * The host must be specified in network byte-order, and the port must be in host - * byte-order. The constant ENET_HOST_ANY may be used to specify the default - * server host. The constant ENET_HOST_BROADCAST may be used to specify the - * broadcast address (255.255.255.255). This makes sense for enet_host_connect, - * but not for enet_host_create. Once a server responds to a broadcast, the - * address is updated from ENET_HOST_BROADCAST to the server's actual IP address. - */ -typedef struct _ENetAddress -{ - enet_uint32 host; - enet_uint16 port; -} ENetAddress; - -/** - * Packet flag bit constants. - * - * The host must be specified in network byte-order, and the port must be in - * host byte-order. The constant ENET_HOST_ANY may be used to specify the - * default server host. - - @sa ENetPacket -*/ -typedef enum _ENetPacketFlag -{ - /** packet must be received by the target peer and resend attempts should be - * made until the packet is delivered */ - ENET_PACKET_FLAG_RELIABLE = (1 << 0), - /** packet will not be sequenced with other packets - * not supported for reliable packets - */ - ENET_PACKET_FLAG_UNSEQUENCED = (1 << 1), - /** packet will not allocate data, and user must supply it instead */ - ENET_PACKET_FLAG_NO_ALLOCATE = (1 << 2), - /** packet will be fragmented using unreliable (instead of reliable) sends - * if it exceeds the MTU */ - ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT = (1 << 3), - - /** whether the packet has been sent from all queues it has been entered into */ - ENET_PACKET_FLAG_SENT = (1<<8) -} ENetPacketFlag; - -typedef void (ENET_CALLBACK * ENetPacketFreeCallback) (struct _ENetPacket *); - -/** - * ENet packet structure. - * - * An ENet data packet that may be sent to or received from a peer. The shown - * fields should only be read and never modified. The data field contains the - * allocated data for the packet. The dataLength fields specifies the length - * of the allocated data. The flags field is either 0 (specifying no flags), - * or a bitwise-or of any combination of the following flags: - * - * ENET_PACKET_FLAG_RELIABLE - packet must be received by the target peer - * and resend attempts should be made until the packet is delivered - * - * ENET_PACKET_FLAG_UNSEQUENCED - packet will not be sequenced with other packets - * (not supported for reliable packets) - * - * ENET_PACKET_FLAG_NO_ALLOCATE - packet will not allocate data, and user must supply it instead - * - * ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT - packet will be fragmented using unreliable - * (instead of reliable) sends if it exceeds the MTU - * - * ENET_PACKET_FLAG_SENT - whether the packet has been sent from all queues it has been entered into - @sa ENetPacketFlag - */ -typedef struct _ENetPacket -{ - size_t referenceCount; /**< internal use only */ - enet_uint32 flags; /**< bitwise-or of ENetPacketFlag constants */ - enet_uint8 * data; /**< allocated data for packet */ - size_t dataLength; /**< length of data */ - ENetPacketFreeCallback freeCallback; /**< function to be called when the packet is no longer in use */ - void * userData; /**< application private data, may be freely modified */ -} ENetPacket; - -typedef struct _ENetAcknowledgement -{ - ENetListNode acknowledgementList; - enet_uint32 sentTime; - ENetProtocol command; -} ENetAcknowledgement; - -typedef struct _ENetOutgoingCommand -{ - ENetListNode outgoingCommandList; - enet_uint16 reliableSequenceNumber; - enet_uint16 unreliableSequenceNumber; - enet_uint32 sentTime; - enet_uint32 roundTripTimeout; - enet_uint32 roundTripTimeoutLimit; - enet_uint32 fragmentOffset; - enet_uint16 fragmentLength; - enet_uint16 sendAttempts; - ENetProtocol command; - ENetPacket * packet; -} ENetOutgoingCommand; - -typedef struct _ENetIncomingCommand -{ - ENetListNode incomingCommandList; - enet_uint16 reliableSequenceNumber; - enet_uint16 unreliableSequenceNumber; - ENetProtocol command; - enet_uint32 fragmentCount; - enet_uint32 fragmentsRemaining; - enet_uint32 * fragments; - ENetPacket * packet; -} ENetIncomingCommand; - -typedef enum _ENetPeerState -{ - ENET_PEER_STATE_DISCONNECTED = 0, - ENET_PEER_STATE_CONNECTING = 1, - ENET_PEER_STATE_ACKNOWLEDGING_CONNECT = 2, - ENET_PEER_STATE_CONNECTION_PENDING = 3, - ENET_PEER_STATE_CONNECTION_SUCCEEDED = 4, - ENET_PEER_STATE_CONNECTED = 5, - ENET_PEER_STATE_DISCONNECT_LATER = 6, - ENET_PEER_STATE_DISCONNECTING = 7, - ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT = 8, - ENET_PEER_STATE_ZOMBIE = 9 -} ENetPeerState; - -#ifndef ENET_BUFFER_MAXIMUM -#define ENET_BUFFER_MAXIMUM (1 + 2 * ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS) -#endif - -enum -{ - ENET_HOST_RECEIVE_BUFFER_SIZE = 256 * 1024, - ENET_HOST_SEND_BUFFER_SIZE = 256 * 1024, - ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL = 1000, - ENET_HOST_DEFAULT_MTU = 1400, - ENET_HOST_DEFAULT_MAXIMUM_PACKET_SIZE = 32 * 1024 * 1024, - ENET_HOST_DEFAULT_MAXIMUM_WAITING_DATA = 32 * 1024 * 1024, - - ENET_PEER_DEFAULT_ROUND_TRIP_TIME = 500, - ENET_PEER_DEFAULT_PACKET_THROTTLE = 32, - ENET_PEER_PACKET_THROTTLE_SCALE = 32, - ENET_PEER_PACKET_THROTTLE_COUNTER = 7, - ENET_PEER_PACKET_THROTTLE_ACCELERATION = 2, - ENET_PEER_PACKET_THROTTLE_DECELERATION = 2, - ENET_PEER_PACKET_THROTTLE_INTERVAL = 5000, - ENET_PEER_PACKET_LOSS_SCALE = (1 << 16), - ENET_PEER_PACKET_LOSS_INTERVAL = 10000, - ENET_PEER_WINDOW_SIZE_SCALE = 64 * 1024, - ENET_PEER_TIMEOUT_LIMIT = 32, - ENET_PEER_TIMEOUT_MINIMUM = 5000, - ENET_PEER_TIMEOUT_MAXIMUM = 30000, - ENET_PEER_PING_INTERVAL = 500, - ENET_PEER_UNSEQUENCED_WINDOWS = 64, - ENET_PEER_UNSEQUENCED_WINDOW_SIZE = 1024, - ENET_PEER_FREE_UNSEQUENCED_WINDOWS = 32, - ENET_PEER_RELIABLE_WINDOWS = 16, - ENET_PEER_RELIABLE_WINDOW_SIZE = 0x1000, - ENET_PEER_FREE_RELIABLE_WINDOWS = 8 -}; - -typedef struct _ENetChannel -{ - enet_uint16 outgoingReliableSequenceNumber; - enet_uint16 outgoingUnreliableSequenceNumber; - enet_uint16 usedReliableWindows; - enet_uint16 reliableWindows [ENET_PEER_RELIABLE_WINDOWS]; - enet_uint16 incomingReliableSequenceNumber; - enet_uint16 incomingUnreliableSequenceNumber; - ENetList incomingReliableCommands; - ENetList incomingUnreliableCommands; -} ENetChannel; - -/** - * An ENet peer which data packets may be sent or received from. - * - * No fields should be modified unless otherwise specified. - */ -typedef struct _ENetPeer -{ - ENetListNode dispatchList; - struct _ENetHost * host; - enet_uint16 outgoingPeerID; - enet_uint16 incomingPeerID; - enet_uint32 connectID; - enet_uint8 outgoingSessionID; - enet_uint8 incomingSessionID; - ENetAddress address; /**< Internet address of the peer */ - void * data; /**< Application private data, may be freely modified */ - ENetPeerState state; - ENetChannel * channels; - size_t channelCount; /**< Number of channels allocated for communication with peer */ - enet_uint32 incomingBandwidth; /**< Downstream bandwidth of the client in bytes/second */ - enet_uint32 outgoingBandwidth; /**< Upstream bandwidth of the client in bytes/second */ - enet_uint32 incomingBandwidthThrottleEpoch; - enet_uint32 outgoingBandwidthThrottleEpoch; - enet_uint32 incomingDataTotal; - enet_uint32 outgoingDataTotal; - enet_uint32 lastSendTime; - enet_uint32 lastReceiveTime; - enet_uint32 nextTimeout; - enet_uint32 earliestTimeout; - enet_uint32 packetLossEpoch; - enet_uint32 packetsSent; - enet_uint32 packetsLost; - enet_uint32 packetLoss; /**< mean packet loss of reliable packets as a ratio with respect to the constant ENET_PEER_PACKET_LOSS_SCALE */ - enet_uint32 packetLossVariance; - enet_uint32 packetThrottle; - enet_uint32 packetThrottleLimit; - enet_uint32 packetThrottleCounter; - enet_uint32 packetThrottleEpoch; - enet_uint32 packetThrottleAcceleration; - enet_uint32 packetThrottleDeceleration; - enet_uint32 packetThrottleInterval; - enet_uint32 pingInterval; - enet_uint32 timeoutLimit; - enet_uint32 timeoutMinimum; - enet_uint32 timeoutMaximum; - enet_uint32 lastRoundTripTime; - enet_uint32 lowestRoundTripTime; - enet_uint32 lastRoundTripTimeVariance; - enet_uint32 highestRoundTripTimeVariance; - enet_uint32 roundTripTime; /**< mean round trip time (RTT), in milliseconds, between sending a reliable packet and receiving its acknowledgement */ - enet_uint32 roundTripTimeVariance; - enet_uint32 mtu; - enet_uint32 windowSize; - enet_uint32 reliableDataInTransit; - enet_uint16 outgoingReliableSequenceNumber; - ENetList acknowledgements; - ENetList sentReliableCommands; - ENetList sentUnreliableCommands; - ENetList outgoingReliableCommands; - ENetList outgoingUnreliableCommands; - ENetList dispatchedCommands; - int needsDispatch; - enet_uint16 incomingUnsequencedGroup; - enet_uint16 outgoingUnsequencedGroup; - enet_uint32 unsequencedWindow [ENET_PEER_UNSEQUENCED_WINDOW_SIZE / 32]; - enet_uint32 eventData; - size_t totalWaitingData; -} ENetPeer; - -/** An ENet packet compressor for compressing UDP packets before socket sends or receives. - */ -typedef struct _ENetCompressor -{ - /** Context data for the compressor. Must be non-NULL. */ - void * context; - /** Compresses from inBuffers[0:inBufferCount-1], containing inLimit bytes, to outData, outputting at most outLimit bytes. Should return 0 on failure. */ - size_t (ENET_CALLBACK * compress) (void * context, const ENetBuffer * inBuffers, size_t inBufferCount, size_t inLimit, enet_uint8 * outData, size_t outLimit); - /** Decompresses from inData, containing inLimit bytes, to outData, outputting at most outLimit bytes. Should return 0 on failure. */ - size_t (ENET_CALLBACK * decompress) (void * context, const enet_uint8 * inData, size_t inLimit, enet_uint8 * outData, size_t outLimit); - /** Destroys the context when compression is disabled or the host is destroyed. May be NULL. */ - void (ENET_CALLBACK * destroy) (void * context); -} ENetCompressor; - -/** Callback that computes the checksum of the data held in buffers[0:bufferCount-1] */ -typedef enet_uint32 (ENET_CALLBACK * ENetChecksumCallback) (const ENetBuffer * buffers, size_t bufferCount); - -/** Callback for intercepting received raw UDP packets. Should return 1 to intercept, 0 to ignore, or -1 to propagate an error. */ -typedef int (ENET_CALLBACK * ENetInterceptCallback) (struct _ENetHost * host, struct _ENetEvent * event); - -/** An ENet host for communicating with peers. - * - * No fields should be modified unless otherwise stated. - - @sa enet_host_create() - @sa enet_host_destroy() - @sa enet_host_connect() - @sa enet_host_service() - @sa enet_host_flush() - @sa enet_host_broadcast() - @sa enet_host_compress() - @sa enet_host_compress_with_range_coder() - @sa enet_host_channel_limit() - @sa enet_host_bandwidth_limit() - @sa enet_host_bandwidth_throttle() - */ -typedef struct _ENetHost -{ - ENetSocket socket; - ENetAddress address; /**< Internet address of the host */ - enet_uint32 incomingBandwidth; /**< downstream bandwidth of the host */ - enet_uint32 outgoingBandwidth; /**< upstream bandwidth of the host */ - enet_uint32 bandwidthThrottleEpoch; - enet_uint32 mtu; - enet_uint32 randomSeed; - int recalculateBandwidthLimits; - ENetPeer * peers; /**< array of peers allocated for this host */ - size_t peerCount; /**< number of peers allocated for this host */ - size_t channelLimit; /**< maximum number of channels allowed for connected peers */ - enet_uint32 serviceTime; - ENetList dispatchQueue; - int continueSending; - size_t packetSize; - enet_uint16 headerFlags; - ENetProtocol commands [ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS]; - size_t commandCount; - ENetBuffer buffers [ENET_BUFFER_MAXIMUM]; - size_t bufferCount; - ENetChecksumCallback checksum; /**< callback the user can set to enable packet checksums for this host */ - ENetCompressor compressor; - enet_uint8 packetData [2][ENET_PROTOCOL_MAXIMUM_MTU]; - ENetAddress receivedAddress; - enet_uint8 * receivedData; - size_t receivedDataLength; - enet_uint32 totalSentData; /**< total data sent, user should reset to 0 as needed to prevent overflow */ - enet_uint32 totalSentPackets; /**< total UDP packets sent, user should reset to 0 as needed to prevent overflow */ - enet_uint32 totalReceivedData; /**< total data received, user should reset to 0 as needed to prevent overflow */ - enet_uint32 totalReceivedPackets; /**< total UDP packets received, user should reset to 0 as needed to prevent overflow */ - ENetInterceptCallback intercept; /**< callback the user can set to intercept received raw UDP packets */ - size_t connectedPeers; - size_t bandwidthLimitedPeers; - size_t duplicatePeers; /**< optional number of allowed peers from duplicate IPs, defaults to ENET_PROTOCOL_MAXIMUM_PEER_ID */ - size_t maximumPacketSize; /**< the maximum allowable packet size that may be sent or received on a peer */ - size_t maximumWaitingData; /**< the maximum aggregate amount of buffer space a peer may use waiting for packets to be delivered */ -} ENetHost; - -/** - * An ENet event type, as specified in @ref ENetEvent. - */ -typedef enum _ENetEventType -{ - /** no event occurred within the specified time limit */ - ENET_EVENT_TYPE_NONE = 0, - - /** a connection request initiated by enet_host_connect has completed. - * The peer field contains the peer which successfully connected. - */ - ENET_EVENT_TYPE_CONNECT = 1, - - /** a peer has disconnected. This event is generated on a successful - * completion of a disconnect initiated by enet_peer_disconnect, if - * a peer has timed out, or if a connection request intialized by - * enet_host_connect has timed out. The peer field contains the peer - * which disconnected. The data field contains user supplied data - * describing the disconnection, or 0, if none is available. - */ - ENET_EVENT_TYPE_DISCONNECT = 2, - - /** a packet has been received from a peer. The peer field specifies the - * peer which sent the packet. The channelID field specifies the channel - * number upon which the packet was received. The packet field contains - * the packet that was received; this packet must be destroyed with - * enet_packet_destroy after use. - */ - ENET_EVENT_TYPE_RECEIVE = 3 -} ENetEventType; - -/** - * An ENet event as returned by enet_host_service(). - - @sa enet_host_service - */ -typedef struct _ENetEvent -{ - ENetEventType type; /**< type of the event */ - ENetPeer * peer; /**< peer that generated a connect, disconnect or receive event */ - enet_uint8 channelID; /**< channel on the peer that generated the event, if appropriate */ - enet_uint32 data; /**< data associated with the event, if appropriate */ - ENetPacket * packet; /**< packet associated with the event, if appropriate */ -} ENetEvent; - -/** @defgroup global ENet global functions - @{ -*/ - -/** - Initializes ENet globally. Must be called prior to using any functions in - ENet. - @returns 0 on success, < 0 on failure -*/ -ENET_API int enet_initialize (void); - -/** - Initializes ENet globally and supplies user-overridden callbacks. Must be called prior to using any functions in ENet. Do not use enet_initialize() if you use this variant. Make sure the ENetCallbacks structure is zeroed out so that any additional callbacks added in future versions will be properly ignored. - - @param version the constant ENET_VERSION should be supplied so ENet knows which version of ENetCallbacks struct to use - @param inits user-overridden callbacks where any NULL callbacks will use ENet's defaults - @returns 0 on success, < 0 on failure -*/ -ENET_API int enet_initialize_with_callbacks (ENetVersion version, const ENetCallbacks * inits); - -/** - Shuts down ENet globally. Should be called when a program that has - initialized ENet exits. -*/ -ENET_API void enet_deinitialize (void); - -/** - Gives the linked version of the ENet library. - @returns the version number -*/ -ENET_API ENetVersion enet_linked_version (void); - -/** @} */ - -/** @defgroup private ENet private implementation functions */ - -/** - Returns the wall-time in milliseconds. Its initial value is unspecified - unless otherwise set. - */ -ENET_API enet_uint32 enet_time_get (void); -/** - Sets the current wall-time in milliseconds. - */ -ENET_API void enet_time_set (enet_uint32); - -/** @defgroup socket ENet socket functions - @{ -*/ -ENET_API ENetSocket enet_socket_create (ENetSocketType); -ENET_API int enet_socket_bind (ENetSocket, const ENetAddress *); -ENET_API int enet_socket_get_address (ENetSocket, ENetAddress *); -ENET_API int enet_socket_listen (ENetSocket, int); -ENET_API ENetSocket enet_socket_accept (ENetSocket, ENetAddress *); -ENET_API int enet_socket_connect (ENetSocket, const ENetAddress *); -ENET_API int enet_socket_send (ENetSocket, const ENetAddress *, const ENetBuffer *, size_t); -ENET_API int enet_socket_receive (ENetSocket, ENetAddress *, ENetBuffer *, size_t); -ENET_API int enet_socket_wait (ENetSocket, enet_uint32 *, enet_uint32); -ENET_API int enet_socket_set_option (ENetSocket, ENetSocketOption, int); -ENET_API int enet_socket_get_option (ENetSocket, ENetSocketOption, int *); -ENET_API int enet_socket_shutdown (ENetSocket, ENetSocketShutdown); -ENET_API void enet_socket_destroy (ENetSocket); -ENET_API int enet_socketset_select (ENetSocket, ENetSocketSet *, ENetSocketSet *, enet_uint32); - -/** @} */ - -/** @defgroup Address ENet address functions - @{ -*/ -/** Attempts to resolve the host named by the parameter hostName and sets - the host field in the address parameter if successful. - @param address destination to store resolved address - @param hostName host name to lookup - @retval 0 on success - @retval < 0 on failure - @returns the address of the given hostName in address on success -*/ -ENET_API int enet_address_set_host (ENetAddress * address, const char * hostName); - -/** Gives the printable form of the IP address specified in the address parameter. - @param address address printed - @param hostName destination for name, must not be NULL - @param nameLength maximum length of hostName. - @returns the null-terminated name of the host in hostName on success - @retval 0 on success - @retval < 0 on failure -*/ -ENET_API int enet_address_get_host_ip (const ENetAddress * address, char * hostName, size_t nameLength); - -/** Attempts to do a reverse lookup of the host field in the address parameter. - @param address address used for reverse lookup - @param hostName destination for name, must not be NULL - @param nameLength maximum length of hostName. - @returns the null-terminated name of the host in hostName on success - @retval 0 on success - @retval < 0 on failure -*/ -ENET_API int enet_address_get_host (const ENetAddress * address, char * hostName, size_t nameLength); - -/** @} */ - -ENET_API ENetPacket * enet_packet_create (const void *, size_t, enet_uint32); -ENET_API void enet_packet_destroy (ENetPacket *); -ENET_API int enet_packet_resize (ENetPacket *, size_t); -ENET_API enet_uint32 enet_crc32 (const ENetBuffer *, size_t); - -ENET_API ENetHost * enet_host_create (const ENetAddress *, size_t, size_t, enet_uint32, enet_uint32); -ENET_API void enet_host_destroy (ENetHost *); -ENET_API ENetPeer * enet_host_connect (ENetHost *, const ENetAddress *, size_t, enet_uint32); -ENET_API int enet_host_check_events (ENetHost *, ENetEvent *); -ENET_API int enet_host_service (ENetHost *, ENetEvent *, enet_uint32); -ENET_API void enet_host_flush (ENetHost *); -ENET_API void enet_host_broadcast (ENetHost *, enet_uint8, ENetPacket *); -ENET_API void enet_host_compress (ENetHost *, const ENetCompressor *); -ENET_API int enet_host_compress_with_range_coder (ENetHost * host); -ENET_API void enet_host_channel_limit (ENetHost *, size_t); -ENET_API void enet_host_bandwidth_limit (ENetHost *, enet_uint32, enet_uint32); -extern void enet_host_bandwidth_throttle (ENetHost *); -extern enet_uint32 enet_host_random_seed (void); - -ENET_API int enet_peer_send (ENetPeer *, enet_uint8, ENetPacket *); -ENET_API ENetPacket * enet_peer_receive (ENetPeer *, enet_uint8 * channelID); -ENET_API void enet_peer_ping (ENetPeer *); -ENET_API void enet_peer_ping_interval (ENetPeer *, enet_uint32); -ENET_API void enet_peer_timeout (ENetPeer *, enet_uint32, enet_uint32, enet_uint32); -ENET_API void enet_peer_reset (ENetPeer *); -ENET_API void enet_peer_disconnect (ENetPeer *, enet_uint32); -ENET_API void enet_peer_disconnect_now (ENetPeer *, enet_uint32); -ENET_API void enet_peer_disconnect_later (ENetPeer *, enet_uint32); -ENET_API void enet_peer_throttle_configure (ENetPeer *, enet_uint32, enet_uint32, enet_uint32); -extern int enet_peer_throttle (ENetPeer *, enet_uint32); -extern void enet_peer_reset_queues (ENetPeer *); -extern void enet_peer_setup_outgoing_command (ENetPeer *, ENetOutgoingCommand *); -extern ENetOutgoingCommand * enet_peer_queue_outgoing_command (ENetPeer *, const ENetProtocol *, ENetPacket *, enet_uint32, enet_uint16); -extern ENetIncomingCommand * enet_peer_queue_incoming_command (ENetPeer *, const ENetProtocol *, const void *, size_t, enet_uint32, enet_uint32); -extern ENetAcknowledgement * enet_peer_queue_acknowledgement (ENetPeer *, const ENetProtocol *, enet_uint16); -extern void enet_peer_dispatch_incoming_unreliable_commands (ENetPeer *, ENetChannel *); -extern void enet_peer_dispatch_incoming_reliable_commands (ENetPeer *, ENetChannel *); -extern void enet_peer_on_connect (ENetPeer *); -extern void enet_peer_on_disconnect (ENetPeer *); - -ENET_API void * enet_range_coder_create (void); -ENET_API void enet_range_coder_destroy (void *); -ENET_API size_t enet_range_coder_compress (void *, const ENetBuffer *, size_t, size_t, enet_uint8 *, size_t); -ENET_API size_t enet_range_coder_decompress (void *, const enet_uint8 *, size_t, enet_uint8 *, size_t); - -extern size_t enet_protocol_command_size (enet_uint8); - -#ifdef __cplusplus -} -#endif - -#endif /* __ENET_ENET_H__ */ - diff --git a/modules/enet/enet/list.h b/modules/enet/enet/list.h deleted file mode 100644 index d7b2600848..0000000000 --- a/modules/enet/enet/list.h +++ /dev/null @@ -1,43 +0,0 @@ -/** - @file list.h - @brief ENet list management -*/ -#ifndef __ENET_LIST_H__ -#define __ENET_LIST_H__ - -#include <stdlib.h> - -typedef struct _ENetListNode -{ - struct _ENetListNode * next; - struct _ENetListNode * previous; -} ENetListNode; - -typedef ENetListNode * ENetListIterator; - -typedef struct _ENetList -{ - ENetListNode sentinel; -} ENetList; - -extern void enet_list_clear (ENetList *); - -extern ENetListIterator enet_list_insert (ENetListIterator, void *); -extern void * enet_list_remove (ENetListIterator); -extern ENetListIterator enet_list_move (ENetListIterator, void *, void *); - -extern size_t enet_list_size (ENetList *); - -#define enet_list_begin(list) ((list) -> sentinel.next) -#define enet_list_end(list) (& (list) -> sentinel) - -#define enet_list_empty(list) (enet_list_begin (list) == enet_list_end (list)) - -#define enet_list_next(iterator) ((iterator) -> next) -#define enet_list_previous(iterator) ((iterator) -> previous) - -#define enet_list_front(list) ((void *) (list) -> sentinel.next) -#define enet_list_back(list) ((void *) (list) -> sentinel.previous) - -#endif /* __ENET_LIST_H__ */ - diff --git a/modules/enet/enet/protocol.h b/modules/enet/enet/protocol.h deleted file mode 100644 index f8c73d8a66..0000000000 --- a/modules/enet/enet/protocol.h +++ /dev/null @@ -1,198 +0,0 @@ -/** - @file protocol.h - @brief ENet protocol -*/ -#ifndef __ENET_PROTOCOL_H__ -#define __ENET_PROTOCOL_H__ - -#include "enet/types.h" - -enum -{ - ENET_PROTOCOL_MINIMUM_MTU = 576, - ENET_PROTOCOL_MAXIMUM_MTU = 4096, - ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS = 32, - ENET_PROTOCOL_MINIMUM_WINDOW_SIZE = 4096, - ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE = 65536, - ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT = 1, - ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT = 255, - ENET_PROTOCOL_MAXIMUM_PEER_ID = 0xFFF, - ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT = 1024 * 1024 -}; - -typedef enum _ENetProtocolCommand -{ - ENET_PROTOCOL_COMMAND_NONE = 0, - ENET_PROTOCOL_COMMAND_ACKNOWLEDGE = 1, - ENET_PROTOCOL_COMMAND_CONNECT = 2, - ENET_PROTOCOL_COMMAND_VERIFY_CONNECT = 3, - ENET_PROTOCOL_COMMAND_DISCONNECT = 4, - ENET_PROTOCOL_COMMAND_PING = 5, - ENET_PROTOCOL_COMMAND_SEND_RELIABLE = 6, - ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE = 7, - ENET_PROTOCOL_COMMAND_SEND_FRAGMENT = 8, - ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED = 9, - ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT = 10, - ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE = 11, - ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT = 12, - ENET_PROTOCOL_COMMAND_COUNT = 13, - - ENET_PROTOCOL_COMMAND_MASK = 0x0F -} ENetProtocolCommand; - -typedef enum _ENetProtocolFlag -{ - ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE = (1 << 7), - ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED = (1 << 6), - - ENET_PROTOCOL_HEADER_FLAG_COMPRESSED = (1 << 14), - ENET_PROTOCOL_HEADER_FLAG_SENT_TIME = (1 << 15), - ENET_PROTOCOL_HEADER_FLAG_MASK = ENET_PROTOCOL_HEADER_FLAG_COMPRESSED | ENET_PROTOCOL_HEADER_FLAG_SENT_TIME, - - ENET_PROTOCOL_HEADER_SESSION_MASK = (3 << 12), - ENET_PROTOCOL_HEADER_SESSION_SHIFT = 12 -} ENetProtocolFlag; - -#ifdef _MSC_VER -#pragma pack(push, 1) -#define ENET_PACKED -#elif defined(__GNUC__) || defined(__clang__) -#define ENET_PACKED __attribute__ ((packed)) -#else -#define ENET_PACKED -#endif - -typedef struct _ENetProtocolHeader -{ - enet_uint16 peerID; - enet_uint16 sentTime; -} ENET_PACKED ENetProtocolHeader; - -typedef struct _ENetProtocolCommandHeader -{ - enet_uint8 command; - enet_uint8 channelID; - enet_uint16 reliableSequenceNumber; -} ENET_PACKED ENetProtocolCommandHeader; - -typedef struct _ENetProtocolAcknowledge -{ - ENetProtocolCommandHeader header; - enet_uint16 receivedReliableSequenceNumber; - enet_uint16 receivedSentTime; -} ENET_PACKED ENetProtocolAcknowledge; - -typedef struct _ENetProtocolConnect -{ - ENetProtocolCommandHeader header; - enet_uint16 outgoingPeerID; - enet_uint8 incomingSessionID; - enet_uint8 outgoingSessionID; - enet_uint32 mtu; - enet_uint32 windowSize; - enet_uint32 channelCount; - enet_uint32 incomingBandwidth; - enet_uint32 outgoingBandwidth; - enet_uint32 packetThrottleInterval; - enet_uint32 packetThrottleAcceleration; - enet_uint32 packetThrottleDeceleration; - enet_uint32 connectID; - enet_uint32 data; -} ENET_PACKED ENetProtocolConnect; - -typedef struct _ENetProtocolVerifyConnect -{ - ENetProtocolCommandHeader header; - enet_uint16 outgoingPeerID; - enet_uint8 incomingSessionID; - enet_uint8 outgoingSessionID; - enet_uint32 mtu; - enet_uint32 windowSize; - enet_uint32 channelCount; - enet_uint32 incomingBandwidth; - enet_uint32 outgoingBandwidth; - enet_uint32 packetThrottleInterval; - enet_uint32 packetThrottleAcceleration; - enet_uint32 packetThrottleDeceleration; - enet_uint32 connectID; -} ENET_PACKED ENetProtocolVerifyConnect; - -typedef struct _ENetProtocolBandwidthLimit -{ - ENetProtocolCommandHeader header; - enet_uint32 incomingBandwidth; - enet_uint32 outgoingBandwidth; -} ENET_PACKED ENetProtocolBandwidthLimit; - -typedef struct _ENetProtocolThrottleConfigure -{ - ENetProtocolCommandHeader header; - enet_uint32 packetThrottleInterval; - enet_uint32 packetThrottleAcceleration; - enet_uint32 packetThrottleDeceleration; -} ENET_PACKED ENetProtocolThrottleConfigure; - -typedef struct _ENetProtocolDisconnect -{ - ENetProtocolCommandHeader header; - enet_uint32 data; -} ENET_PACKED ENetProtocolDisconnect; - -typedef struct _ENetProtocolPing -{ - ENetProtocolCommandHeader header; -} ENET_PACKED ENetProtocolPing; - -typedef struct _ENetProtocolSendReliable -{ - ENetProtocolCommandHeader header; - enet_uint16 dataLength; -} ENET_PACKED ENetProtocolSendReliable; - -typedef struct _ENetProtocolSendUnreliable -{ - ENetProtocolCommandHeader header; - enet_uint16 unreliableSequenceNumber; - enet_uint16 dataLength; -} ENET_PACKED ENetProtocolSendUnreliable; - -typedef struct _ENetProtocolSendUnsequenced -{ - ENetProtocolCommandHeader header; - enet_uint16 unsequencedGroup; - enet_uint16 dataLength; -} ENET_PACKED ENetProtocolSendUnsequenced; - -typedef struct _ENetProtocolSendFragment -{ - ENetProtocolCommandHeader header; - enet_uint16 startSequenceNumber; - enet_uint16 dataLength; - enet_uint32 fragmentCount; - enet_uint32 fragmentNumber; - enet_uint32 totalLength; - enet_uint32 fragmentOffset; -} ENET_PACKED ENetProtocolSendFragment; - -typedef union _ENetProtocol -{ - ENetProtocolCommandHeader header; - ENetProtocolAcknowledge acknowledge; - ENetProtocolConnect connect; - ENetProtocolVerifyConnect verifyConnect; - ENetProtocolDisconnect disconnect; - ENetProtocolPing ping; - ENetProtocolSendReliable sendReliable; - ENetProtocolSendUnreliable sendUnreliable; - ENetProtocolSendUnsequenced sendUnsequenced; - ENetProtocolSendFragment sendFragment; - ENetProtocolBandwidthLimit bandwidthLimit; - ENetProtocolThrottleConfigure throttleConfigure; -} ENET_PACKED ENetProtocol; - -#ifdef _MSC_VER -#pragma pack(pop) -#endif - -#endif /* __ENET_PROTOCOL_H__ */ - diff --git a/modules/enet/enet/time.h b/modules/enet/enet/time.h deleted file mode 100644 index c82a546035..0000000000 --- a/modules/enet/enet/time.h +++ /dev/null @@ -1,18 +0,0 @@ -/** - @file time.h - @brief ENet time constants and macros -*/ -#ifndef __ENET_TIME_H__ -#define __ENET_TIME_H__ - -#define ENET_TIME_OVERFLOW 86400000 - -#define ENET_TIME_LESS(a, b) ((a) - (b) >= ENET_TIME_OVERFLOW) -#define ENET_TIME_GREATER(a, b) ((b) - (a) >= ENET_TIME_OVERFLOW) -#define ENET_TIME_LESS_EQUAL(a, b) (! ENET_TIME_GREATER (a, b)) -#define ENET_TIME_GREATER_EQUAL(a, b) (! ENET_TIME_LESS (a, b)) - -#define ENET_TIME_DIFFERENCE(a, b) ((a) - (b) >= ENET_TIME_OVERFLOW ? (b) - (a) : (a) - (b)) - -#endif /* __ENET_TIME_H__ */ - diff --git a/modules/enet/enet/types.h b/modules/enet/enet/types.h deleted file mode 100644 index ab010a4b13..0000000000 --- a/modules/enet/enet/types.h +++ /dev/null @@ -1,13 +0,0 @@ -/** - @file types.h - @brief type definitions for ENet -*/ -#ifndef __ENET_TYPES_H__ -#define __ENET_TYPES_H__ - -typedef unsigned char enet_uint8; /**< unsigned 8-bit type */ -typedef unsigned short enet_uint16; /**< unsigned 16-bit type */ -typedef unsigned int enet_uint32; /**< unsigned 32-bit type */ - -#endif /* __ENET_TYPES_H__ */ - diff --git a/modules/enet/enet/unix.h b/modules/enet/enet/unix.h deleted file mode 100644 index a59e340606..0000000000 --- a/modules/enet/enet/unix.h +++ /dev/null @@ -1,47 +0,0 @@ -/** - @file unix.h - @brief ENet Unix header -*/ -#ifndef __ENET_UNIX_H__ -#define __ENET_UNIX_H__ - -#include <stdlib.h> -#include <sys/time.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <unistd.h> - -#ifdef MSG_MAXIOVLEN -#define ENET_BUFFER_MAXIMUM MSG_MAXIOVLEN -#endif - -typedef int ENetSocket; - -#define ENET_SOCKET_NULL -1 - -#define ENET_HOST_TO_NET_16(value) (htons (value)) /**< macro that converts host to net byte-order of a 16-bit value */ -#define ENET_HOST_TO_NET_32(value) (htonl (value)) /**< macro that converts host to net byte-order of a 32-bit value */ - -#define ENET_NET_TO_HOST_16(value) (ntohs (value)) /**< macro that converts net to host byte-order of a 16-bit value */ -#define ENET_NET_TO_HOST_32(value) (ntohl (value)) /**< macro that converts net to host byte-order of a 32-bit value */ - -typedef struct -{ - void * data; - size_t dataLength; -} ENetBuffer; - -#define ENET_CALLBACK - -#define ENET_API extern - -typedef fd_set ENetSocketSet; - -#define ENET_SOCKETSET_EMPTY(sockset) FD_ZERO (& (sockset)) -#define ENET_SOCKETSET_ADD(sockset, socket) FD_SET (socket, & (sockset)) -#define ENET_SOCKETSET_REMOVE(sockset, socket) FD_CLR (socket, & (sockset)) -#define ENET_SOCKETSET_CHECK(sockset, socket) FD_ISSET (socket, & (sockset)) - -#endif /* __ENET_UNIX_H__ */ - diff --git a/modules/enet/enet/utility.h b/modules/enet/enet/utility.h deleted file mode 100644 index e48a476be3..0000000000 --- a/modules/enet/enet/utility.h +++ /dev/null @@ -1,12 +0,0 @@ -/** - @file utility.h - @brief ENet utility header -*/ -#ifndef __ENET_UTILITY_H__ -#define __ENET_UTILITY_H__ - -#define ENET_MAX(x, y) ((x) > (y) ? (x) : (y)) -#define ENET_MIN(x, y) ((x) < (y) ? (x) : (y)) - -#endif /* __ENET_UTILITY_H__ */ - diff --git a/modules/enet/enet/win32.h b/modules/enet/enet/win32.h deleted file mode 100644 index e73ca9d052..0000000000 --- a/modules/enet/enet/win32.h +++ /dev/null @@ -1,57 +0,0 @@ -/** - @file win32.h - @brief ENet Win32 header -*/ -#ifndef __ENET_WIN32_H__ -#define __ENET_WIN32_H__ - -#ifdef _MSC_VER -#ifdef ENET_BUILDING_LIB -#pragma warning (disable: 4267) // size_t to int conversion -#pragma warning (disable: 4244) // 64bit to 32bit int -#pragma warning (disable: 4018) // signed/unsigned mismatch -#pragma warning (disable: 4146) // unary minus operator applied to unsigned type -#endif -#endif - -#include <stdlib.h> -#include <winsock2.h> - -typedef SOCKET ENetSocket; - -#define ENET_SOCKET_NULL INVALID_SOCKET - -#define ENET_HOST_TO_NET_16(value) (htons (value)) -#define ENET_HOST_TO_NET_32(value) (htonl (value)) - -#define ENET_NET_TO_HOST_16(value) (ntohs (value)) -#define ENET_NET_TO_HOST_32(value) (ntohl (value)) - -typedef struct -{ - size_t dataLength; - void * data; -} ENetBuffer; - -#define ENET_CALLBACK __cdecl - -#ifdef ENET_DLL -#ifdef ENET_BUILDING_LIB -#define ENET_API __declspec( dllexport ) -#else -#define ENET_API __declspec( dllimport ) -#endif /* ENET_BUILDING_LIB */ -#else /* !ENET_DLL */ -#define ENET_API extern -#endif /* ENET_DLL */ - -typedef fd_set ENetSocketSet; - -#define ENET_SOCKETSET_EMPTY(sockset) FD_ZERO (& (sockset)) -#define ENET_SOCKETSET_ADD(sockset, socket) FD_SET (socket, & (sockset)) -#define ENET_SOCKETSET_REMOVE(sockset, socket) FD_CLR (socket, & (sockset)) -#define ENET_SOCKETSET_CHECK(sockset, socket) FD_ISSET (socket, & (sockset)) - -#endif /* __ENET_WIN32_H__ */ - - diff --git a/modules/enet/host.c b/modules/enet/host.c deleted file mode 100644 index 3be6c0922c..0000000000 --- a/modules/enet/host.c +++ /dev/null @@ -1,492 +0,0 @@ -/** - @file host.c - @brief ENet host management functions -*/ -#define ENET_BUILDING_LIB 1 -#include <string.h> -#include "enet/enet.h" - -/** @defgroup host ENet host functions - @{ -*/ - -/** Creates a host for communicating to peers. - - @param address the address at which other peers may connect to this host. If NULL, then no peers may connect to the host. - @param peerCount the maximum number of peers that should be allocated for the host. - @param channelLimit the maximum number of channels allowed; if 0, then this is equivalent to ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT - @param incomingBandwidth downstream bandwidth of the host in bytes/second; if 0, ENet will assume unlimited bandwidth. - @param outgoingBandwidth upstream bandwidth of the host in bytes/second; if 0, ENet will assume unlimited bandwidth. - - @returns the host on success and NULL on failure - - @remarks ENet will strategically drop packets on specific sides of a connection between hosts - to ensure the host's bandwidth is not overwhelmed. The bandwidth parameters also determine - the window size of a connection which limits the amount of reliable packets that may be in transit - at any given time. -*/ -ENetHost * -enet_host_create (const ENetAddress * address, size_t peerCount, size_t channelLimit, enet_uint32 incomingBandwidth, enet_uint32 outgoingBandwidth) -{ - ENetHost * host; - ENetPeer * currentPeer; - - if (peerCount > ENET_PROTOCOL_MAXIMUM_PEER_ID) - return NULL; - - host = (ENetHost *) enet_malloc (sizeof (ENetHost)); - if (host == NULL) - return NULL; - memset (host, 0, sizeof (ENetHost)); - - host -> peers = (ENetPeer *) enet_malloc (peerCount * sizeof (ENetPeer)); - if (host -> peers == NULL) - { - enet_free (host); - - return NULL; - } - memset (host -> peers, 0, peerCount * sizeof (ENetPeer)); - - host -> socket = enet_socket_create (ENET_SOCKET_TYPE_DATAGRAM); - if (host -> socket == ENET_SOCKET_NULL || (address != NULL && enet_socket_bind (host -> socket, address) < 0)) - { - if (host -> socket != ENET_SOCKET_NULL) - enet_socket_destroy (host -> socket); - - enet_free (host -> peers); - enet_free (host); - - return NULL; - } - - enet_socket_set_option (host -> socket, ENET_SOCKOPT_NONBLOCK, 1); - enet_socket_set_option (host -> socket, ENET_SOCKOPT_BROADCAST, 1); - enet_socket_set_option (host -> socket, ENET_SOCKOPT_RCVBUF, ENET_HOST_RECEIVE_BUFFER_SIZE); - enet_socket_set_option (host -> socket, ENET_SOCKOPT_SNDBUF, ENET_HOST_SEND_BUFFER_SIZE); - - if (address != NULL && enet_socket_get_address (host -> socket, & host -> address) < 0) - host -> address = * address; - - if (! channelLimit || channelLimit > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT) - channelLimit = ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT; - else - if (channelLimit < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT) - channelLimit = ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT; - - host -> randomSeed = (enet_uint32) (size_t) host; - host -> randomSeed += enet_host_random_seed (); - host -> randomSeed = (host -> randomSeed << 16) | (host -> randomSeed >> 16); - host -> channelLimit = channelLimit; - host -> incomingBandwidth = incomingBandwidth; - host -> outgoingBandwidth = outgoingBandwidth; - host -> bandwidthThrottleEpoch = 0; - host -> recalculateBandwidthLimits = 0; - host -> mtu = ENET_HOST_DEFAULT_MTU; - host -> peerCount = peerCount; - host -> commandCount = 0; - host -> bufferCount = 0; - host -> checksum = NULL; - host -> receivedAddress.host = ENET_HOST_ANY; - host -> receivedAddress.port = 0; - host -> receivedData = NULL; - host -> receivedDataLength = 0; - - host -> totalSentData = 0; - host -> totalSentPackets = 0; - host -> totalReceivedData = 0; - host -> totalReceivedPackets = 0; - - host -> connectedPeers = 0; - host -> bandwidthLimitedPeers = 0; - host -> duplicatePeers = ENET_PROTOCOL_MAXIMUM_PEER_ID; - host -> maximumPacketSize = ENET_HOST_DEFAULT_MAXIMUM_PACKET_SIZE; - host -> maximumWaitingData = ENET_HOST_DEFAULT_MAXIMUM_WAITING_DATA; - - host -> compressor.context = NULL; - host -> compressor.compress = NULL; - host -> compressor.decompress = NULL; - host -> compressor.destroy = NULL; - - host -> intercept = NULL; - - enet_list_clear (& host -> dispatchQueue); - - for (currentPeer = host -> peers; - currentPeer < & host -> peers [host -> peerCount]; - ++ currentPeer) - { - currentPeer -> host = host; - currentPeer -> incomingPeerID = currentPeer - host -> peers; - currentPeer -> outgoingSessionID = currentPeer -> incomingSessionID = 0xFF; - currentPeer -> data = NULL; - - enet_list_clear (& currentPeer -> acknowledgements); - enet_list_clear (& currentPeer -> sentReliableCommands); - enet_list_clear (& currentPeer -> sentUnreliableCommands); - enet_list_clear (& currentPeer -> outgoingReliableCommands); - enet_list_clear (& currentPeer -> outgoingUnreliableCommands); - enet_list_clear (& currentPeer -> dispatchedCommands); - - enet_peer_reset (currentPeer); - } - - return host; -} - -/** Destroys the host and all resources associated with it. - @param host pointer to the host to destroy -*/ -void -enet_host_destroy (ENetHost * host) -{ - ENetPeer * currentPeer; - - if (host == NULL) - return; - - enet_socket_destroy (host -> socket); - - for (currentPeer = host -> peers; - currentPeer < & host -> peers [host -> peerCount]; - ++ currentPeer) - { - enet_peer_reset (currentPeer); - } - - if (host -> compressor.context != NULL && host -> compressor.destroy) - (* host -> compressor.destroy) (host -> compressor.context); - - enet_free (host -> peers); - enet_free (host); -} - -/** Initiates a connection to a foreign host. - @param host host seeking the connection - @param address destination for the connection - @param channelCount number of channels to allocate - @param data user data supplied to the receiving host - @returns a peer representing the foreign host on success, NULL on failure - @remarks The peer returned will have not completed the connection until enet_host_service() - notifies of an ENET_EVENT_TYPE_CONNECT event for the peer. -*/ -ENetPeer * -enet_host_connect (ENetHost * host, const ENetAddress * address, size_t channelCount, enet_uint32 data) -{ - ENetPeer * currentPeer; - ENetChannel * channel; - ENetProtocol command; - - if (channelCount < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT) - channelCount = ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT; - else - if (channelCount > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT) - channelCount = ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT; - - for (currentPeer = host -> peers; - currentPeer < & host -> peers [host -> peerCount]; - ++ currentPeer) - { - if (currentPeer -> state == ENET_PEER_STATE_DISCONNECTED) - break; - } - - if (currentPeer >= & host -> peers [host -> peerCount]) - return NULL; - - currentPeer -> channels = (ENetChannel *) enet_malloc (channelCount * sizeof (ENetChannel)); - if (currentPeer -> channels == NULL) - return NULL; - currentPeer -> channelCount = channelCount; - currentPeer -> state = ENET_PEER_STATE_CONNECTING; - currentPeer -> address = * address; - currentPeer -> connectID = ++ host -> randomSeed; - - if (host -> outgoingBandwidth == 0) - currentPeer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; - else - currentPeer -> windowSize = (host -> outgoingBandwidth / - ENET_PEER_WINDOW_SIZE_SCALE) * - ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; - - if (currentPeer -> windowSize < ENET_PROTOCOL_MINIMUM_WINDOW_SIZE) - currentPeer -> windowSize = ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; - else - if (currentPeer -> windowSize > ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE) - currentPeer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; - - for (channel = currentPeer -> channels; - channel < & currentPeer -> channels [channelCount]; - ++ channel) - { - channel -> outgoingReliableSequenceNumber = 0; - channel -> outgoingUnreliableSequenceNumber = 0; - channel -> incomingReliableSequenceNumber = 0; - channel -> incomingUnreliableSequenceNumber = 0; - - enet_list_clear (& channel -> incomingReliableCommands); - enet_list_clear (& channel -> incomingUnreliableCommands); - - channel -> usedReliableWindows = 0; - memset (channel -> reliableWindows, 0, sizeof (channel -> reliableWindows)); - } - - command.header.command = ENET_PROTOCOL_COMMAND_CONNECT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; - command.header.channelID = 0xFF; - command.connect.outgoingPeerID = ENET_HOST_TO_NET_16 (currentPeer -> incomingPeerID); - command.connect.incomingSessionID = currentPeer -> incomingSessionID; - command.connect.outgoingSessionID = currentPeer -> outgoingSessionID; - command.connect.mtu = ENET_HOST_TO_NET_32 (currentPeer -> mtu); - command.connect.windowSize = ENET_HOST_TO_NET_32 (currentPeer -> windowSize); - command.connect.channelCount = ENET_HOST_TO_NET_32 (channelCount); - command.connect.incomingBandwidth = ENET_HOST_TO_NET_32 (host -> incomingBandwidth); - command.connect.outgoingBandwidth = ENET_HOST_TO_NET_32 (host -> outgoingBandwidth); - command.connect.packetThrottleInterval = ENET_HOST_TO_NET_32 (currentPeer -> packetThrottleInterval); - command.connect.packetThrottleAcceleration = ENET_HOST_TO_NET_32 (currentPeer -> packetThrottleAcceleration); - command.connect.packetThrottleDeceleration = ENET_HOST_TO_NET_32 (currentPeer -> packetThrottleDeceleration); - command.connect.connectID = currentPeer -> connectID; - command.connect.data = ENET_HOST_TO_NET_32 (data); - - enet_peer_queue_outgoing_command (currentPeer, & command, NULL, 0, 0); - - return currentPeer; -} - -/** Queues a packet to be sent to all peers associated with the host. - @param host host on which to broadcast the packet - @param channelID channel on which to broadcast - @param packet packet to broadcast -*/ -void -enet_host_broadcast (ENetHost * host, enet_uint8 channelID, ENetPacket * packet) -{ - ENetPeer * currentPeer; - - for (currentPeer = host -> peers; - currentPeer < & host -> peers [host -> peerCount]; - ++ currentPeer) - { - if (currentPeer -> state != ENET_PEER_STATE_CONNECTED) - continue; - - enet_peer_send (currentPeer, channelID, packet); - } - - if (packet -> referenceCount == 0) - enet_packet_destroy (packet); -} - -/** Sets the packet compressor the host should use to compress and decompress packets. - @param host host to enable or disable compression for - @param compressor callbacks for for the packet compressor; if NULL, then compression is disabled -*/ -void -enet_host_compress (ENetHost * host, const ENetCompressor * compressor) -{ - if (host -> compressor.context != NULL && host -> compressor.destroy) - (* host -> compressor.destroy) (host -> compressor.context); - - if (compressor) - host -> compressor = * compressor; - else - host -> compressor.context = NULL; -} - -/** Limits the maximum allowed channels of future incoming connections. - @param host host to limit - @param channelLimit the maximum number of channels allowed; if 0, then this is equivalent to ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT -*/ -void -enet_host_channel_limit (ENetHost * host, size_t channelLimit) -{ - if (! channelLimit || channelLimit > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT) - channelLimit = ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT; - else - if (channelLimit < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT) - channelLimit = ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT; - - host -> channelLimit = channelLimit; -} - - -/** Adjusts the bandwidth limits of a host. - @param host host to adjust - @param incomingBandwidth new incoming bandwidth - @param outgoingBandwidth new outgoing bandwidth - @remarks the incoming and outgoing bandwidth parameters are identical in function to those - specified in enet_host_create(). -*/ -void -enet_host_bandwidth_limit (ENetHost * host, enet_uint32 incomingBandwidth, enet_uint32 outgoingBandwidth) -{ - host -> incomingBandwidth = incomingBandwidth; - host -> outgoingBandwidth = outgoingBandwidth; - host -> recalculateBandwidthLimits = 1; -} - -void -enet_host_bandwidth_throttle (ENetHost * host) -{ - enet_uint32 timeCurrent = enet_time_get (), - elapsedTime = timeCurrent - host -> bandwidthThrottleEpoch, - peersRemaining = (enet_uint32) host -> connectedPeers, - dataTotal = ~0, - bandwidth = ~0, - throttle = 0, - bandwidthLimit = 0; - int needsAdjustment = host -> bandwidthLimitedPeers > 0 ? 1 : 0; - ENetPeer * peer; - ENetProtocol command; - - if (elapsedTime < ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL) - return; - - host -> bandwidthThrottleEpoch = timeCurrent; - - if (peersRemaining == 0) - return; - - if (host -> outgoingBandwidth != 0) - { - dataTotal = 0; - bandwidth = (host -> outgoingBandwidth * elapsedTime) / 1000; - - for (peer = host -> peers; - peer < & host -> peers [host -> peerCount]; - ++ peer) - { - if (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) - continue; - - dataTotal += peer -> outgoingDataTotal; - } - } - - while (peersRemaining > 0 && needsAdjustment != 0) - { - needsAdjustment = 0; - - if (dataTotal <= bandwidth) - throttle = ENET_PEER_PACKET_THROTTLE_SCALE; - else - throttle = (bandwidth * ENET_PEER_PACKET_THROTTLE_SCALE) / dataTotal; - - for (peer = host -> peers; - peer < & host -> peers [host -> peerCount]; - ++ peer) - { - enet_uint32 peerBandwidth; - - if ((peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) || - peer -> incomingBandwidth == 0 || - peer -> outgoingBandwidthThrottleEpoch == timeCurrent) - continue; - - peerBandwidth = (peer -> incomingBandwidth * elapsedTime) / 1000; - if ((throttle * peer -> outgoingDataTotal) / ENET_PEER_PACKET_THROTTLE_SCALE <= peerBandwidth) - continue; - - peer -> packetThrottleLimit = (peerBandwidth * - ENET_PEER_PACKET_THROTTLE_SCALE) / peer -> outgoingDataTotal; - - if (peer -> packetThrottleLimit == 0) - peer -> packetThrottleLimit = 1; - - if (peer -> packetThrottle > peer -> packetThrottleLimit) - peer -> packetThrottle = peer -> packetThrottleLimit; - - peer -> outgoingBandwidthThrottleEpoch = timeCurrent; - - peer -> incomingDataTotal = 0; - peer -> outgoingDataTotal = 0; - - needsAdjustment = 1; - -- peersRemaining; - bandwidth -= peerBandwidth; - dataTotal -= peerBandwidth; - } - } - - if (peersRemaining > 0) - { - if (dataTotal <= bandwidth) - throttle = ENET_PEER_PACKET_THROTTLE_SCALE; - else - throttle = (bandwidth * ENET_PEER_PACKET_THROTTLE_SCALE) / dataTotal; - - for (peer = host -> peers; - peer < & host -> peers [host -> peerCount]; - ++ peer) - { - if ((peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) || - peer -> outgoingBandwidthThrottleEpoch == timeCurrent) - continue; - - peer -> packetThrottleLimit = throttle; - - if (peer -> packetThrottle > peer -> packetThrottleLimit) - peer -> packetThrottle = peer -> packetThrottleLimit; - - peer -> incomingDataTotal = 0; - peer -> outgoingDataTotal = 0; - } - } - - if (host -> recalculateBandwidthLimits) - { - host -> recalculateBandwidthLimits = 0; - - peersRemaining = (enet_uint32) host -> connectedPeers; - bandwidth = host -> incomingBandwidth; - needsAdjustment = 1; - - if (bandwidth == 0) - bandwidthLimit = 0; - else - while (peersRemaining > 0 && needsAdjustment != 0) - { - needsAdjustment = 0; - bandwidthLimit = bandwidth / peersRemaining; - - for (peer = host -> peers; - peer < & host -> peers [host -> peerCount]; - ++ peer) - { - if ((peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) || - peer -> incomingBandwidthThrottleEpoch == timeCurrent) - continue; - - if (peer -> outgoingBandwidth > 0 && - peer -> outgoingBandwidth >= bandwidthLimit) - continue; - - peer -> incomingBandwidthThrottleEpoch = timeCurrent; - - needsAdjustment = 1; - -- peersRemaining; - bandwidth -= peer -> outgoingBandwidth; - } - } - - for (peer = host -> peers; - peer < & host -> peers [host -> peerCount]; - ++ peer) - { - if (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) - continue; - - command.header.command = ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; - command.header.channelID = 0xFF; - command.bandwidthLimit.outgoingBandwidth = ENET_HOST_TO_NET_32 (host -> outgoingBandwidth); - - if (peer -> incomingBandwidthThrottleEpoch == timeCurrent) - command.bandwidthLimit.incomingBandwidth = ENET_HOST_TO_NET_32 (peer -> outgoingBandwidth); - else - command.bandwidthLimit.incomingBandwidth = ENET_HOST_TO_NET_32 (bandwidthLimit); - - enet_peer_queue_outgoing_command (peer, & command, NULL, 0, 0); - } - } -} - -/** @} */ diff --git a/modules/enet/list.c b/modules/enet/list.c deleted file mode 100644 index 1c1a8dfaaf..0000000000 --- a/modules/enet/list.c +++ /dev/null @@ -1,75 +0,0 @@ -/** - @file list.c - @brief ENet linked list functions -*/ -#define ENET_BUILDING_LIB 1 -#include "enet/enet.h" - -/** - @defgroup list ENet linked list utility functions - @ingroup private - @{ -*/ -void -enet_list_clear (ENetList * list) -{ - list -> sentinel.next = & list -> sentinel; - list -> sentinel.previous = & list -> sentinel; -} - -ENetListIterator -enet_list_insert (ENetListIterator position, void * data) -{ - ENetListIterator result = (ENetListIterator) data; - - result -> previous = position -> previous; - result -> next = position; - - result -> previous -> next = result; - position -> previous = result; - - return result; -} - -void * -enet_list_remove (ENetListIterator position) -{ - position -> previous -> next = position -> next; - position -> next -> previous = position -> previous; - - return position; -} - -ENetListIterator -enet_list_move (ENetListIterator position, void * dataFirst, void * dataLast) -{ - ENetListIterator first = (ENetListIterator) dataFirst, - last = (ENetListIterator) dataLast; - - first -> previous -> next = last -> next; - last -> next -> previous = first -> previous; - - first -> previous = position -> previous; - last -> next = position; - - first -> previous -> next = first; - position -> previous = last; - - return first; -} - -size_t -enet_list_size (ENetList * list) -{ - size_t size = 0; - ENetListIterator position; - - for (position = enet_list_begin (list); - position != enet_list_end (list); - position = enet_list_next (position)) - ++ size; - - return size; -} - -/** @} */ diff --git a/modules/enet/networked_multiplayer_enet.cpp b/modules/enet/networked_multiplayer_enet.cpp index 18a4347edf..af555b7eb6 100644 --- a/modules/enet/networked_multiplayer_enet.cpp +++ b/modules/enet/networked_multiplayer_enet.cpp @@ -1,3 +1,31 @@ +/*************************************************************************/ +/* networked_multiplayer_enet.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ #include "os/os.h" #include "io/marshalls.h" #include "networked_multiplayer_enet.h" @@ -32,7 +60,7 @@ Error NetworkedMultiplayerENet::create_server(int p_port, int p_max_clients, int host = enet_host_create (& address /* the address to bind the server host to */, p_max_clients /* allow up to 32 clients and/or outgoing connections */, - 2 /* allow up to 2 channels to be used, 0 and 1 */, + SYSCH_MAX /* allow up to SYSCH_MAX channels to be used */, p_in_bandwidth /* assume any amount of incoming bandwidth */, p_out_bandwidth /* assume any amount of outgoing bandwidth */); @@ -49,10 +77,11 @@ Error NetworkedMultiplayerENet::create_server(int p_port, int p_max_clients, int Error NetworkedMultiplayerENet::create_client(const IP_Address& p_ip, int p_port, int p_in_bandwidth, int p_out_bandwidth){ ERR_FAIL_COND_V(active,ERR_ALREADY_IN_USE); + ERR_FAIL_COND_V(!p_ip.is_ipv4(), ERR_INVALID_PARAMETER); host = enet_host_create (NULL /* create a client host */, 1 /* only allow 1 outgoing connection */, - 2 /* allow up 2 channels to be used, 0 and 1 */, + SYSCH_MAX /* allow up to SYSCH_MAX channels to be used */, p_in_bandwidth /* 56K modem with 56 Kbps downstream bandwidth */, p_out_bandwidth /* 56K modem with 14 Kbps upstream bandwidth */); @@ -62,7 +91,7 @@ Error NetworkedMultiplayerENet::create_client(const IP_Address& p_ip, int p_port _setup_compressor(); ENetAddress address; - address.host=p_ip.host; + address.host=*((uint32_t *)p_ip.get_ipv4()); address.port=p_port; //enet_address_set_host (& address, "localhost"); @@ -70,8 +99,8 @@ Error NetworkedMultiplayerENet::create_client(const IP_Address& p_ip, int p_port unique_id=_gen_unique_id(); - /* Initiate the connection, allocating the two channels 0 and 1. */ - ENetPeer *peer = enet_host_connect (host, & address, 2, unique_id); + /* Initiate the connection, allocating the enough channels */ + ENetPeer *peer = enet_host_connect (host, & address, SYSCH_MAX, unique_id); if (peer == NULL) { enet_host_destroy(host); @@ -121,7 +150,7 @@ void NetworkedMultiplayerENet::poll(){ } IP_Address ip; - ip.host=event.peer -> address.host; + ip.set_ipv4((uint8_t *)&(event.peer -> address.host)); int *new_id = memnew( int ); *new_id = event.data; @@ -148,12 +177,12 @@ void NetworkedMultiplayerENet::poll(){ ENetPacket * packet = enet_packet_create (NULL,8,ENET_PACKET_FLAG_RELIABLE); encode_uint32(SYSMSG_ADD_PEER,&packet->data[0]); encode_uint32(E->key(),&packet->data[4]); - enet_peer_send(event.peer,1,packet); + enet_peer_send(event.peer,SYSCH_CONFIG,packet); //send the new peer to existing peers packet = enet_packet_create (NULL,8,ENET_PACKET_FLAG_RELIABLE); encode_uint32(SYSMSG_ADD_PEER,&packet->data[0]); encode_uint32(*new_id,&packet->data[4]); - enet_peer_send(E->get(),1,packet); + enet_peer_send(E->get(),SYSCH_CONFIG,packet); } } else { @@ -185,7 +214,7 @@ void NetworkedMultiplayerENet::poll(){ ENetPacket* packet = enet_packet_create (NULL,8,ENET_PACKET_FLAG_RELIABLE); encode_uint32(SYSMSG_REMOVE_PEER,&packet->data[0]); encode_uint32(*id,&packet->data[4]); - enet_peer_send(E->get(),1,packet); + enet_peer_send(E->get(),SYSCH_CONFIG,packet); } } else if (!server) { emit_signal("server_disconnected"); @@ -204,10 +233,13 @@ void NetworkedMultiplayerENet::poll(){ case ENET_EVENT_TYPE_RECEIVE: { - if (event.channelID==1) { + if (event.channelID==SYSCH_CONFIG) { //some config message ERR_CONTINUE( event.packet->dataLength < 8); + // Only server can send config messages + ERR_CONTINUE( server ); + int msg = decode_uint32(&event.packet->data[0]); int id = decode_uint32(&event.packet->data[4]); @@ -226,12 +258,12 @@ void NetworkedMultiplayerENet::poll(){ } enet_packet_destroy(event.packet); - } else if (event.channelID==0){ + } else if (event.channelID < SYSCH_MAX){ Packet packet; packet.packet = event.packet; - int *id = (int*)event.peer -> data; + uint32_t *id = (uint32_t*)event.peer->data; ERR_CONTINUE(event.packet->dataLength<12) @@ -243,6 +275,8 @@ void NetworkedMultiplayerENet::poll(){ packet.from=source; if (server) { + // Someone is cheating and trying to fake the source! + ERR_CONTINUE(source!=*id); packet.from=*id; @@ -258,7 +292,7 @@ void NetworkedMultiplayerENet::poll(){ ENetPacket* packet2 = enet_packet_create (packet.packet->data,packet.packet->dataLength,flags); - enet_peer_send(E->get(),0,packet2); + enet_peer_send(E->get(),event.channelID,packet2); } } else if (target<0) { @@ -272,7 +306,7 @@ void NetworkedMultiplayerENet::poll(){ ENetPacket* packet2 = enet_packet_create (packet.packet->data,packet.packet->dataLength,flags); - enet_peer_send(E->get(),0,packet2); + enet_peer_send(E->get(),event.channelID,packet2); } if (-target != 1) { @@ -289,7 +323,7 @@ void NetworkedMultiplayerENet::poll(){ } else { //to someone else, specifically ERR_CONTINUE(!peer_map.has(target)); - enet_peer_send(peer_map[target],0,packet.packet); + enet_peer_send(peer_map[target],event.channelID,packet.packet); } } else { @@ -359,7 +393,7 @@ Error NetworkedMultiplayerENet::get_packet(const uint8_t **r_buffer,int &r_buffe incoming_packets.pop_front(); *r_buffer=(const uint8_t*)(¤t_packet.packet->data[12]); - r_buffer_size=current_packet.packet->dataLength; + r_buffer_size=current_packet.packet->dataLength-12; return OK; } @@ -369,16 +403,20 @@ Error NetworkedMultiplayerENet::put_packet(const uint8_t *p_buffer,int p_buffer_ ERR_FAIL_COND_V(connection_status!=CONNECTION_CONNECTED,ERR_UNCONFIGURED); int packet_flags=0; + int channel=SYSCH_RELIABLE; switch(transfer_mode) { case TRANSFER_MODE_UNRELIABLE: { packet_flags=ENET_PACKET_FLAG_UNSEQUENCED; + channel=SYSCH_UNRELIABLE; } break; case TRANSFER_MODE_UNRELIABLE_ORDERED: { packet_flags=0; + channel=SYSCH_UNRELIABLE; } break; case TRANSFER_MODE_RELIABLE: { packet_flags=ENET_PACKET_FLAG_RELIABLE; + channel=SYSCH_RELIABLE; } break; } @@ -402,7 +440,7 @@ Error NetworkedMultiplayerENet::put_packet(const uint8_t *p_buffer,int p_buffer_ if (server) { if (target_peer==0) { - enet_host_broadcast(host,0,packet); + enet_host_broadcast(host,channel,packet); } else if (target_peer<0) { //send to all but one //and make copies for sending @@ -416,18 +454,18 @@ Error NetworkedMultiplayerENet::put_packet(const uint8_t *p_buffer,int p_buffer_ ENetPacket* packet2 = enet_packet_create (packet->data,packet->dataLength,packet_flags); - enet_peer_send(F->get(),0,packet2); + enet_peer_send(F->get(),channel,packet2); } enet_packet_destroy(packet); //original packet no longer needed } else { - enet_peer_send (E->get(), 0, packet); + enet_peer_send (E->get(), channel, packet); } } else { ERR_FAIL_COND_V(!peer_map.has(1),ERR_BUG); - enet_peer_send (peer_map[1], 0, packet); //send to server for broadcast.. + enet_peer_send (peer_map[1], channel, packet); //send to server for broadcast.. } @@ -468,8 +506,10 @@ uint32_t NetworkedMultiplayerENet::_gen_unique_id() const { (uint32_t)OS::get_singleton()->get_unix_time(), hash ); hash = hash_djb2_one_32( (uint32_t)OS::get_singleton()->get_data_dir().hash64(), hash ); - //hash = hash_djb2_one_32( - // (uint32_t)OS::get_singleton()->get_unique_ID().hash64(), hash ); + /* + hash = hash_djb2_one_32( + (uint32_t)OS::get_singleton()->get_unique_ID().hash64(), hash ); + */ hash = hash_djb2_one_32( (uint32_t)((uint64_t)this), hash ); //rely on aslr heap hash = hash_djb2_one_32( @@ -605,12 +645,12 @@ void NetworkedMultiplayerENet::enet_compressor_destroy(void * context){ void NetworkedMultiplayerENet::_bind_methods() { - ObjectTypeDB::bind_method(_MD("create_server","port","max_clients","in_bandwidth","out_bandwidth"),&NetworkedMultiplayerENet::create_server,DEFVAL(32),DEFVAL(0),DEFVAL(0)); - ObjectTypeDB::bind_method(_MD("create_client","ip","port","in_bandwidth","out_bandwidth"),&NetworkedMultiplayerENet::create_client,DEFVAL(0),DEFVAL(0)); - ObjectTypeDB::bind_method(_MD("close_connection"),&NetworkedMultiplayerENet::close_connection); - ObjectTypeDB::bind_method(_MD("set_compression_mode","mode"),&NetworkedMultiplayerENet::set_compression_mode); - ObjectTypeDB::bind_method(_MD("get_compression_mode"),&NetworkedMultiplayerENet::get_compression_mode); - ObjectTypeDB::bind_method(_MD("set_bind_ip", "ip"),&NetworkedMultiplayerENet::set_bind_ip); + ClassDB::bind_method(D_METHOD("create_server","port","max_clients","in_bandwidth","out_bandwidth"),&NetworkedMultiplayerENet::create_server,DEFVAL(32),DEFVAL(0),DEFVAL(0)); + ClassDB::bind_method(D_METHOD("create_client","ip","port","in_bandwidth","out_bandwidth"),&NetworkedMultiplayerENet::create_client,DEFVAL(0),DEFVAL(0)); + ClassDB::bind_method(D_METHOD("close_connection"),&NetworkedMultiplayerENet::close_connection); + ClassDB::bind_method(D_METHOD("set_compression_mode","mode"),&NetworkedMultiplayerENet::set_compression_mode); + ClassDB::bind_method(D_METHOD("get_compression_mode"),&NetworkedMultiplayerENet::get_compression_mode); + ClassDB::bind_method(D_METHOD("set_bind_ip", "ip"),&NetworkedMultiplayerENet::set_bind_ip); BIND_CONSTANT( COMPRESS_NONE ); BIND_CONSTANT( COMPRESS_RANGE_CODER ); @@ -646,5 +686,6 @@ NetworkedMultiplayerENet::~NetworkedMultiplayerENet(){ // sets IP for ENet to bind when using create_server // if no IP is set, then ENet bind to ENET_HOST_ANY void NetworkedMultiplayerENet::set_bind_ip(const IP_Address& p_ip){ - bind_ip=p_ip.host; + ERR_FAIL_COND(!p_ip.is_ipv4()); + bind_ip=*(uint32_t *)p_ip.get_ipv4(); } diff --git a/modules/enet/networked_multiplayer_enet.h b/modules/enet/networked_multiplayer_enet.h index 59863c1f78..dcf8c2429b 100644 --- a/modules/enet/networked_multiplayer_enet.h +++ b/modules/enet/networked_multiplayer_enet.h @@ -1,3 +1,31 @@ +/*************************************************************************/ +/* networked_multiplayer_enet.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ #ifndef NETWORKED_MULTIPLAYER_ENET_H #define NETWORKED_MULTIPLAYER_ENET_H @@ -7,7 +35,7 @@ class NetworkedMultiplayerENet : public NetworkedMultiplayerPeer { - OBJ_TYPE(NetworkedMultiplayerENet,NetworkedMultiplayerPeer) + GDCLASS(NetworkedMultiplayerENet,NetworkedMultiplayerPeer) public: enum CompressionMode { COMPRESS_NONE, @@ -23,6 +51,13 @@ private: SYSMSG_REMOVE_PEER }; + enum { + SYSCH_CONFIG, + SYSCH_RELIABLE, + SYSCH_UNRELIABLE, + SYSCH_MAX + }; + bool active; bool server; diff --git a/modules/enet/packet.c b/modules/enet/packet.c deleted file mode 100644 index 5fa78b28ae..0000000000 --- a/modules/enet/packet.c +++ /dev/null @@ -1,165 +0,0 @@ -/** - @file packet.c - @brief ENet packet management functions -*/ -#include <string.h> -#define ENET_BUILDING_LIB 1 -#include "enet/enet.h" - -/** @defgroup Packet ENet packet functions - @{ -*/ - -/** Creates a packet that may be sent to a peer. - @param data initial contents of the packet's data; the packet's data will remain uninitialized if data is NULL. - @param dataLength size of the data allocated for this packet - @param flags flags for this packet as described for the ENetPacket structure. - @returns the packet on success, NULL on failure -*/ -ENetPacket * -enet_packet_create (const void * data, size_t dataLength, enet_uint32 flags) -{ - ENetPacket * packet = (ENetPacket *) enet_malloc (sizeof (ENetPacket)); - if (packet == NULL) - return NULL; - - if (flags & ENET_PACKET_FLAG_NO_ALLOCATE) - packet -> data = (enet_uint8 *) data; - else - if (dataLength <= 0) - packet -> data = NULL; - else - { - packet -> data = (enet_uint8 *) enet_malloc (dataLength); - if (packet -> data == NULL) - { - enet_free (packet); - return NULL; - } - - if (data != NULL) - memcpy (packet -> data, data, dataLength); - } - - packet -> referenceCount = 0; - packet -> flags = flags; - packet -> dataLength = dataLength; - packet -> freeCallback = NULL; - packet -> userData = NULL; - - return packet; -} - -/** Destroys the packet and deallocates its data. - @param packet packet to be destroyed -*/ -void -enet_packet_destroy (ENetPacket * packet) -{ - if (packet == NULL) - return; - - if (packet -> freeCallback != NULL) - (* packet -> freeCallback) (packet); - if (! (packet -> flags & ENET_PACKET_FLAG_NO_ALLOCATE) && - packet -> data != NULL) - enet_free (packet -> data); - enet_free (packet); -} - -/** Attempts to resize the data in the packet to length specified in the - dataLength parameter - @param packet packet to resize - @param dataLength new size for the packet data - @returns 0 on success, < 0 on failure -*/ -int -enet_packet_resize (ENetPacket * packet, size_t dataLength) -{ - enet_uint8 * newData; - - if (dataLength <= packet -> dataLength || (packet -> flags & ENET_PACKET_FLAG_NO_ALLOCATE)) - { - packet -> dataLength = dataLength; - - return 0; - } - - newData = (enet_uint8 *) enet_malloc (dataLength); - if (newData == NULL) - return -1; - - memcpy (newData, packet -> data, packet -> dataLength); - enet_free (packet -> data); - - packet -> data = newData; - packet -> dataLength = dataLength; - - return 0; -} - -static int initializedCRC32 = 0; -static enet_uint32 crcTable [256]; - -static enet_uint32 -reflect_crc (int val, int bits) -{ - int result = 0, bit; - - for (bit = 0; bit < bits; bit ++) - { - if(val & 1) result |= 1 << (bits - 1 - bit); - val >>= 1; - } - - return result; -} - -static void -initialize_crc32 (void) -{ - int byte; - - for (byte = 0; byte < 256; ++ byte) - { - enet_uint32 crc = reflect_crc (byte, 8) << 24; - int offset; - - for(offset = 0; offset < 8; ++ offset) - { - if (crc & 0x80000000) - crc = (crc << 1) ^ 0x04c11db7; - else - crc <<= 1; - } - - crcTable [byte] = reflect_crc (crc, 32); - } - - initializedCRC32 = 1; -} - -enet_uint32 -enet_crc32 (const ENetBuffer * buffers, size_t bufferCount) -{ - enet_uint32 crc = 0xFFFFFFFF; - - if (! initializedCRC32) initialize_crc32 (); - - while (bufferCount -- > 0) - { - const enet_uint8 * data = (const enet_uint8 *) buffers -> data, - * dataEnd = & data [buffers -> dataLength]; - - while (data < dataEnd) - { - crc = (crc >> 8) ^ crcTable [(crc & 0xFF) ^ *data++]; - } - - ++ buffers; - } - - return ENET_HOST_TO_NET_32 (~ crc); -} - -/** @} */ diff --git a/modules/enet/peer.c b/modules/enet/peer.c deleted file mode 100644 index e2d0872bd3..0000000000 --- a/modules/enet/peer.c +++ /dev/null @@ -1,1004 +0,0 @@ -/** - @file peer.c - @brief ENet peer management functions -*/ -#include <string.h> -#define ENET_BUILDING_LIB 1 -#include "enet/enet.h" - -/** @defgroup peer ENet peer functions - @{ -*/ - -/** Configures throttle parameter for a peer. - - Unreliable packets are dropped by ENet in response to the varying conditions - of the Internet connection to the peer. The throttle represents a probability - that an unreliable packet should not be dropped and thus sent by ENet to the peer. - The lowest mean round trip time from the sending of a reliable packet to the - receipt of its acknowledgement is measured over an amount of time specified by - the interval parameter in milliseconds. If a measured round trip time happens to - be significantly less than the mean round trip time measured over the interval, - then the throttle probability is increased to allow more traffic by an amount - specified in the acceleration parameter, which is a ratio to the ENET_PEER_PACKET_THROTTLE_SCALE - constant. If a measured round trip time happens to be significantly greater than - the mean round trip time measured over the interval, then the throttle probability - is decreased to limit traffic by an amount specified in the deceleration parameter, which - is a ratio to the ENET_PEER_PACKET_THROTTLE_SCALE constant. When the throttle has - a value of ENET_PEER_PACKET_THROTTLE_SCALE, no unreliable packets are dropped by - ENet, and so 100% of all unreliable packets will be sent. When the throttle has a - value of 0, all unreliable packets are dropped by ENet, and so 0% of all unreliable - packets will be sent. Intermediate values for the throttle represent intermediate - probabilities between 0% and 100% of unreliable packets being sent. The bandwidth - limits of the local and foreign hosts are taken into account to determine a - sensible limit for the throttle probability above which it should not raise even in - the best of conditions. - - @param peer peer to configure - @param interval interval, in milliseconds, over which to measure lowest mean RTT; the default value is ENET_PEER_PACKET_THROTTLE_INTERVAL. - @param acceleration rate at which to increase the throttle probability as mean RTT declines - @param deceleration rate at which to decrease the throttle probability as mean RTT increases -*/ -void -enet_peer_throttle_configure (ENetPeer * peer, enet_uint32 interval, enet_uint32 acceleration, enet_uint32 deceleration) -{ - ENetProtocol command; - - peer -> packetThrottleInterval = interval; - peer -> packetThrottleAcceleration = acceleration; - peer -> packetThrottleDeceleration = deceleration; - - command.header.command = ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; - command.header.channelID = 0xFF; - - command.throttleConfigure.packetThrottleInterval = ENET_HOST_TO_NET_32 (interval); - command.throttleConfigure.packetThrottleAcceleration = ENET_HOST_TO_NET_32 (acceleration); - command.throttleConfigure.packetThrottleDeceleration = ENET_HOST_TO_NET_32 (deceleration); - - enet_peer_queue_outgoing_command (peer, & command, NULL, 0, 0); -} - -int -enet_peer_throttle (ENetPeer * peer, enet_uint32 rtt) -{ - if (peer -> lastRoundTripTime <= peer -> lastRoundTripTimeVariance) - { - peer -> packetThrottle = peer -> packetThrottleLimit; - } - else - if (rtt < peer -> lastRoundTripTime) - { - peer -> packetThrottle += peer -> packetThrottleAcceleration; - - if (peer -> packetThrottle > peer -> packetThrottleLimit) - peer -> packetThrottle = peer -> packetThrottleLimit; - - return 1; - } - else - if (rtt > peer -> lastRoundTripTime + 2 * peer -> lastRoundTripTimeVariance) - { - if (peer -> packetThrottle > peer -> packetThrottleDeceleration) - peer -> packetThrottle -= peer -> packetThrottleDeceleration; - else - peer -> packetThrottle = 0; - - return -1; - } - - return 0; -} - -/** Queues a packet to be sent. - @param peer destination for the packet - @param channelID channel on which to send - @param packet packet to send - @retval 0 on success - @retval < 0 on failure -*/ -int -enet_peer_send (ENetPeer * peer, enet_uint8 channelID, ENetPacket * packet) -{ - ENetChannel * channel = & peer -> channels [channelID]; - ENetProtocol command; - size_t fragmentLength; - - if (peer -> state != ENET_PEER_STATE_CONNECTED || - channelID >= peer -> channelCount || - packet -> dataLength > peer -> host -> maximumPacketSize) - return -1; - - fragmentLength = peer -> mtu - sizeof (ENetProtocolHeader) - sizeof (ENetProtocolSendFragment); - if (peer -> host -> checksum != NULL) - fragmentLength -= sizeof(enet_uint32); - - if (packet -> dataLength > fragmentLength) - { - enet_uint32 fragmentCount = (packet -> dataLength + fragmentLength - 1) / fragmentLength, - fragmentNumber, - fragmentOffset; - enet_uint8 commandNumber; - enet_uint16 startSequenceNumber; - ENetList fragments; - ENetOutgoingCommand * fragment; - - if (fragmentCount > ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT) - return -1; - - if ((packet -> flags & (ENET_PACKET_FLAG_RELIABLE | ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT)) == ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT && - channel -> outgoingUnreliableSequenceNumber < 0xFFFF) - { - commandNumber = ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT; - startSequenceNumber = ENET_HOST_TO_NET_16 (channel -> outgoingUnreliableSequenceNumber + 1); - } - else - { - commandNumber = ENET_PROTOCOL_COMMAND_SEND_FRAGMENT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; - startSequenceNumber = ENET_HOST_TO_NET_16 (channel -> outgoingReliableSequenceNumber + 1); - } - - enet_list_clear (& fragments); - - for (fragmentNumber = 0, - fragmentOffset = 0; - fragmentOffset < packet -> dataLength; - ++ fragmentNumber, - fragmentOffset += fragmentLength) - { - if (packet -> dataLength - fragmentOffset < fragmentLength) - fragmentLength = packet -> dataLength - fragmentOffset; - - fragment = (ENetOutgoingCommand *) enet_malloc (sizeof (ENetOutgoingCommand)); - if (fragment == NULL) - { - while (! enet_list_empty (& fragments)) - { - fragment = (ENetOutgoingCommand *) enet_list_remove (enet_list_begin (& fragments)); - - enet_free (fragment); - } - - return -1; - } - - fragment -> fragmentOffset = fragmentOffset; - fragment -> fragmentLength = fragmentLength; - fragment -> packet = packet; - fragment -> command.header.command = commandNumber; - fragment -> command.header.channelID = channelID; - fragment -> command.sendFragment.startSequenceNumber = startSequenceNumber; - fragment -> command.sendFragment.dataLength = ENET_HOST_TO_NET_16 (fragmentLength); - fragment -> command.sendFragment.fragmentCount = ENET_HOST_TO_NET_32 (fragmentCount); - fragment -> command.sendFragment.fragmentNumber = ENET_HOST_TO_NET_32 (fragmentNumber); - fragment -> command.sendFragment.totalLength = ENET_HOST_TO_NET_32 (packet -> dataLength); - fragment -> command.sendFragment.fragmentOffset = ENET_NET_TO_HOST_32 (fragmentOffset); - - enet_list_insert (enet_list_end (& fragments), fragment); - } - - packet -> referenceCount += fragmentNumber; - - while (! enet_list_empty (& fragments)) - { - fragment = (ENetOutgoingCommand *) enet_list_remove (enet_list_begin (& fragments)); - - enet_peer_setup_outgoing_command (peer, fragment); - } - - return 0; - } - - command.header.channelID = channelID; - - if ((packet -> flags & (ENET_PACKET_FLAG_RELIABLE | ENET_PACKET_FLAG_UNSEQUENCED)) == ENET_PACKET_FLAG_UNSEQUENCED) - { - command.header.command = ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED | ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED; - command.sendUnsequenced.dataLength = ENET_HOST_TO_NET_16 (packet -> dataLength); - } - else - if (packet -> flags & ENET_PACKET_FLAG_RELIABLE || channel -> outgoingUnreliableSequenceNumber >= 0xFFFF) - { - command.header.command = ENET_PROTOCOL_COMMAND_SEND_RELIABLE | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; - command.sendReliable.dataLength = ENET_HOST_TO_NET_16 (packet -> dataLength); - } - else - { - command.header.command = ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE; - command.sendUnreliable.dataLength = ENET_HOST_TO_NET_16 (packet -> dataLength); - } - - if (enet_peer_queue_outgoing_command (peer, & command, packet, 0, packet -> dataLength) == NULL) - return -1; - - return 0; -} - -/** Attempts to dequeue any incoming queued packet. - @param peer peer to dequeue packets from - @param channelID holds the channel ID of the channel the packet was received on success - @returns a pointer to the packet, or NULL if there are no available incoming queued packets -*/ -ENetPacket * -enet_peer_receive (ENetPeer * peer, enet_uint8 * channelID) -{ - ENetIncomingCommand * incomingCommand; - ENetPacket * packet; - - if (enet_list_empty (& peer -> dispatchedCommands)) - return NULL; - - incomingCommand = (ENetIncomingCommand *) enet_list_remove (enet_list_begin (& peer -> dispatchedCommands)); - - if (channelID != NULL) - * channelID = incomingCommand -> command.header.channelID; - - packet = incomingCommand -> packet; - - -- packet -> referenceCount; - - if (incomingCommand -> fragments != NULL) - enet_free (incomingCommand -> fragments); - - enet_free (incomingCommand); - - peer -> totalWaitingData -= packet -> dataLength; - - return packet; -} - -static void -enet_peer_reset_outgoing_commands (ENetList * queue) -{ - ENetOutgoingCommand * outgoingCommand; - - while (! enet_list_empty (queue)) - { - outgoingCommand = (ENetOutgoingCommand *) enet_list_remove (enet_list_begin (queue)); - - if (outgoingCommand -> packet != NULL) - { - -- outgoingCommand -> packet -> referenceCount; - - if (outgoingCommand -> packet -> referenceCount == 0) - enet_packet_destroy (outgoingCommand -> packet); - } - - enet_free (outgoingCommand); - } -} - -static void -enet_peer_remove_incoming_commands (ENetList * queue, ENetListIterator startCommand, ENetListIterator endCommand) -{ - ENetListIterator currentCommand; - - for (currentCommand = startCommand; currentCommand != endCommand; ) - { - ENetIncomingCommand * incomingCommand = (ENetIncomingCommand *) currentCommand; - - currentCommand = enet_list_next (currentCommand); - - enet_list_remove (& incomingCommand -> incomingCommandList); - - if (incomingCommand -> packet != NULL) - { - -- incomingCommand -> packet -> referenceCount; - - if (incomingCommand -> packet -> referenceCount == 0) - enet_packet_destroy (incomingCommand -> packet); - } - - if (incomingCommand -> fragments != NULL) - enet_free (incomingCommand -> fragments); - - enet_free (incomingCommand); - } -} - -static void -enet_peer_reset_incoming_commands (ENetList * queue) -{ - enet_peer_remove_incoming_commands(queue, enet_list_begin (queue), enet_list_end (queue)); -} - -void -enet_peer_reset_queues (ENetPeer * peer) -{ - ENetChannel * channel; - - if (peer -> needsDispatch) - { - enet_list_remove (& peer -> dispatchList); - - peer -> needsDispatch = 0; - } - - while (! enet_list_empty (& peer -> acknowledgements)) - enet_free (enet_list_remove (enet_list_begin (& peer -> acknowledgements))); - - enet_peer_reset_outgoing_commands (& peer -> sentReliableCommands); - enet_peer_reset_outgoing_commands (& peer -> sentUnreliableCommands); - enet_peer_reset_outgoing_commands (& peer -> outgoingReliableCommands); - enet_peer_reset_outgoing_commands (& peer -> outgoingUnreliableCommands); - enet_peer_reset_incoming_commands (& peer -> dispatchedCommands); - - if (peer -> channels != NULL && peer -> channelCount > 0) - { - for (channel = peer -> channels; - channel < & peer -> channels [peer -> channelCount]; - ++ channel) - { - enet_peer_reset_incoming_commands (& channel -> incomingReliableCommands); - enet_peer_reset_incoming_commands (& channel -> incomingUnreliableCommands); - } - - enet_free (peer -> channels); - } - - peer -> channels = NULL; - peer -> channelCount = 0; -} - -void -enet_peer_on_connect (ENetPeer * peer) -{ - if (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) - { - if (peer -> incomingBandwidth != 0) - ++ peer -> host -> bandwidthLimitedPeers; - - ++ peer -> host -> connectedPeers; - } -} - -void -enet_peer_on_disconnect (ENetPeer * peer) -{ - if (peer -> state == ENET_PEER_STATE_CONNECTED || peer -> state == ENET_PEER_STATE_DISCONNECT_LATER) - { - if (peer -> incomingBandwidth != 0) - -- peer -> host -> bandwidthLimitedPeers; - - -- peer -> host -> connectedPeers; - } -} - -/** Forcefully disconnects a peer. - @param peer peer to forcefully disconnect - @remarks The foreign host represented by the peer is not notified of the disconnection and will timeout - on its connection to the local host. -*/ -void -enet_peer_reset (ENetPeer * peer) -{ - enet_peer_on_disconnect (peer); - - peer -> outgoingPeerID = ENET_PROTOCOL_MAXIMUM_PEER_ID; - peer -> connectID = 0; - - peer -> state = ENET_PEER_STATE_DISCONNECTED; - - peer -> incomingBandwidth = 0; - peer -> outgoingBandwidth = 0; - peer -> incomingBandwidthThrottleEpoch = 0; - peer -> outgoingBandwidthThrottleEpoch = 0; - peer -> incomingDataTotal = 0; - peer -> outgoingDataTotal = 0; - peer -> lastSendTime = 0; - peer -> lastReceiveTime = 0; - peer -> nextTimeout = 0; - peer -> earliestTimeout = 0; - peer -> packetLossEpoch = 0; - peer -> packetsSent = 0; - peer -> packetsLost = 0; - peer -> packetLoss = 0; - peer -> packetLossVariance = 0; - peer -> packetThrottle = ENET_PEER_DEFAULT_PACKET_THROTTLE; - peer -> packetThrottleLimit = ENET_PEER_PACKET_THROTTLE_SCALE; - peer -> packetThrottleCounter = 0; - peer -> packetThrottleEpoch = 0; - peer -> packetThrottleAcceleration = ENET_PEER_PACKET_THROTTLE_ACCELERATION; - peer -> packetThrottleDeceleration = ENET_PEER_PACKET_THROTTLE_DECELERATION; - peer -> packetThrottleInterval = ENET_PEER_PACKET_THROTTLE_INTERVAL; - peer -> pingInterval = ENET_PEER_PING_INTERVAL; - peer -> timeoutLimit = ENET_PEER_TIMEOUT_LIMIT; - peer -> timeoutMinimum = ENET_PEER_TIMEOUT_MINIMUM; - peer -> timeoutMaximum = ENET_PEER_TIMEOUT_MAXIMUM; - peer -> lastRoundTripTime = ENET_PEER_DEFAULT_ROUND_TRIP_TIME; - peer -> lowestRoundTripTime = ENET_PEER_DEFAULT_ROUND_TRIP_TIME; - peer -> lastRoundTripTimeVariance = 0; - peer -> highestRoundTripTimeVariance = 0; - peer -> roundTripTime = ENET_PEER_DEFAULT_ROUND_TRIP_TIME; - peer -> roundTripTimeVariance = 0; - peer -> mtu = peer -> host -> mtu; - peer -> reliableDataInTransit = 0; - peer -> outgoingReliableSequenceNumber = 0; - peer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; - peer -> incomingUnsequencedGroup = 0; - peer -> outgoingUnsequencedGroup = 0; - peer -> eventData = 0; - peer -> totalWaitingData = 0; - - memset (peer -> unsequencedWindow, 0, sizeof (peer -> unsequencedWindow)); - - enet_peer_reset_queues (peer); -} - -/** Sends a ping request to a peer. - @param peer destination for the ping request - @remarks ping requests factor into the mean round trip time as designated by the - roundTripTime field in the ENetPeer structure. ENet automatically pings all connected - peers at regular intervals, however, this function may be called to ensure more - frequent ping requests. -*/ -void -enet_peer_ping (ENetPeer * peer) -{ - ENetProtocol command; - - if (peer -> state != ENET_PEER_STATE_CONNECTED) - return; - - command.header.command = ENET_PROTOCOL_COMMAND_PING | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; - command.header.channelID = 0xFF; - - enet_peer_queue_outgoing_command (peer, & command, NULL, 0, 0); -} - -/** Sets the interval at which pings will be sent to a peer. - - Pings are used both to monitor the liveness of the connection and also to dynamically - adjust the throttle during periods of low traffic so that the throttle has reasonable - responsiveness during traffic spikes. - - @param peer the peer to adjust - @param pingInterval the interval at which to send pings; defaults to ENET_PEER_PING_INTERVAL if 0 -*/ -void -enet_peer_ping_interval (ENetPeer * peer, enet_uint32 pingInterval) -{ - peer -> pingInterval = pingInterval ? pingInterval : ENET_PEER_PING_INTERVAL; -} - -/** Sets the timeout parameters for a peer. - - The timeout parameter control how and when a peer will timeout from a failure to acknowledge - reliable traffic. Timeout values use an exponential backoff mechanism, where if a reliable - packet is not acknowledge within some multiple of the average RTT plus a variance tolerance, - the timeout will be doubled until it reaches a set limit. If the timeout is thus at this - limit and reliable packets have been sent but not acknowledged within a certain minimum time - period, the peer will be disconnected. Alternatively, if reliable packets have been sent - but not acknowledged for a certain maximum time period, the peer will be disconnected regardless - of the current timeout limit value. - - @param peer the peer to adjust - @param timeoutLimit the timeout limit; defaults to ENET_PEER_TIMEOUT_LIMIT if 0 - @param timeoutMinimum the timeout minimum; defaults to ENET_PEER_TIMEOUT_MINIMUM if 0 - @param timeoutMaximum the timeout maximum; defaults to ENET_PEER_TIMEOUT_MAXIMUM if 0 -*/ - -void -enet_peer_timeout (ENetPeer * peer, enet_uint32 timeoutLimit, enet_uint32 timeoutMinimum, enet_uint32 timeoutMaximum) -{ - peer -> timeoutLimit = timeoutLimit ? timeoutLimit : ENET_PEER_TIMEOUT_LIMIT; - peer -> timeoutMinimum = timeoutMinimum ? timeoutMinimum : ENET_PEER_TIMEOUT_MINIMUM; - peer -> timeoutMaximum = timeoutMaximum ? timeoutMaximum : ENET_PEER_TIMEOUT_MAXIMUM; -} - -/** Force an immediate disconnection from a peer. - @param peer peer to disconnect - @param data data describing the disconnection - @remarks No ENET_EVENT_DISCONNECT event will be generated. The foreign peer is not - guaranteed to receive the disconnect notification, and is reset immediately upon - return from this function. -*/ -void -enet_peer_disconnect_now (ENetPeer * peer, enet_uint32 data) -{ - ENetProtocol command; - - if (peer -> state == ENET_PEER_STATE_DISCONNECTED) - return; - - if (peer -> state != ENET_PEER_STATE_ZOMBIE && - peer -> state != ENET_PEER_STATE_DISCONNECTING) - { - enet_peer_reset_queues (peer); - - command.header.command = ENET_PROTOCOL_COMMAND_DISCONNECT | ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED; - command.header.channelID = 0xFF; - command.disconnect.data = ENET_HOST_TO_NET_32 (data); - - enet_peer_queue_outgoing_command (peer, & command, NULL, 0, 0); - - enet_host_flush (peer -> host); - } - - enet_peer_reset (peer); -} - -/** Request a disconnection from a peer. - @param peer peer to request a disconnection - @param data data describing the disconnection - @remarks An ENET_EVENT_DISCONNECT event will be generated by enet_host_service() - once the disconnection is complete. -*/ -void -enet_peer_disconnect (ENetPeer * peer, enet_uint32 data) -{ - ENetProtocol command; - - if (peer -> state == ENET_PEER_STATE_DISCONNECTING || - peer -> state == ENET_PEER_STATE_DISCONNECTED || - peer -> state == ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT || - peer -> state == ENET_PEER_STATE_ZOMBIE) - return; - - enet_peer_reset_queues (peer); - - command.header.command = ENET_PROTOCOL_COMMAND_DISCONNECT; - command.header.channelID = 0xFF; - command.disconnect.data = ENET_HOST_TO_NET_32 (data); - - if (peer -> state == ENET_PEER_STATE_CONNECTED || peer -> state == ENET_PEER_STATE_DISCONNECT_LATER) - command.header.command |= ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; - else - command.header.command |= ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED; - - enet_peer_queue_outgoing_command (peer, & command, NULL, 0, 0); - - if (peer -> state == ENET_PEER_STATE_CONNECTED || peer -> state == ENET_PEER_STATE_DISCONNECT_LATER) - { - enet_peer_on_disconnect (peer); - - peer -> state = ENET_PEER_STATE_DISCONNECTING; - } - else - { - enet_host_flush (peer -> host); - enet_peer_reset (peer); - } -} - -/** Request a disconnection from a peer, but only after all queued outgoing packets are sent. - @param peer peer to request a disconnection - @param data data describing the disconnection - @remarks An ENET_EVENT_DISCONNECT event will be generated by enet_host_service() - once the disconnection is complete. -*/ -void -enet_peer_disconnect_later (ENetPeer * peer, enet_uint32 data) -{ - if ((peer -> state == ENET_PEER_STATE_CONNECTED || peer -> state == ENET_PEER_STATE_DISCONNECT_LATER) && - ! (enet_list_empty (& peer -> outgoingReliableCommands) && - enet_list_empty (& peer -> outgoingUnreliableCommands) && - enet_list_empty (& peer -> sentReliableCommands))) - { - peer -> state = ENET_PEER_STATE_DISCONNECT_LATER; - peer -> eventData = data; - } - else - enet_peer_disconnect (peer, data); -} - -ENetAcknowledgement * -enet_peer_queue_acknowledgement (ENetPeer * peer, const ENetProtocol * command, enet_uint16 sentTime) -{ - ENetAcknowledgement * acknowledgement; - - if (command -> header.channelID < peer -> channelCount) - { - ENetChannel * channel = & peer -> channels [command -> header.channelID]; - enet_uint16 reliableWindow = command -> header.reliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE, - currentWindow = channel -> incomingReliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; - - if (command -> header.reliableSequenceNumber < channel -> incomingReliableSequenceNumber) - reliableWindow += ENET_PEER_RELIABLE_WINDOWS; - - if (reliableWindow >= currentWindow + ENET_PEER_FREE_RELIABLE_WINDOWS - 1 && reliableWindow <= currentWindow + ENET_PEER_FREE_RELIABLE_WINDOWS) - return NULL; - } - - acknowledgement = (ENetAcknowledgement *) enet_malloc (sizeof (ENetAcknowledgement)); - if (acknowledgement == NULL) - return NULL; - - peer -> outgoingDataTotal += sizeof (ENetProtocolAcknowledge); - - acknowledgement -> sentTime = sentTime; - acknowledgement -> command = * command; - - enet_list_insert (enet_list_end (& peer -> acknowledgements), acknowledgement); - - return acknowledgement; -} - -void -enet_peer_setup_outgoing_command (ENetPeer * peer, ENetOutgoingCommand * outgoingCommand) -{ - ENetChannel * channel = & peer -> channels [outgoingCommand -> command.header.channelID]; - - peer -> outgoingDataTotal += enet_protocol_command_size (outgoingCommand -> command.header.command) + outgoingCommand -> fragmentLength; - - if (outgoingCommand -> command.header.channelID == 0xFF) - { - ++ peer -> outgoingReliableSequenceNumber; - - outgoingCommand -> reliableSequenceNumber = peer -> outgoingReliableSequenceNumber; - outgoingCommand -> unreliableSequenceNumber = 0; - } - else - if (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE) - { - ++ channel -> outgoingReliableSequenceNumber; - channel -> outgoingUnreliableSequenceNumber = 0; - - outgoingCommand -> reliableSequenceNumber = channel -> outgoingReliableSequenceNumber; - outgoingCommand -> unreliableSequenceNumber = 0; - } - else - if (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED) - { - ++ peer -> outgoingUnsequencedGroup; - - outgoingCommand -> reliableSequenceNumber = 0; - outgoingCommand -> unreliableSequenceNumber = 0; - } - else - { - if (outgoingCommand -> fragmentOffset == 0) - ++ channel -> outgoingUnreliableSequenceNumber; - - outgoingCommand -> reliableSequenceNumber = channel -> outgoingReliableSequenceNumber; - outgoingCommand -> unreliableSequenceNumber = channel -> outgoingUnreliableSequenceNumber; - } - - outgoingCommand -> sendAttempts = 0; - outgoingCommand -> sentTime = 0; - outgoingCommand -> roundTripTimeout = 0; - outgoingCommand -> roundTripTimeoutLimit = 0; - outgoingCommand -> command.header.reliableSequenceNumber = ENET_HOST_TO_NET_16 (outgoingCommand -> reliableSequenceNumber); - - switch (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_MASK) - { - case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE: - outgoingCommand -> command.sendUnreliable.unreliableSequenceNumber = ENET_HOST_TO_NET_16 (outgoingCommand -> unreliableSequenceNumber); - break; - - case ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED: - outgoingCommand -> command.sendUnsequenced.unsequencedGroup = ENET_HOST_TO_NET_16 (peer -> outgoingUnsequencedGroup); - break; - - default: - break; - } - - if (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE) - enet_list_insert (enet_list_end (& peer -> outgoingReliableCommands), outgoingCommand); - else - enet_list_insert (enet_list_end (& peer -> outgoingUnreliableCommands), outgoingCommand); -} - -ENetOutgoingCommand * -enet_peer_queue_outgoing_command (ENetPeer * peer, const ENetProtocol * command, ENetPacket * packet, enet_uint32 offset, enet_uint16 length) -{ - ENetOutgoingCommand * outgoingCommand = (ENetOutgoingCommand *) enet_malloc (sizeof (ENetOutgoingCommand)); - if (outgoingCommand == NULL) - return NULL; - - outgoingCommand -> command = * command; - outgoingCommand -> fragmentOffset = offset; - outgoingCommand -> fragmentLength = length; - outgoingCommand -> packet = packet; - if (packet != NULL) - ++ packet -> referenceCount; - - enet_peer_setup_outgoing_command (peer, outgoingCommand); - - return outgoingCommand; -} - -void -enet_peer_dispatch_incoming_unreliable_commands (ENetPeer * peer, ENetChannel * channel) -{ - ENetListIterator droppedCommand, startCommand, currentCommand; - - for (droppedCommand = startCommand = currentCommand = enet_list_begin (& channel -> incomingUnreliableCommands); - currentCommand != enet_list_end (& channel -> incomingUnreliableCommands); - currentCommand = enet_list_next (currentCommand)) - { - ENetIncomingCommand * incomingCommand = (ENetIncomingCommand *) currentCommand; - - if ((incomingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_MASK) == ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED) - continue; - - if (incomingCommand -> reliableSequenceNumber == channel -> incomingReliableSequenceNumber) - { - if (incomingCommand -> fragmentsRemaining <= 0) - { - channel -> incomingUnreliableSequenceNumber = incomingCommand -> unreliableSequenceNumber; - continue; - } - - if (startCommand != currentCommand) - { - enet_list_move (enet_list_end (& peer -> dispatchedCommands), startCommand, enet_list_previous (currentCommand)); - - if (! peer -> needsDispatch) - { - enet_list_insert (enet_list_end (& peer -> host -> dispatchQueue), & peer -> dispatchList); - - peer -> needsDispatch = 1; - } - - droppedCommand = currentCommand; - } - else - if (droppedCommand != currentCommand) - droppedCommand = enet_list_previous (currentCommand); - } - else - { - enet_uint16 reliableWindow = incomingCommand -> reliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE, - currentWindow = channel -> incomingReliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; - if (incomingCommand -> reliableSequenceNumber < channel -> incomingReliableSequenceNumber) - reliableWindow += ENET_PEER_RELIABLE_WINDOWS; - if (reliableWindow >= currentWindow && reliableWindow < currentWindow + ENET_PEER_FREE_RELIABLE_WINDOWS - 1) - break; - - droppedCommand = enet_list_next (currentCommand); - - if (startCommand != currentCommand) - { - enet_list_move (enet_list_end (& peer -> dispatchedCommands), startCommand, enet_list_previous (currentCommand)); - - if (! peer -> needsDispatch) - { - enet_list_insert (enet_list_end (& peer -> host -> dispatchQueue), & peer -> dispatchList); - - peer -> needsDispatch = 1; - } - } - } - - startCommand = enet_list_next (currentCommand); - } - - if (startCommand != currentCommand) - { - enet_list_move (enet_list_end (& peer -> dispatchedCommands), startCommand, enet_list_previous (currentCommand)); - - if (! peer -> needsDispatch) - { - enet_list_insert (enet_list_end (& peer -> host -> dispatchQueue), & peer -> dispatchList); - - peer -> needsDispatch = 1; - } - - droppedCommand = currentCommand; - } - - enet_peer_remove_incoming_commands (& channel -> incomingUnreliableCommands, enet_list_begin (& channel -> incomingUnreliableCommands), droppedCommand); -} - -void -enet_peer_dispatch_incoming_reliable_commands (ENetPeer * peer, ENetChannel * channel) -{ - ENetListIterator currentCommand; - - for (currentCommand = enet_list_begin (& channel -> incomingReliableCommands); - currentCommand != enet_list_end (& channel -> incomingReliableCommands); - currentCommand = enet_list_next (currentCommand)) - { - ENetIncomingCommand * incomingCommand = (ENetIncomingCommand *) currentCommand; - - if (incomingCommand -> fragmentsRemaining > 0 || - incomingCommand -> reliableSequenceNumber != (enet_uint16) (channel -> incomingReliableSequenceNumber + 1)) - break; - - channel -> incomingReliableSequenceNumber = incomingCommand -> reliableSequenceNumber; - - if (incomingCommand -> fragmentCount > 0) - channel -> incomingReliableSequenceNumber += incomingCommand -> fragmentCount - 1; - } - - if (currentCommand == enet_list_begin (& channel -> incomingReliableCommands)) - return; - - channel -> incomingUnreliableSequenceNumber = 0; - - enet_list_move (enet_list_end (& peer -> dispatchedCommands), enet_list_begin (& channel -> incomingReliableCommands), enet_list_previous (currentCommand)); - - if (! peer -> needsDispatch) - { - enet_list_insert (enet_list_end (& peer -> host -> dispatchQueue), & peer -> dispatchList); - - peer -> needsDispatch = 1; - } - - if (! enet_list_empty (& channel -> incomingUnreliableCommands)) - enet_peer_dispatch_incoming_unreliable_commands (peer, channel); -} - -ENetIncomingCommand * -enet_peer_queue_incoming_command (ENetPeer * peer, const ENetProtocol * command, const void * data, size_t dataLength, enet_uint32 flags, enet_uint32 fragmentCount) -{ - static ENetIncomingCommand dummyCommand; - - ENetChannel * channel = & peer -> channels [command -> header.channelID]; - enet_uint32 unreliableSequenceNumber = 0, reliableSequenceNumber = 0; - enet_uint16 reliableWindow, currentWindow; - ENetIncomingCommand * incomingCommand; - ENetListIterator currentCommand; - ENetPacket * packet = NULL; - - if (peer -> state == ENET_PEER_STATE_DISCONNECT_LATER) - goto discardCommand; - - if ((command -> header.command & ENET_PROTOCOL_COMMAND_MASK) != ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED) - { - reliableSequenceNumber = command -> header.reliableSequenceNumber; - reliableWindow = reliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; - currentWindow = channel -> incomingReliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; - - if (reliableSequenceNumber < channel -> incomingReliableSequenceNumber) - reliableWindow += ENET_PEER_RELIABLE_WINDOWS; - - if (reliableWindow < currentWindow || reliableWindow >= currentWindow + ENET_PEER_FREE_RELIABLE_WINDOWS - 1) - goto discardCommand; - } - - switch (command -> header.command & ENET_PROTOCOL_COMMAND_MASK) - { - case ENET_PROTOCOL_COMMAND_SEND_FRAGMENT: - case ENET_PROTOCOL_COMMAND_SEND_RELIABLE: - if (reliableSequenceNumber == channel -> incomingReliableSequenceNumber) - goto discardCommand; - - for (currentCommand = enet_list_previous (enet_list_end (& channel -> incomingReliableCommands)); - currentCommand != enet_list_end (& channel -> incomingReliableCommands); - currentCommand = enet_list_previous (currentCommand)) - { - incomingCommand = (ENetIncomingCommand *) currentCommand; - - if (reliableSequenceNumber >= channel -> incomingReliableSequenceNumber) - { - if (incomingCommand -> reliableSequenceNumber < channel -> incomingReliableSequenceNumber) - continue; - } - else - if (incomingCommand -> reliableSequenceNumber >= channel -> incomingReliableSequenceNumber) - break; - - if (incomingCommand -> reliableSequenceNumber <= reliableSequenceNumber) - { - if (incomingCommand -> reliableSequenceNumber < reliableSequenceNumber) - break; - - goto discardCommand; - } - } - break; - - case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE: - case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT: - unreliableSequenceNumber = ENET_NET_TO_HOST_16 (command -> sendUnreliable.unreliableSequenceNumber); - - if (reliableSequenceNumber == channel -> incomingReliableSequenceNumber && - unreliableSequenceNumber <= channel -> incomingUnreliableSequenceNumber) - goto discardCommand; - - for (currentCommand = enet_list_previous (enet_list_end (& channel -> incomingUnreliableCommands)); - currentCommand != enet_list_end (& channel -> incomingUnreliableCommands); - currentCommand = enet_list_previous (currentCommand)) - { - incomingCommand = (ENetIncomingCommand *) currentCommand; - - if ((command -> header.command & ENET_PROTOCOL_COMMAND_MASK) == ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED) - continue; - - if (reliableSequenceNumber >= channel -> incomingReliableSequenceNumber) - { - if (incomingCommand -> reliableSequenceNumber < channel -> incomingReliableSequenceNumber) - continue; - } - else - if (incomingCommand -> reliableSequenceNumber >= channel -> incomingReliableSequenceNumber) - break; - - if (incomingCommand -> reliableSequenceNumber < reliableSequenceNumber) - break; - - if (incomingCommand -> reliableSequenceNumber > reliableSequenceNumber) - continue; - - if (incomingCommand -> unreliableSequenceNumber <= unreliableSequenceNumber) - { - if (incomingCommand -> unreliableSequenceNumber < unreliableSequenceNumber) - break; - - goto discardCommand; - } - } - break; - - case ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED: - currentCommand = enet_list_end (& channel -> incomingUnreliableCommands); - break; - - default: - goto discardCommand; - } - - if (peer -> totalWaitingData >= peer -> host -> maximumWaitingData) - goto notifyError; - - packet = enet_packet_create (data, dataLength, flags); - if (packet == NULL) - goto notifyError; - - incomingCommand = (ENetIncomingCommand *) enet_malloc (sizeof (ENetIncomingCommand)); - if (incomingCommand == NULL) - goto notifyError; - - incomingCommand -> reliableSequenceNumber = command -> header.reliableSequenceNumber; - incomingCommand -> unreliableSequenceNumber = unreliableSequenceNumber & 0xFFFF; - incomingCommand -> command = * command; - incomingCommand -> fragmentCount = fragmentCount; - incomingCommand -> fragmentsRemaining = fragmentCount; - incomingCommand -> packet = packet; - incomingCommand -> fragments = NULL; - - if (fragmentCount > 0) - { - if (fragmentCount <= ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT) - incomingCommand -> fragments = (enet_uint32 *) enet_malloc ((fragmentCount + 31) / 32 * sizeof (enet_uint32)); - if (incomingCommand -> fragments == NULL) - { - enet_free (incomingCommand); - - goto notifyError; - } - memset (incomingCommand -> fragments, 0, (fragmentCount + 31) / 32 * sizeof (enet_uint32)); - } - - if (packet != NULL) - { - ++ packet -> referenceCount; - - peer -> totalWaitingData += packet -> dataLength; - } - - enet_list_insert (enet_list_next (currentCommand), incomingCommand); - - switch (command -> header.command & ENET_PROTOCOL_COMMAND_MASK) - { - case ENET_PROTOCOL_COMMAND_SEND_FRAGMENT: - case ENET_PROTOCOL_COMMAND_SEND_RELIABLE: - enet_peer_dispatch_incoming_reliable_commands (peer, channel); - break; - - default: - enet_peer_dispatch_incoming_unreliable_commands (peer, channel); - break; - } - - return incomingCommand; - -discardCommand: - if (fragmentCount > 0) - goto notifyError; - - if (packet != NULL && packet -> referenceCount == 0) - enet_packet_destroy (packet); - - return & dummyCommand; - -notifyError: - if (packet != NULL && packet -> referenceCount == 0) - enet_packet_destroy (packet); - - return NULL; -} - -/** @} */ diff --git a/modules/enet/protocol.c b/modules/enet/protocol.c deleted file mode 100644 index 4a2a4ed185..0000000000 --- a/modules/enet/protocol.c +++ /dev/null @@ -1,1914 +0,0 @@ -/** - @file protocol.c - @brief ENet protocol functions -*/ -#include <stdio.h> -#include <string.h> -#define ENET_BUILDING_LIB 1 -#include "enet/utility.h" -#include "enet/time.h" -#include "enet/enet.h" - - -static size_t commandSizes [ENET_PROTOCOL_COMMAND_COUNT] = -{ - 0, - sizeof (ENetProtocolAcknowledge), - sizeof (ENetProtocolConnect), - sizeof (ENetProtocolVerifyConnect), - sizeof (ENetProtocolDisconnect), - sizeof (ENetProtocolPing), - sizeof (ENetProtocolSendReliable), - sizeof (ENetProtocolSendUnreliable), - sizeof (ENetProtocolSendFragment), - sizeof (ENetProtocolSendUnsequenced), - sizeof (ENetProtocolBandwidthLimit), - sizeof (ENetProtocolThrottleConfigure), - sizeof (ENetProtocolSendFragment) -}; - -size_t -enet_protocol_command_size (enet_uint8 commandNumber) -{ - return commandSizes [commandNumber & ENET_PROTOCOL_COMMAND_MASK]; -} - -static void -enet_protocol_change_state (ENetHost * host, ENetPeer * peer, ENetPeerState state) -{ - if (state == ENET_PEER_STATE_CONNECTED || state == ENET_PEER_STATE_DISCONNECT_LATER) - enet_peer_on_connect (peer); - else - enet_peer_on_disconnect (peer); - - peer -> state = state; -} - -static void -enet_protocol_dispatch_state (ENetHost * host, ENetPeer * peer, ENetPeerState state) -{ - enet_protocol_change_state (host, peer, state); - - if (! peer -> needsDispatch) - { - enet_list_insert (enet_list_end (& host -> dispatchQueue), & peer -> dispatchList); - - peer -> needsDispatch = 1; - } -} - -static int -enet_protocol_dispatch_incoming_commands (ENetHost * host, ENetEvent * event) -{ - while (! enet_list_empty (& host -> dispatchQueue)) - { - ENetPeer * peer = (ENetPeer *) enet_list_remove (enet_list_begin (& host -> dispatchQueue)); - - peer -> needsDispatch = 0; - - switch (peer -> state) - { - case ENET_PEER_STATE_CONNECTION_PENDING: - case ENET_PEER_STATE_CONNECTION_SUCCEEDED: - enet_protocol_change_state (host, peer, ENET_PEER_STATE_CONNECTED); - - event -> type = ENET_EVENT_TYPE_CONNECT; - event -> peer = peer; - event -> data = peer -> eventData; - - return 1; - - case ENET_PEER_STATE_ZOMBIE: - host -> recalculateBandwidthLimits = 1; - - event -> type = ENET_EVENT_TYPE_DISCONNECT; - event -> peer = peer; - event -> data = peer -> eventData; - - enet_peer_reset (peer); - - return 1; - - case ENET_PEER_STATE_CONNECTED: - if (enet_list_empty (& peer -> dispatchedCommands)) - continue; - - event -> packet = enet_peer_receive (peer, & event -> channelID); - if (event -> packet == NULL) - continue; - - event -> type = ENET_EVENT_TYPE_RECEIVE; - event -> peer = peer; - - if (! enet_list_empty (& peer -> dispatchedCommands)) - { - peer -> needsDispatch = 1; - - enet_list_insert (enet_list_end (& host -> dispatchQueue), & peer -> dispatchList); - } - - return 1; - - default: - break; - } - } - - return 0; -} - -static void -enet_protocol_notify_connect (ENetHost * host, ENetPeer * peer, ENetEvent * event) -{ - host -> recalculateBandwidthLimits = 1; - - if (event != NULL) - { - enet_protocol_change_state (host, peer, ENET_PEER_STATE_CONNECTED); - - event -> type = ENET_EVENT_TYPE_CONNECT; - event -> peer = peer; - event -> data = peer -> eventData; - } - else - enet_protocol_dispatch_state (host, peer, peer -> state == ENET_PEER_STATE_CONNECTING ? ENET_PEER_STATE_CONNECTION_SUCCEEDED : ENET_PEER_STATE_CONNECTION_PENDING); -} - -static void -enet_protocol_notify_disconnect (ENetHost * host, ENetPeer * peer, ENetEvent * event) -{ - if (peer -> state >= ENET_PEER_STATE_CONNECTION_PENDING) - host -> recalculateBandwidthLimits = 1; - - if (peer -> state != ENET_PEER_STATE_CONNECTING && peer -> state < ENET_PEER_STATE_CONNECTION_SUCCEEDED) - enet_peer_reset (peer); - else - if (event != NULL) - { - event -> type = ENET_EVENT_TYPE_DISCONNECT; - event -> peer = peer; - event -> data = 0; - - enet_peer_reset (peer); - } - else - { - peer -> eventData = 0; - - enet_protocol_dispatch_state (host, peer, ENET_PEER_STATE_ZOMBIE); - } -} - -static void -enet_protocol_remove_sent_unreliable_commands (ENetPeer * peer) -{ - ENetOutgoingCommand * outgoingCommand; - - while (! enet_list_empty (& peer -> sentUnreliableCommands)) - { - outgoingCommand = (ENetOutgoingCommand *) enet_list_front (& peer -> sentUnreliableCommands); - - enet_list_remove (& outgoingCommand -> outgoingCommandList); - - if (outgoingCommand -> packet != NULL) - { - -- outgoingCommand -> packet -> referenceCount; - - if (outgoingCommand -> packet -> referenceCount == 0) - { - outgoingCommand -> packet -> flags |= ENET_PACKET_FLAG_SENT; - - enet_packet_destroy (outgoingCommand -> packet); - } - } - - enet_free (outgoingCommand); - } -} - -static ENetProtocolCommand -enet_protocol_remove_sent_reliable_command (ENetPeer * peer, enet_uint16 reliableSequenceNumber, enet_uint8 channelID) -{ - ENetOutgoingCommand * outgoingCommand = NULL; - ENetListIterator currentCommand; - ENetProtocolCommand commandNumber; - int wasSent = 1; - - for (currentCommand = enet_list_begin (& peer -> sentReliableCommands); - currentCommand != enet_list_end (& peer -> sentReliableCommands); - currentCommand = enet_list_next (currentCommand)) - { - outgoingCommand = (ENetOutgoingCommand *) currentCommand; - - if (outgoingCommand -> reliableSequenceNumber == reliableSequenceNumber && - outgoingCommand -> command.header.channelID == channelID) - break; - } - - if (currentCommand == enet_list_end (& peer -> sentReliableCommands)) - { - for (currentCommand = enet_list_begin (& peer -> outgoingReliableCommands); - currentCommand != enet_list_end (& peer -> outgoingReliableCommands); - currentCommand = enet_list_next (currentCommand)) - { - outgoingCommand = (ENetOutgoingCommand *) currentCommand; - - if (outgoingCommand -> sendAttempts < 1) return ENET_PROTOCOL_COMMAND_NONE; - - if (outgoingCommand -> reliableSequenceNumber == reliableSequenceNumber && - outgoingCommand -> command.header.channelID == channelID) - break; - } - - if (currentCommand == enet_list_end (& peer -> outgoingReliableCommands)) - return ENET_PROTOCOL_COMMAND_NONE; - - wasSent = 0; - } - - if (outgoingCommand == NULL) - return ENET_PROTOCOL_COMMAND_NONE; - - if (channelID < peer -> channelCount) - { - ENetChannel * channel = & peer -> channels [channelID]; - enet_uint16 reliableWindow = reliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; - if (channel -> reliableWindows [reliableWindow] > 0) - { - -- channel -> reliableWindows [reliableWindow]; - if (! channel -> reliableWindows [reliableWindow]) - channel -> usedReliableWindows &= ~ (1 << reliableWindow); - } - } - - commandNumber = (ENetProtocolCommand) (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_MASK); - - enet_list_remove (& outgoingCommand -> outgoingCommandList); - - if (outgoingCommand -> packet != NULL) - { - if (wasSent) - peer -> reliableDataInTransit -= outgoingCommand -> fragmentLength; - - -- outgoingCommand -> packet -> referenceCount; - - if (outgoingCommand -> packet -> referenceCount == 0) - { - outgoingCommand -> packet -> flags |= ENET_PACKET_FLAG_SENT; - - enet_packet_destroy (outgoingCommand -> packet); - } - } - - enet_free (outgoingCommand); - - if (enet_list_empty (& peer -> sentReliableCommands)) - return commandNumber; - - outgoingCommand = (ENetOutgoingCommand *) enet_list_front (& peer -> sentReliableCommands); - - peer -> nextTimeout = outgoingCommand -> sentTime + outgoingCommand -> roundTripTimeout; - - return commandNumber; -} - -static ENetPeer * -enet_protocol_handle_connect (ENetHost * host, ENetProtocolHeader * header, ENetProtocol * command) -{ - enet_uint8 incomingSessionID, outgoingSessionID; - enet_uint32 mtu, windowSize; - ENetChannel * channel; - size_t channelCount, duplicatePeers = 0; - ENetPeer * currentPeer, * peer = NULL; - ENetProtocol verifyCommand; - - channelCount = ENET_NET_TO_HOST_32 (command -> connect.channelCount); - - if (channelCount < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT || - channelCount > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT) - return NULL; - - for (currentPeer = host -> peers; - currentPeer < & host -> peers [host -> peerCount]; - ++ currentPeer) - { - if (currentPeer -> state == ENET_PEER_STATE_DISCONNECTED) - { - if (peer == NULL) - peer = currentPeer; - } - else - if (currentPeer -> state != ENET_PEER_STATE_CONNECTING && - currentPeer -> address.host == host -> receivedAddress.host) - { - if (currentPeer -> address.port == host -> receivedAddress.port && - currentPeer -> connectID == command -> connect.connectID) - return NULL; - - ++ duplicatePeers; - } - } - - if (peer == NULL || duplicatePeers >= host -> duplicatePeers) - return NULL; - - if (channelCount > host -> channelLimit) - channelCount = host -> channelLimit; - peer -> channels = (ENetChannel *) enet_malloc (channelCount * sizeof (ENetChannel)); - if (peer -> channels == NULL) - return NULL; - peer -> channelCount = channelCount; - peer -> state = ENET_PEER_STATE_ACKNOWLEDGING_CONNECT; - peer -> connectID = command -> connect.connectID; - peer -> address = host -> receivedAddress; - peer -> outgoingPeerID = ENET_NET_TO_HOST_16 (command -> connect.outgoingPeerID); - peer -> incomingBandwidth = ENET_NET_TO_HOST_32 (command -> connect.incomingBandwidth); - peer -> outgoingBandwidth = ENET_NET_TO_HOST_32 (command -> connect.outgoingBandwidth); - peer -> packetThrottleInterval = ENET_NET_TO_HOST_32 (command -> connect.packetThrottleInterval); - peer -> packetThrottleAcceleration = ENET_NET_TO_HOST_32 (command -> connect.packetThrottleAcceleration); - peer -> packetThrottleDeceleration = ENET_NET_TO_HOST_32 (command -> connect.packetThrottleDeceleration); - peer -> eventData = ENET_NET_TO_HOST_32 (command -> connect.data); - - incomingSessionID = command -> connect.incomingSessionID == 0xFF ? peer -> outgoingSessionID : command -> connect.incomingSessionID; - incomingSessionID = (incomingSessionID + 1) & (ENET_PROTOCOL_HEADER_SESSION_MASK >> ENET_PROTOCOL_HEADER_SESSION_SHIFT); - if (incomingSessionID == peer -> outgoingSessionID) - incomingSessionID = (incomingSessionID + 1) & (ENET_PROTOCOL_HEADER_SESSION_MASK >> ENET_PROTOCOL_HEADER_SESSION_SHIFT); - peer -> outgoingSessionID = incomingSessionID; - - outgoingSessionID = command -> connect.outgoingSessionID == 0xFF ? peer -> incomingSessionID : command -> connect.outgoingSessionID; - outgoingSessionID = (outgoingSessionID + 1) & (ENET_PROTOCOL_HEADER_SESSION_MASK >> ENET_PROTOCOL_HEADER_SESSION_SHIFT); - if (outgoingSessionID == peer -> incomingSessionID) - outgoingSessionID = (outgoingSessionID + 1) & (ENET_PROTOCOL_HEADER_SESSION_MASK >> ENET_PROTOCOL_HEADER_SESSION_SHIFT); - peer -> incomingSessionID = outgoingSessionID; - - for (channel = peer -> channels; - channel < & peer -> channels [channelCount]; - ++ channel) - { - channel -> outgoingReliableSequenceNumber = 0; - channel -> outgoingUnreliableSequenceNumber = 0; - channel -> incomingReliableSequenceNumber = 0; - channel -> incomingUnreliableSequenceNumber = 0; - - enet_list_clear (& channel -> incomingReliableCommands); - enet_list_clear (& channel -> incomingUnreliableCommands); - - channel -> usedReliableWindows = 0; - memset (channel -> reliableWindows, 0, sizeof (channel -> reliableWindows)); - } - - mtu = ENET_NET_TO_HOST_32 (command -> connect.mtu); - - if (mtu < ENET_PROTOCOL_MINIMUM_MTU) - mtu = ENET_PROTOCOL_MINIMUM_MTU; - else - if (mtu > ENET_PROTOCOL_MAXIMUM_MTU) - mtu = ENET_PROTOCOL_MAXIMUM_MTU; - - peer -> mtu = mtu; - - if (host -> outgoingBandwidth == 0 && - peer -> incomingBandwidth == 0) - peer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; - else - if (host -> outgoingBandwidth == 0 || - peer -> incomingBandwidth == 0) - peer -> windowSize = (ENET_MAX (host -> outgoingBandwidth, peer -> incomingBandwidth) / - ENET_PEER_WINDOW_SIZE_SCALE) * - ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; - else - peer -> windowSize = (ENET_MIN (host -> outgoingBandwidth, peer -> incomingBandwidth) / - ENET_PEER_WINDOW_SIZE_SCALE) * - ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; - - if (peer -> windowSize < ENET_PROTOCOL_MINIMUM_WINDOW_SIZE) - peer -> windowSize = ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; - else - if (peer -> windowSize > ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE) - peer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; - - if (host -> incomingBandwidth == 0) - windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; - else - windowSize = (host -> incomingBandwidth / ENET_PEER_WINDOW_SIZE_SCALE) * - ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; - - if (windowSize > ENET_NET_TO_HOST_32 (command -> connect.windowSize)) - windowSize = ENET_NET_TO_HOST_32 (command -> connect.windowSize); - - if (windowSize < ENET_PROTOCOL_MINIMUM_WINDOW_SIZE) - windowSize = ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; - else - if (windowSize > ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE) - windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; - - verifyCommand.header.command = ENET_PROTOCOL_COMMAND_VERIFY_CONNECT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; - verifyCommand.header.channelID = 0xFF; - verifyCommand.verifyConnect.outgoingPeerID = ENET_HOST_TO_NET_16 (peer -> incomingPeerID); - verifyCommand.verifyConnect.incomingSessionID = incomingSessionID; - verifyCommand.verifyConnect.outgoingSessionID = outgoingSessionID; - verifyCommand.verifyConnect.mtu = ENET_HOST_TO_NET_32 (peer -> mtu); - verifyCommand.verifyConnect.windowSize = ENET_HOST_TO_NET_32 (windowSize); - verifyCommand.verifyConnect.channelCount = ENET_HOST_TO_NET_32 (channelCount); - verifyCommand.verifyConnect.incomingBandwidth = ENET_HOST_TO_NET_32 (host -> incomingBandwidth); - verifyCommand.verifyConnect.outgoingBandwidth = ENET_HOST_TO_NET_32 (host -> outgoingBandwidth); - verifyCommand.verifyConnect.packetThrottleInterval = ENET_HOST_TO_NET_32 (peer -> packetThrottleInterval); - verifyCommand.verifyConnect.packetThrottleAcceleration = ENET_HOST_TO_NET_32 (peer -> packetThrottleAcceleration); - verifyCommand.verifyConnect.packetThrottleDeceleration = ENET_HOST_TO_NET_32 (peer -> packetThrottleDeceleration); - verifyCommand.verifyConnect.connectID = peer -> connectID; - - enet_peer_queue_outgoing_command (peer, & verifyCommand, NULL, 0, 0); - - return peer; -} - -static int -enet_protocol_handle_send_reliable (ENetHost * host, ENetPeer * peer, const ENetProtocol * command, enet_uint8 ** currentData) -{ - size_t dataLength; - - if (command -> header.channelID >= peer -> channelCount || - (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER)) - return -1; - - dataLength = ENET_NET_TO_HOST_16 (command -> sendReliable.dataLength); - * currentData += dataLength; - if (dataLength > host -> maximumPacketSize || - * currentData < host -> receivedData || - * currentData > & host -> receivedData [host -> receivedDataLength]) - return -1; - - if (enet_peer_queue_incoming_command (peer, command, (const enet_uint8 *) command + sizeof (ENetProtocolSendReliable), dataLength, ENET_PACKET_FLAG_RELIABLE, 0) == NULL) - return -1; - - return 0; -} - -static int -enet_protocol_handle_send_unsequenced (ENetHost * host, ENetPeer * peer, const ENetProtocol * command, enet_uint8 ** currentData) -{ - enet_uint32 unsequencedGroup, index; - size_t dataLength; - - if (command -> header.channelID >= peer -> channelCount || - (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER)) - return -1; - - dataLength = ENET_NET_TO_HOST_16 (command -> sendUnsequenced.dataLength); - * currentData += dataLength; - if (dataLength > host -> maximumPacketSize || - * currentData < host -> receivedData || - * currentData > & host -> receivedData [host -> receivedDataLength]) - return -1; - - unsequencedGroup = ENET_NET_TO_HOST_16 (command -> sendUnsequenced.unsequencedGroup); - index = unsequencedGroup % ENET_PEER_UNSEQUENCED_WINDOW_SIZE; - - if (unsequencedGroup < peer -> incomingUnsequencedGroup) - unsequencedGroup += 0x10000; - - if (unsequencedGroup >= (enet_uint32) peer -> incomingUnsequencedGroup + ENET_PEER_FREE_UNSEQUENCED_WINDOWS * ENET_PEER_UNSEQUENCED_WINDOW_SIZE) - return 0; - - unsequencedGroup &= 0xFFFF; - - if (unsequencedGroup - index != peer -> incomingUnsequencedGroup) - { - peer -> incomingUnsequencedGroup = unsequencedGroup - index; - - memset (peer -> unsequencedWindow, 0, sizeof (peer -> unsequencedWindow)); - } - else - if (peer -> unsequencedWindow [index / 32] & (1 << (index % 32))) - return 0; - - if (enet_peer_queue_incoming_command (peer, command, (const enet_uint8 *) command + sizeof (ENetProtocolSendUnsequenced), dataLength, ENET_PACKET_FLAG_UNSEQUENCED, 0) == NULL) - return -1; - - peer -> unsequencedWindow [index / 32] |= 1 << (index % 32); - - return 0; -} - -static int -enet_protocol_handle_send_unreliable (ENetHost * host, ENetPeer * peer, const ENetProtocol * command, enet_uint8 ** currentData) -{ - size_t dataLength; - - if (command -> header.channelID >= peer -> channelCount || - (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER)) - return -1; - - dataLength = ENET_NET_TO_HOST_16 (command -> sendUnreliable.dataLength); - * currentData += dataLength; - if (dataLength > host -> maximumPacketSize || - * currentData < host -> receivedData || - * currentData > & host -> receivedData [host -> receivedDataLength]) - return -1; - - if (enet_peer_queue_incoming_command (peer, command, (const enet_uint8 *) command + sizeof (ENetProtocolSendUnreliable), dataLength, 0, 0) == NULL) - return -1; - - return 0; -} - -static int -enet_protocol_handle_send_fragment (ENetHost * host, ENetPeer * peer, const ENetProtocol * command, enet_uint8 ** currentData) -{ - enet_uint32 fragmentNumber, - fragmentCount, - fragmentOffset, - fragmentLength, - startSequenceNumber, - totalLength; - ENetChannel * channel; - enet_uint16 startWindow, currentWindow; - ENetListIterator currentCommand; - ENetIncomingCommand * startCommand = NULL; - - if (command -> header.channelID >= peer -> channelCount || - (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER)) - return -1; - - fragmentLength = ENET_NET_TO_HOST_16 (command -> sendFragment.dataLength); - * currentData += fragmentLength; - if (fragmentLength > host -> maximumPacketSize || - * currentData < host -> receivedData || - * currentData > & host -> receivedData [host -> receivedDataLength]) - return -1; - - channel = & peer -> channels [command -> header.channelID]; - startSequenceNumber = ENET_NET_TO_HOST_16 (command -> sendFragment.startSequenceNumber); - startWindow = startSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; - currentWindow = channel -> incomingReliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; - - if (startSequenceNumber < channel -> incomingReliableSequenceNumber) - startWindow += ENET_PEER_RELIABLE_WINDOWS; - - if (startWindow < currentWindow || startWindow >= currentWindow + ENET_PEER_FREE_RELIABLE_WINDOWS - 1) - return 0; - - fragmentNumber = ENET_NET_TO_HOST_32 (command -> sendFragment.fragmentNumber); - fragmentCount = ENET_NET_TO_HOST_32 (command -> sendFragment.fragmentCount); - fragmentOffset = ENET_NET_TO_HOST_32 (command -> sendFragment.fragmentOffset); - totalLength = ENET_NET_TO_HOST_32 (command -> sendFragment.totalLength); - - if (fragmentCount > ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT || - fragmentNumber >= fragmentCount || - totalLength > host -> maximumPacketSize || - fragmentOffset >= totalLength || - fragmentLength > totalLength - fragmentOffset) - return -1; - - for (currentCommand = enet_list_previous (enet_list_end (& channel -> incomingReliableCommands)); - currentCommand != enet_list_end (& channel -> incomingReliableCommands); - currentCommand = enet_list_previous (currentCommand)) - { - ENetIncomingCommand * incomingCommand = (ENetIncomingCommand *) currentCommand; - - if (startSequenceNumber >= channel -> incomingReliableSequenceNumber) - { - if (incomingCommand -> reliableSequenceNumber < channel -> incomingReliableSequenceNumber) - continue; - } - else - if (incomingCommand -> reliableSequenceNumber >= channel -> incomingReliableSequenceNumber) - break; - - if (incomingCommand -> reliableSequenceNumber <= startSequenceNumber) - { - if (incomingCommand -> reliableSequenceNumber < startSequenceNumber) - break; - - if ((incomingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_MASK) != ENET_PROTOCOL_COMMAND_SEND_FRAGMENT || - totalLength != incomingCommand -> packet -> dataLength || - fragmentCount != incomingCommand -> fragmentCount) - return -1; - - startCommand = incomingCommand; - break; - } - } - - if (startCommand == NULL) - { - ENetProtocol hostCommand = * command; - - hostCommand.header.reliableSequenceNumber = startSequenceNumber; - - startCommand = enet_peer_queue_incoming_command (peer, & hostCommand, NULL, totalLength, ENET_PACKET_FLAG_RELIABLE, fragmentCount); - if (startCommand == NULL) - return -1; - } - - if ((startCommand -> fragments [fragmentNumber / 32] & (1 << (fragmentNumber % 32))) == 0) - { - -- startCommand -> fragmentsRemaining; - - startCommand -> fragments [fragmentNumber / 32] |= (1 << (fragmentNumber % 32)); - - if (fragmentOffset + fragmentLength > startCommand -> packet -> dataLength) - fragmentLength = startCommand -> packet -> dataLength - fragmentOffset; - - memcpy (startCommand -> packet -> data + fragmentOffset, - (enet_uint8 *) command + sizeof (ENetProtocolSendFragment), - fragmentLength); - - if (startCommand -> fragmentsRemaining <= 0) - enet_peer_dispatch_incoming_reliable_commands (peer, channel); - } - - return 0; -} - -static int -enet_protocol_handle_send_unreliable_fragment (ENetHost * host, ENetPeer * peer, const ENetProtocol * command, enet_uint8 ** currentData) -{ - enet_uint32 fragmentNumber, - fragmentCount, - fragmentOffset, - fragmentLength, - reliableSequenceNumber, - startSequenceNumber, - totalLength; - enet_uint16 reliableWindow, currentWindow; - ENetChannel * channel; - ENetListIterator currentCommand; - ENetIncomingCommand * startCommand = NULL; - - if (command -> header.channelID >= peer -> channelCount || - (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER)) - return -1; - - fragmentLength = ENET_NET_TO_HOST_16 (command -> sendFragment.dataLength); - * currentData += fragmentLength; - if (fragmentLength > host -> maximumPacketSize || - * currentData < host -> receivedData || - * currentData > & host -> receivedData [host -> receivedDataLength]) - return -1; - - channel = & peer -> channels [command -> header.channelID]; - reliableSequenceNumber = command -> header.reliableSequenceNumber; - startSequenceNumber = ENET_NET_TO_HOST_16 (command -> sendFragment.startSequenceNumber); - - reliableWindow = reliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; - currentWindow = channel -> incomingReliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; - - if (reliableSequenceNumber < channel -> incomingReliableSequenceNumber) - reliableWindow += ENET_PEER_RELIABLE_WINDOWS; - - if (reliableWindow < currentWindow || reliableWindow >= currentWindow + ENET_PEER_FREE_RELIABLE_WINDOWS - 1) - return 0; - - if (reliableSequenceNumber == channel -> incomingReliableSequenceNumber && - startSequenceNumber <= channel -> incomingUnreliableSequenceNumber) - return 0; - - fragmentNumber = ENET_NET_TO_HOST_32 (command -> sendFragment.fragmentNumber); - fragmentCount = ENET_NET_TO_HOST_32 (command -> sendFragment.fragmentCount); - fragmentOffset = ENET_NET_TO_HOST_32 (command -> sendFragment.fragmentOffset); - totalLength = ENET_NET_TO_HOST_32 (command -> sendFragment.totalLength); - - if (fragmentCount > ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT || - fragmentNumber >= fragmentCount || - totalLength > host -> maximumPacketSize || - fragmentOffset >= totalLength || - fragmentLength > totalLength - fragmentOffset) - return -1; - - for (currentCommand = enet_list_previous (enet_list_end (& channel -> incomingUnreliableCommands)); - currentCommand != enet_list_end (& channel -> incomingUnreliableCommands); - currentCommand = enet_list_previous (currentCommand)) - { - ENetIncomingCommand * incomingCommand = (ENetIncomingCommand *) currentCommand; - - if (reliableSequenceNumber >= channel -> incomingReliableSequenceNumber) - { - if (incomingCommand -> reliableSequenceNumber < channel -> incomingReliableSequenceNumber) - continue; - } - else - if (incomingCommand -> reliableSequenceNumber >= channel -> incomingReliableSequenceNumber) - break; - - if (incomingCommand -> reliableSequenceNumber < reliableSequenceNumber) - break; - - if (incomingCommand -> reliableSequenceNumber > reliableSequenceNumber) - continue; - - if (incomingCommand -> unreliableSequenceNumber <= startSequenceNumber) - { - if (incomingCommand -> unreliableSequenceNumber < startSequenceNumber) - break; - - if ((incomingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_MASK) != ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT || - totalLength != incomingCommand -> packet -> dataLength || - fragmentCount != incomingCommand -> fragmentCount) - return -1; - - startCommand = incomingCommand; - break; - } - } - - if (startCommand == NULL) - { - startCommand = enet_peer_queue_incoming_command (peer, command, NULL, totalLength, ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT, fragmentCount); - if (startCommand == NULL) - return -1; - } - - if ((startCommand -> fragments [fragmentNumber / 32] & (1 << (fragmentNumber % 32))) == 0) - { - -- startCommand -> fragmentsRemaining; - - startCommand -> fragments [fragmentNumber / 32] |= (1 << (fragmentNumber % 32)); - - if (fragmentOffset + fragmentLength > startCommand -> packet -> dataLength) - fragmentLength = startCommand -> packet -> dataLength - fragmentOffset; - - memcpy (startCommand -> packet -> data + fragmentOffset, - (enet_uint8 *) command + sizeof (ENetProtocolSendFragment), - fragmentLength); - - if (startCommand -> fragmentsRemaining <= 0) - enet_peer_dispatch_incoming_unreliable_commands (peer, channel); - } - - return 0; -} - -static int -enet_protocol_handle_ping (ENetHost * host, ENetPeer * peer, const ENetProtocol * command) -{ - if (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) - return -1; - - return 0; -} - -static int -enet_protocol_handle_bandwidth_limit (ENetHost * host, ENetPeer * peer, const ENetProtocol * command) -{ - if (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) - return -1; - - if (peer -> incomingBandwidth != 0) - -- host -> bandwidthLimitedPeers; - - peer -> incomingBandwidth = ENET_NET_TO_HOST_32 (command -> bandwidthLimit.incomingBandwidth); - peer -> outgoingBandwidth = ENET_NET_TO_HOST_32 (command -> bandwidthLimit.outgoingBandwidth); - - if (peer -> incomingBandwidth != 0) - ++ host -> bandwidthLimitedPeers; - - if (peer -> incomingBandwidth == 0 && host -> outgoingBandwidth == 0) - peer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; - else - if (peer -> incomingBandwidth == 0 || host -> outgoingBandwidth == 0) - peer -> windowSize = (ENET_MAX (peer -> incomingBandwidth, host -> outgoingBandwidth) / - ENET_PEER_WINDOW_SIZE_SCALE) * ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; - else - peer -> windowSize = (ENET_MIN (peer -> incomingBandwidth, host -> outgoingBandwidth) / - ENET_PEER_WINDOW_SIZE_SCALE) * ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; - - if (peer -> windowSize < ENET_PROTOCOL_MINIMUM_WINDOW_SIZE) - peer -> windowSize = ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; - else - if (peer -> windowSize > ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE) - peer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; - - return 0; -} - -static int -enet_protocol_handle_throttle_configure (ENetHost * host, ENetPeer * peer, const ENetProtocol * command) -{ - if (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) - return -1; - - peer -> packetThrottleInterval = ENET_NET_TO_HOST_32 (command -> throttleConfigure.packetThrottleInterval); - peer -> packetThrottleAcceleration = ENET_NET_TO_HOST_32 (command -> throttleConfigure.packetThrottleAcceleration); - peer -> packetThrottleDeceleration = ENET_NET_TO_HOST_32 (command -> throttleConfigure.packetThrottleDeceleration); - - return 0; -} - -static int -enet_protocol_handle_disconnect (ENetHost * host, ENetPeer * peer, const ENetProtocol * command) -{ - if (peer -> state == ENET_PEER_STATE_DISCONNECTED || peer -> state == ENET_PEER_STATE_ZOMBIE || peer -> state == ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT) - return 0; - - enet_peer_reset_queues (peer); - - if (peer -> state == ENET_PEER_STATE_CONNECTION_SUCCEEDED || peer -> state == ENET_PEER_STATE_DISCONNECTING || peer -> state == ENET_PEER_STATE_CONNECTING) - enet_protocol_dispatch_state (host, peer, ENET_PEER_STATE_ZOMBIE); - else - if (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) - { - if (peer -> state == ENET_PEER_STATE_CONNECTION_PENDING) host -> recalculateBandwidthLimits = 1; - - enet_peer_reset (peer); - } - else - if (command -> header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE) - enet_protocol_change_state (host, peer, ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT); - else - enet_protocol_dispatch_state (host, peer, ENET_PEER_STATE_ZOMBIE); - - if (peer -> state != ENET_PEER_STATE_DISCONNECTED) - peer -> eventData = ENET_NET_TO_HOST_32 (command -> disconnect.data); - - return 0; -} - -static int -enet_protocol_handle_acknowledge (ENetHost * host, ENetEvent * event, ENetPeer * peer, const ENetProtocol * command) -{ - enet_uint32 roundTripTime, - receivedSentTime, - receivedReliableSequenceNumber; - ENetProtocolCommand commandNumber; - - if (peer -> state == ENET_PEER_STATE_DISCONNECTED || peer -> state == ENET_PEER_STATE_ZOMBIE) - return 0; - - receivedSentTime = ENET_NET_TO_HOST_16 (command -> acknowledge.receivedSentTime); - receivedSentTime |= host -> serviceTime & 0xFFFF0000; - if ((receivedSentTime & 0x8000) > (host -> serviceTime & 0x8000)) - receivedSentTime -= 0x10000; - - if (ENET_TIME_LESS (host -> serviceTime, receivedSentTime)) - return 0; - - peer -> lastReceiveTime = host -> serviceTime; - peer -> earliestTimeout = 0; - - roundTripTime = ENET_TIME_DIFFERENCE (host -> serviceTime, receivedSentTime); - - enet_peer_throttle (peer, roundTripTime); - - peer -> roundTripTimeVariance -= peer -> roundTripTimeVariance / 4; - - if (roundTripTime >= peer -> roundTripTime) - { - peer -> roundTripTime += (roundTripTime - peer -> roundTripTime) / 8; - peer -> roundTripTimeVariance += (roundTripTime - peer -> roundTripTime) / 4; - } - else - { - peer -> roundTripTime -= (peer -> roundTripTime - roundTripTime) / 8; - peer -> roundTripTimeVariance += (peer -> roundTripTime - roundTripTime) / 4; - } - - if (peer -> roundTripTime < peer -> lowestRoundTripTime) - peer -> lowestRoundTripTime = peer -> roundTripTime; - - if (peer -> roundTripTimeVariance > peer -> highestRoundTripTimeVariance) - peer -> highestRoundTripTimeVariance = peer -> roundTripTimeVariance; - - if (peer -> packetThrottleEpoch == 0 || - ENET_TIME_DIFFERENCE (host -> serviceTime, peer -> packetThrottleEpoch) >= peer -> packetThrottleInterval) - { - peer -> lastRoundTripTime = peer -> lowestRoundTripTime; - peer -> lastRoundTripTimeVariance = peer -> highestRoundTripTimeVariance; - peer -> lowestRoundTripTime = peer -> roundTripTime; - peer -> highestRoundTripTimeVariance = peer -> roundTripTimeVariance; - peer -> packetThrottleEpoch = host -> serviceTime; - } - - receivedReliableSequenceNumber = ENET_NET_TO_HOST_16 (command -> acknowledge.receivedReliableSequenceNumber); - - commandNumber = enet_protocol_remove_sent_reliable_command (peer, receivedReliableSequenceNumber, command -> header.channelID); - - switch (peer -> state) - { - case ENET_PEER_STATE_ACKNOWLEDGING_CONNECT: - if (commandNumber != ENET_PROTOCOL_COMMAND_VERIFY_CONNECT) - return -1; - - enet_protocol_notify_connect (host, peer, event); - break; - - case ENET_PEER_STATE_DISCONNECTING: - if (commandNumber != ENET_PROTOCOL_COMMAND_DISCONNECT) - return -1; - - enet_protocol_notify_disconnect (host, peer, event); - break; - - case ENET_PEER_STATE_DISCONNECT_LATER: - if (enet_list_empty (& peer -> outgoingReliableCommands) && - enet_list_empty (& peer -> outgoingUnreliableCommands) && - enet_list_empty (& peer -> sentReliableCommands)) - enet_peer_disconnect (peer, peer -> eventData); - break; - - default: - break; - } - - return 0; -} - -static int -enet_protocol_handle_verify_connect (ENetHost * host, ENetEvent * event, ENetPeer * peer, const ENetProtocol * command) -{ - enet_uint32 mtu, windowSize; - size_t channelCount; - - if (peer -> state != ENET_PEER_STATE_CONNECTING) - return 0; - - channelCount = ENET_NET_TO_HOST_32 (command -> verifyConnect.channelCount); - - if (channelCount < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT || channelCount > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT || - ENET_NET_TO_HOST_32 (command -> verifyConnect.packetThrottleInterval) != peer -> packetThrottleInterval || - ENET_NET_TO_HOST_32 (command -> verifyConnect.packetThrottleAcceleration) != peer -> packetThrottleAcceleration || - ENET_NET_TO_HOST_32 (command -> verifyConnect.packetThrottleDeceleration) != peer -> packetThrottleDeceleration || - command -> verifyConnect.connectID != peer -> connectID) - { - peer -> eventData = 0; - - enet_protocol_dispatch_state (host, peer, ENET_PEER_STATE_ZOMBIE); - - return -1; - } - - enet_protocol_remove_sent_reliable_command (peer, 1, 0xFF); - - if (channelCount < peer -> channelCount) - peer -> channelCount = channelCount; - - peer -> outgoingPeerID = ENET_NET_TO_HOST_16 (command -> verifyConnect.outgoingPeerID); - peer -> incomingSessionID = command -> verifyConnect.incomingSessionID; - peer -> outgoingSessionID = command -> verifyConnect.outgoingSessionID; - - mtu = ENET_NET_TO_HOST_32 (command -> verifyConnect.mtu); - - if (mtu < ENET_PROTOCOL_MINIMUM_MTU) - mtu = ENET_PROTOCOL_MINIMUM_MTU; - else - if (mtu > ENET_PROTOCOL_MAXIMUM_MTU) - mtu = ENET_PROTOCOL_MAXIMUM_MTU; - - if (mtu < peer -> mtu) - peer -> mtu = mtu; - - windowSize = ENET_NET_TO_HOST_32 (command -> verifyConnect.windowSize); - - if (windowSize < ENET_PROTOCOL_MINIMUM_WINDOW_SIZE) - windowSize = ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; - - if (windowSize > ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE) - windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; - - if (windowSize < peer -> windowSize) - peer -> windowSize = windowSize; - - peer -> incomingBandwidth = ENET_NET_TO_HOST_32 (command -> verifyConnect.incomingBandwidth); - peer -> outgoingBandwidth = ENET_NET_TO_HOST_32 (command -> verifyConnect.outgoingBandwidth); - - enet_protocol_notify_connect (host, peer, event); - return 0; -} - -static int -enet_protocol_handle_incoming_commands (ENetHost * host, ENetEvent * event) -{ - ENetProtocolHeader * header; - ENetProtocol * command; - ENetPeer * peer; - enet_uint8 * currentData; - size_t headerSize; - enet_uint16 peerID, flags; - enet_uint8 sessionID; - - if (host -> receivedDataLength < (size_t) & ((ENetProtocolHeader *) 0) -> sentTime) - return 0; - - header = (ENetProtocolHeader *) host -> receivedData; - - peerID = ENET_NET_TO_HOST_16 (header -> peerID); - sessionID = (peerID & ENET_PROTOCOL_HEADER_SESSION_MASK) >> ENET_PROTOCOL_HEADER_SESSION_SHIFT; - flags = peerID & ENET_PROTOCOL_HEADER_FLAG_MASK; - peerID &= ~ (ENET_PROTOCOL_HEADER_FLAG_MASK | ENET_PROTOCOL_HEADER_SESSION_MASK); - - headerSize = (flags & ENET_PROTOCOL_HEADER_FLAG_SENT_TIME ? sizeof (ENetProtocolHeader) : (size_t) & ((ENetProtocolHeader *) 0) -> sentTime); - if (host -> checksum != NULL) - headerSize += sizeof (enet_uint32); - - if (peerID == ENET_PROTOCOL_MAXIMUM_PEER_ID) - peer = NULL; - else - if (peerID >= host -> peerCount) - return 0; - else - { - peer = & host -> peers [peerID]; - - if (peer -> state == ENET_PEER_STATE_DISCONNECTED || - peer -> state == ENET_PEER_STATE_ZOMBIE || - ((host -> receivedAddress.host != peer -> address.host || - host -> receivedAddress.port != peer -> address.port) && - peer -> address.host != ENET_HOST_BROADCAST) || - (peer -> outgoingPeerID < ENET_PROTOCOL_MAXIMUM_PEER_ID && - sessionID != peer -> incomingSessionID)) - return 0; - } - - if (flags & ENET_PROTOCOL_HEADER_FLAG_COMPRESSED) - { - size_t originalSize; - if (host -> compressor.context == NULL || host -> compressor.decompress == NULL) - return 0; - - originalSize = host -> compressor.decompress (host -> compressor.context, - host -> receivedData + headerSize, - host -> receivedDataLength - headerSize, - host -> packetData [1] + headerSize, - sizeof (host -> packetData [1]) - headerSize); - if (originalSize <= 0 || originalSize > sizeof (host -> packetData [1]) - headerSize) - return 0; - - memcpy (host -> packetData [1], header, headerSize); - host -> receivedData = host -> packetData [1]; - host -> receivedDataLength = headerSize + originalSize; - } - - if (host -> checksum != NULL) - { - enet_uint32 * checksum = (enet_uint32 *) & host -> receivedData [headerSize - sizeof (enet_uint32)], - desiredChecksum = * checksum; - ENetBuffer buffer; - - * checksum = peer != NULL ? peer -> connectID : 0; - - buffer.data = host -> receivedData; - buffer.dataLength = host -> receivedDataLength; - - if (host -> checksum (& buffer, 1) != desiredChecksum) - return 0; - } - - if (peer != NULL) - { - peer -> address.host = host -> receivedAddress.host; - peer -> address.port = host -> receivedAddress.port; - peer -> incomingDataTotal += host -> receivedDataLength; - } - - currentData = host -> receivedData + headerSize; - - while (currentData < & host -> receivedData [host -> receivedDataLength]) - { - enet_uint8 commandNumber; - size_t commandSize; - - command = (ENetProtocol *) currentData; - - if (currentData + sizeof (ENetProtocolCommandHeader) > & host -> receivedData [host -> receivedDataLength]) - break; - - commandNumber = command -> header.command & ENET_PROTOCOL_COMMAND_MASK; - if (commandNumber >= ENET_PROTOCOL_COMMAND_COUNT) - break; - - commandSize = commandSizes [commandNumber]; - if (commandSize == 0 || currentData + commandSize > & host -> receivedData [host -> receivedDataLength]) - break; - - currentData += commandSize; - - if (peer == NULL && commandNumber != ENET_PROTOCOL_COMMAND_CONNECT) - break; - - command -> header.reliableSequenceNumber = ENET_NET_TO_HOST_16 (command -> header.reliableSequenceNumber); - - switch (commandNumber) - { - case ENET_PROTOCOL_COMMAND_ACKNOWLEDGE: - if (enet_protocol_handle_acknowledge (host, event, peer, command)) - goto commandError; - break; - - case ENET_PROTOCOL_COMMAND_CONNECT: - if (peer != NULL) - goto commandError; - peer = enet_protocol_handle_connect (host, header, command); - if (peer == NULL) - goto commandError; - break; - - case ENET_PROTOCOL_COMMAND_VERIFY_CONNECT: - if (enet_protocol_handle_verify_connect (host, event, peer, command)) - goto commandError; - break; - - case ENET_PROTOCOL_COMMAND_DISCONNECT: - if (enet_protocol_handle_disconnect (host, peer, command)) - goto commandError; - break; - - case ENET_PROTOCOL_COMMAND_PING: - if (enet_protocol_handle_ping (host, peer, command)) - goto commandError; - break; - - case ENET_PROTOCOL_COMMAND_SEND_RELIABLE: - if (enet_protocol_handle_send_reliable (host, peer, command, & currentData)) - goto commandError; - break; - - case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE: - if (enet_protocol_handle_send_unreliable (host, peer, command, & currentData)) - goto commandError; - break; - - case ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED: - if (enet_protocol_handle_send_unsequenced (host, peer, command, & currentData)) - goto commandError; - break; - - case ENET_PROTOCOL_COMMAND_SEND_FRAGMENT: - if (enet_protocol_handle_send_fragment (host, peer, command, & currentData)) - goto commandError; - break; - - case ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT: - if (enet_protocol_handle_bandwidth_limit (host, peer, command)) - goto commandError; - break; - - case ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE: - if (enet_protocol_handle_throttle_configure (host, peer, command)) - goto commandError; - break; - - case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT: - if (enet_protocol_handle_send_unreliable_fragment (host, peer, command, & currentData)) - goto commandError; - break; - - default: - goto commandError; - } - - if (peer != NULL && - (command -> header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE) != 0) - { - enet_uint16 sentTime; - - if (! (flags & ENET_PROTOCOL_HEADER_FLAG_SENT_TIME)) - break; - - sentTime = ENET_NET_TO_HOST_16 (header -> sentTime); - - switch (peer -> state) - { - case ENET_PEER_STATE_DISCONNECTING: - case ENET_PEER_STATE_ACKNOWLEDGING_CONNECT: - case ENET_PEER_STATE_DISCONNECTED: - case ENET_PEER_STATE_ZOMBIE: - break; - - case ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT: - if ((command -> header.command & ENET_PROTOCOL_COMMAND_MASK) == ENET_PROTOCOL_COMMAND_DISCONNECT) - enet_peer_queue_acknowledgement (peer, command, sentTime); - break; - - default: - enet_peer_queue_acknowledgement (peer, command, sentTime); - break; - } - } - } - -commandError: - if (event != NULL && event -> type != ENET_EVENT_TYPE_NONE) - return 1; - - return 0; -} - -static int -enet_protocol_receive_incoming_commands (ENetHost * host, ENetEvent * event) -{ - int packets; - - for (packets = 0; packets < 256; ++ packets) - { - int receivedLength; - ENetBuffer buffer; - - buffer.data = host -> packetData [0]; - buffer.dataLength = sizeof (host -> packetData [0]); - - receivedLength = enet_socket_receive (host -> socket, - & host -> receivedAddress, - & buffer, - 1); - - if (receivedLength < 0) - return -1; - - if (receivedLength == 0) - return 0; - - host -> receivedData = host -> packetData [0]; - host -> receivedDataLength = receivedLength; - - host -> totalReceivedData += receivedLength; - host -> totalReceivedPackets ++; - - if (host -> intercept != NULL) - { - switch (host -> intercept (host, event)) - { - case 1: - if (event != NULL && event -> type != ENET_EVENT_TYPE_NONE) - return 1; - - continue; - - case -1: - return -1; - - default: - break; - } - } - - switch (enet_protocol_handle_incoming_commands (host, event)) - { - case 1: - return 1; - - case -1: - return -1; - - default: - break; - } - } - - return -1; -} - -static void -enet_protocol_send_acknowledgements (ENetHost * host, ENetPeer * peer) -{ - ENetProtocol * command = & host -> commands [host -> commandCount]; - ENetBuffer * buffer = & host -> buffers [host -> bufferCount]; - ENetAcknowledgement * acknowledgement; - ENetListIterator currentAcknowledgement; - enet_uint16 reliableSequenceNumber; - - currentAcknowledgement = enet_list_begin (& peer -> acknowledgements); - - while (currentAcknowledgement != enet_list_end (& peer -> acknowledgements)) - { - if (command >= & host -> commands [sizeof (host -> commands) / sizeof (ENetProtocol)] || - buffer >= & host -> buffers [sizeof (host -> buffers) / sizeof (ENetBuffer)] || - peer -> mtu - host -> packetSize < sizeof (ENetProtocolAcknowledge)) - { - host -> continueSending = 1; - - break; - } - - acknowledgement = (ENetAcknowledgement *) currentAcknowledgement; - - currentAcknowledgement = enet_list_next (currentAcknowledgement); - - buffer -> data = command; - buffer -> dataLength = sizeof (ENetProtocolAcknowledge); - - host -> packetSize += buffer -> dataLength; - - reliableSequenceNumber = ENET_HOST_TO_NET_16 (acknowledgement -> command.header.reliableSequenceNumber); - - command -> header.command = ENET_PROTOCOL_COMMAND_ACKNOWLEDGE; - command -> header.channelID = acknowledgement -> command.header.channelID; - command -> header.reliableSequenceNumber = reliableSequenceNumber; - command -> acknowledge.receivedReliableSequenceNumber = reliableSequenceNumber; - command -> acknowledge.receivedSentTime = ENET_HOST_TO_NET_16 (acknowledgement -> sentTime); - - if ((acknowledgement -> command.header.command & ENET_PROTOCOL_COMMAND_MASK) == ENET_PROTOCOL_COMMAND_DISCONNECT) - enet_protocol_dispatch_state (host, peer, ENET_PEER_STATE_ZOMBIE); - - enet_list_remove (& acknowledgement -> acknowledgementList); - enet_free (acknowledgement); - - ++ command; - ++ buffer; - } - - host -> commandCount = command - host -> commands; - host -> bufferCount = buffer - host -> buffers; -} - -static void -enet_protocol_send_unreliable_outgoing_commands (ENetHost * host, ENetPeer * peer) -{ - ENetProtocol * command = & host -> commands [host -> commandCount]; - ENetBuffer * buffer = & host -> buffers [host -> bufferCount]; - ENetOutgoingCommand * outgoingCommand; - ENetListIterator currentCommand; - - currentCommand = enet_list_begin (& peer -> outgoingUnreliableCommands); - - while (currentCommand != enet_list_end (& peer -> outgoingUnreliableCommands)) - { - size_t commandSize; - - outgoingCommand = (ENetOutgoingCommand *) currentCommand; - commandSize = commandSizes [outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_MASK]; - - if (command >= & host -> commands [sizeof (host -> commands) / sizeof (ENetProtocol)] || - buffer + 1 >= & host -> buffers [sizeof (host -> buffers) / sizeof (ENetBuffer)] || - peer -> mtu - host -> packetSize < commandSize || - (outgoingCommand -> packet != NULL && - peer -> mtu - host -> packetSize < commandSize + outgoingCommand -> fragmentLength)) - { - host -> continueSending = 1; - - break; - } - - currentCommand = enet_list_next (currentCommand); - - if (outgoingCommand -> packet != NULL && outgoingCommand -> fragmentOffset == 0) - { - peer -> packetThrottleCounter += ENET_PEER_PACKET_THROTTLE_COUNTER; - peer -> packetThrottleCounter %= ENET_PEER_PACKET_THROTTLE_SCALE; - - if (peer -> packetThrottleCounter > peer -> packetThrottle) - { - enet_uint16 reliableSequenceNumber = outgoingCommand -> reliableSequenceNumber, - unreliableSequenceNumber = outgoingCommand -> unreliableSequenceNumber; - for (;;) - { - -- outgoingCommand -> packet -> referenceCount; - - if (outgoingCommand -> packet -> referenceCount == 0) - enet_packet_destroy (outgoingCommand -> packet); - - enet_list_remove (& outgoingCommand -> outgoingCommandList); - enet_free (outgoingCommand); - - if (currentCommand == enet_list_end (& peer -> outgoingUnreliableCommands)) - break; - - outgoingCommand = (ENetOutgoingCommand *) currentCommand; - if (outgoingCommand -> reliableSequenceNumber != reliableSequenceNumber || - outgoingCommand -> unreliableSequenceNumber != unreliableSequenceNumber) - break; - - currentCommand = enet_list_next (currentCommand); - } - - continue; - } - } - - buffer -> data = command; - buffer -> dataLength = commandSize; - - host -> packetSize += buffer -> dataLength; - - * command = outgoingCommand -> command; - - enet_list_remove (& outgoingCommand -> outgoingCommandList); - - if (outgoingCommand -> packet != NULL) - { - ++ buffer; - - buffer -> data = outgoingCommand -> packet -> data + outgoingCommand -> fragmentOffset; - buffer -> dataLength = outgoingCommand -> fragmentLength; - - host -> packetSize += buffer -> dataLength; - - enet_list_insert (enet_list_end (& peer -> sentUnreliableCommands), outgoingCommand); - } - else - enet_free (outgoingCommand); - - ++ command; - ++ buffer; - } - - host -> commandCount = command - host -> commands; - host -> bufferCount = buffer - host -> buffers; - - if (peer -> state == ENET_PEER_STATE_DISCONNECT_LATER && - enet_list_empty (& peer -> outgoingReliableCommands) && - enet_list_empty (& peer -> outgoingUnreliableCommands) && - enet_list_empty (& peer -> sentReliableCommands)) - enet_peer_disconnect (peer, peer -> eventData); -} - -static int -enet_protocol_check_timeouts (ENetHost * host, ENetPeer * peer, ENetEvent * event) -{ - ENetOutgoingCommand * outgoingCommand; - ENetListIterator currentCommand, insertPosition; - - currentCommand = enet_list_begin (& peer -> sentReliableCommands); - insertPosition = enet_list_begin (& peer -> outgoingReliableCommands); - - while (currentCommand != enet_list_end (& peer -> sentReliableCommands)) - { - outgoingCommand = (ENetOutgoingCommand *) currentCommand; - - currentCommand = enet_list_next (currentCommand); - - if (ENET_TIME_DIFFERENCE (host -> serviceTime, outgoingCommand -> sentTime) < outgoingCommand -> roundTripTimeout) - continue; - - if (peer -> earliestTimeout == 0 || - ENET_TIME_LESS (outgoingCommand -> sentTime, peer -> earliestTimeout)) - peer -> earliestTimeout = outgoingCommand -> sentTime; - - if (peer -> earliestTimeout != 0 && - (ENET_TIME_DIFFERENCE (host -> serviceTime, peer -> earliestTimeout) >= peer -> timeoutMaximum || - (outgoingCommand -> roundTripTimeout >= outgoingCommand -> roundTripTimeoutLimit && - ENET_TIME_DIFFERENCE (host -> serviceTime, peer -> earliestTimeout) >= peer -> timeoutMinimum))) - { - enet_protocol_notify_disconnect (host, peer, event); - - return 1; - } - - if (outgoingCommand -> packet != NULL) - peer -> reliableDataInTransit -= outgoingCommand -> fragmentLength; - - ++ peer -> packetsLost; - - outgoingCommand -> roundTripTimeout *= 2; - - enet_list_insert (insertPosition, enet_list_remove (& outgoingCommand -> outgoingCommandList)); - - if (currentCommand == enet_list_begin (& peer -> sentReliableCommands) && - ! enet_list_empty (& peer -> sentReliableCommands)) - { - outgoingCommand = (ENetOutgoingCommand *) currentCommand; - - peer -> nextTimeout = outgoingCommand -> sentTime + outgoingCommand -> roundTripTimeout; - } - } - - return 0; -} - -static int -enet_protocol_send_reliable_outgoing_commands (ENetHost * host, ENetPeer * peer) -{ - ENetProtocol * command = & host -> commands [host -> commandCount]; - ENetBuffer * buffer = & host -> buffers [host -> bufferCount]; - ENetOutgoingCommand * outgoingCommand; - ENetListIterator currentCommand; - ENetChannel *channel; - enet_uint16 reliableWindow; - size_t commandSize; - int windowExceeded = 0, windowWrap = 0, canPing = 1; - - currentCommand = enet_list_begin (& peer -> outgoingReliableCommands); - - while (currentCommand != enet_list_end (& peer -> outgoingReliableCommands)) - { - outgoingCommand = (ENetOutgoingCommand *) currentCommand; - - channel = outgoingCommand -> command.header.channelID < peer -> channelCount ? & peer -> channels [outgoingCommand -> command.header.channelID] : NULL; - reliableWindow = outgoingCommand -> reliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; - if (channel != NULL) - { - if (! windowWrap && - outgoingCommand -> sendAttempts < 1 && - ! (outgoingCommand -> reliableSequenceNumber % ENET_PEER_RELIABLE_WINDOW_SIZE) && - (channel -> reliableWindows [(reliableWindow + ENET_PEER_RELIABLE_WINDOWS - 1) % ENET_PEER_RELIABLE_WINDOWS] >= ENET_PEER_RELIABLE_WINDOW_SIZE || - channel -> usedReliableWindows & ((((1 << ENET_PEER_FREE_RELIABLE_WINDOWS) - 1) << reliableWindow) | - (((1 << ENET_PEER_FREE_RELIABLE_WINDOWS) - 1) >> (ENET_PEER_RELIABLE_WINDOWS - reliableWindow))))) - windowWrap = 1; - if (windowWrap) - { - currentCommand = enet_list_next (currentCommand); - - continue; - } - } - - if (outgoingCommand -> packet != NULL) - { - if (! windowExceeded) - { - enet_uint32 windowSize = (peer -> packetThrottle * peer -> windowSize) / ENET_PEER_PACKET_THROTTLE_SCALE; - - if (peer -> reliableDataInTransit + outgoingCommand -> fragmentLength > ENET_MAX (windowSize, peer -> mtu)) - windowExceeded = 1; - } - if (windowExceeded) - { - currentCommand = enet_list_next (currentCommand); - - continue; - } - } - - canPing = 0; - - commandSize = commandSizes [outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_MASK]; - if (command >= & host -> commands [sizeof (host -> commands) / sizeof (ENetProtocol)] || - buffer + 1 >= & host -> buffers [sizeof (host -> buffers) / sizeof (ENetBuffer)] || - peer -> mtu - host -> packetSize < commandSize || - (outgoingCommand -> packet != NULL && - (enet_uint16) (peer -> mtu - host -> packetSize) < (enet_uint16) (commandSize + outgoingCommand -> fragmentLength))) - { - host -> continueSending = 1; - - break; - } - - currentCommand = enet_list_next (currentCommand); - - if (channel != NULL && outgoingCommand -> sendAttempts < 1) - { - channel -> usedReliableWindows |= 1 << reliableWindow; - ++ channel -> reliableWindows [reliableWindow]; - } - - ++ outgoingCommand -> sendAttempts; - - if (outgoingCommand -> roundTripTimeout == 0) - { - outgoingCommand -> roundTripTimeout = peer -> roundTripTime + 4 * peer -> roundTripTimeVariance; - outgoingCommand -> roundTripTimeoutLimit = peer -> timeoutLimit * outgoingCommand -> roundTripTimeout; - } - - if (enet_list_empty (& peer -> sentReliableCommands)) - peer -> nextTimeout = host -> serviceTime + outgoingCommand -> roundTripTimeout; - - enet_list_insert (enet_list_end (& peer -> sentReliableCommands), - enet_list_remove (& outgoingCommand -> outgoingCommandList)); - - outgoingCommand -> sentTime = host -> serviceTime; - - buffer -> data = command; - buffer -> dataLength = commandSize; - - host -> packetSize += buffer -> dataLength; - host -> headerFlags |= ENET_PROTOCOL_HEADER_FLAG_SENT_TIME; - - * command = outgoingCommand -> command; - - if (outgoingCommand -> packet != NULL) - { - ++ buffer; - - buffer -> data = outgoingCommand -> packet -> data + outgoingCommand -> fragmentOffset; - buffer -> dataLength = outgoingCommand -> fragmentLength; - - host -> packetSize += outgoingCommand -> fragmentLength; - - peer -> reliableDataInTransit += outgoingCommand -> fragmentLength; - } - - ++ peer -> packetsSent; - - ++ command; - ++ buffer; - } - - host -> commandCount = command - host -> commands; - host -> bufferCount = buffer - host -> buffers; - - return canPing; -} - -static int -enet_protocol_send_outgoing_commands (ENetHost * host, ENetEvent * event, int checkForTimeouts) -{ - enet_uint8 headerData [sizeof (ENetProtocolHeader) + sizeof (enet_uint32)]; - ENetProtocolHeader * header = (ENetProtocolHeader *) headerData; - ENetPeer * currentPeer; - int sentLength; - size_t shouldCompress = 0; - - host -> continueSending = 1; - - while (host -> continueSending) - for (host -> continueSending = 0, - currentPeer = host -> peers; - currentPeer < & host -> peers [host -> peerCount]; - ++ currentPeer) - { - if (currentPeer -> state == ENET_PEER_STATE_DISCONNECTED || - currentPeer -> state == ENET_PEER_STATE_ZOMBIE) - continue; - - host -> headerFlags = 0; - host -> commandCount = 0; - host -> bufferCount = 1; - host -> packetSize = sizeof (ENetProtocolHeader); - - if (! enet_list_empty (& currentPeer -> acknowledgements)) - enet_protocol_send_acknowledgements (host, currentPeer); - - if (checkForTimeouts != 0 && - ! enet_list_empty (& currentPeer -> sentReliableCommands) && - ENET_TIME_GREATER_EQUAL (host -> serviceTime, currentPeer -> nextTimeout) && - enet_protocol_check_timeouts (host, currentPeer, event) == 1) - { - if (event != NULL && event -> type != ENET_EVENT_TYPE_NONE) - return 1; - else - continue; - } - - if ((enet_list_empty (& currentPeer -> outgoingReliableCommands) || - enet_protocol_send_reliable_outgoing_commands (host, currentPeer)) && - enet_list_empty (& currentPeer -> sentReliableCommands) && - ENET_TIME_DIFFERENCE (host -> serviceTime, currentPeer -> lastReceiveTime) >= currentPeer -> pingInterval && - currentPeer -> mtu - host -> packetSize >= sizeof (ENetProtocolPing)) - { - enet_peer_ping (currentPeer); - enet_protocol_send_reliable_outgoing_commands (host, currentPeer); - } - - if (! enet_list_empty (& currentPeer -> outgoingUnreliableCommands)) - enet_protocol_send_unreliable_outgoing_commands (host, currentPeer); - - if (host -> commandCount == 0) - continue; - - if (currentPeer -> packetLossEpoch == 0) - currentPeer -> packetLossEpoch = host -> serviceTime; - else - if (ENET_TIME_DIFFERENCE (host -> serviceTime, currentPeer -> packetLossEpoch) >= ENET_PEER_PACKET_LOSS_INTERVAL && - currentPeer -> packetsSent > 0) - { - enet_uint32 packetLoss = currentPeer -> packetsLost * ENET_PEER_PACKET_LOSS_SCALE / currentPeer -> packetsSent; - -#ifdef ENET_DEBUG - printf ("peer %u: %f%%+-%f%% packet loss, %u+-%u ms round trip time, %f%% throttle, %u/%u outgoing, %u/%u incoming\n", currentPeer -> incomingPeerID, currentPeer -> packetLoss / (float) ENET_PEER_PACKET_LOSS_SCALE, currentPeer -> packetLossVariance / (float) ENET_PEER_PACKET_LOSS_SCALE, currentPeer -> roundTripTime, currentPeer -> roundTripTimeVariance, currentPeer -> packetThrottle / (float) ENET_PEER_PACKET_THROTTLE_SCALE, enet_list_size (& currentPeer -> outgoingReliableCommands), enet_list_size (& currentPeer -> outgoingUnreliableCommands), currentPeer -> channels != NULL ? enet_list_size (& currentPeer -> channels -> incomingReliableCommands) : 0, currentPeer -> channels != NULL ? enet_list_size (& currentPeer -> channels -> incomingUnreliableCommands) : 0); -#endif - - currentPeer -> packetLossVariance -= currentPeer -> packetLossVariance / 4; - - if (packetLoss >= currentPeer -> packetLoss) - { - currentPeer -> packetLoss += (packetLoss - currentPeer -> packetLoss) / 8; - currentPeer -> packetLossVariance += (packetLoss - currentPeer -> packetLoss) / 4; - } - else - { - currentPeer -> packetLoss -= (currentPeer -> packetLoss - packetLoss) / 8; - currentPeer -> packetLossVariance += (currentPeer -> packetLoss - packetLoss) / 4; - } - - currentPeer -> packetLossEpoch = host -> serviceTime; - currentPeer -> packetsSent = 0; - currentPeer -> packetsLost = 0; - } - - host -> buffers -> data = headerData; - if (host -> headerFlags & ENET_PROTOCOL_HEADER_FLAG_SENT_TIME) - { - header -> sentTime = ENET_HOST_TO_NET_16 (host -> serviceTime & 0xFFFF); - - host -> buffers -> dataLength = sizeof (ENetProtocolHeader); - } - else - host -> buffers -> dataLength = (size_t) & ((ENetProtocolHeader *) 0) -> sentTime; - - shouldCompress = 0; - if (host -> compressor.context != NULL && host -> compressor.compress != NULL) - { - size_t originalSize = host -> packetSize - sizeof(ENetProtocolHeader), - compressedSize = host -> compressor.compress (host -> compressor.context, - & host -> buffers [1], host -> bufferCount - 1, - originalSize, - host -> packetData [1], - originalSize); - if (compressedSize > 0 && compressedSize < originalSize) - { - host -> headerFlags |= ENET_PROTOCOL_HEADER_FLAG_COMPRESSED; - shouldCompress = compressedSize; -#ifdef ENET_DEBUG_COMPRESS - printf ("peer %u: compressed %u -> %u (%u%%)\n", currentPeer -> incomingPeerID, originalSize, compressedSize, (compressedSize * 100) / originalSize); -#endif - } - } - - if (currentPeer -> outgoingPeerID < ENET_PROTOCOL_MAXIMUM_PEER_ID) - host -> headerFlags |= currentPeer -> outgoingSessionID << ENET_PROTOCOL_HEADER_SESSION_SHIFT; - header -> peerID = ENET_HOST_TO_NET_16 (currentPeer -> outgoingPeerID | host -> headerFlags); - if (host -> checksum != NULL) - { - enet_uint32 * checksum = (enet_uint32 *) & headerData [host -> buffers -> dataLength]; - * checksum = currentPeer -> outgoingPeerID < ENET_PROTOCOL_MAXIMUM_PEER_ID ? currentPeer -> connectID : 0; - host -> buffers -> dataLength += sizeof (enet_uint32); - * checksum = host -> checksum (host -> buffers, host -> bufferCount); - } - - if (shouldCompress > 0) - { - host -> buffers [1].data = host -> packetData [1]; - host -> buffers [1].dataLength = shouldCompress; - host -> bufferCount = 2; - } - - currentPeer -> lastSendTime = host -> serviceTime; - - sentLength = enet_socket_send (host -> socket, & currentPeer -> address, host -> buffers, host -> bufferCount); - - enet_protocol_remove_sent_unreliable_commands (currentPeer); - - if (sentLength < 0) - return -1; - - host -> totalSentData += sentLength; - host -> totalSentPackets ++; - } - - return 0; -} - -/** Sends any queued packets on the host specified to its designated peers. - - @param host host to flush - @remarks this function need only be used in circumstances where one wishes to send queued packets earlier than in a call to enet_host_service(). - @ingroup host -*/ -void -enet_host_flush (ENetHost * host) -{ - host -> serviceTime = enet_time_get (); - - enet_protocol_send_outgoing_commands (host, NULL, 0); -} - -/** Checks for any queued events on the host and dispatches one if available. - - @param host host to check for events - @param event an event structure where event details will be placed if available - @retval > 0 if an event was dispatched - @retval 0 if no events are available - @retval < 0 on failure - @ingroup host -*/ -int -enet_host_check_events (ENetHost * host, ENetEvent * event) -{ - if (event == NULL) return -1; - - event -> type = ENET_EVENT_TYPE_NONE; - event -> peer = NULL; - event -> packet = NULL; - - return enet_protocol_dispatch_incoming_commands (host, event); -} - -/** Waits for events on the host specified and shuttles packets between - the host and its peers. - - @param host host to service - @param event an event structure where event details will be placed if one occurs - if event == NULL then no events will be delivered - @param timeout number of milliseconds that ENet should wait for events - @retval > 0 if an event occurred within the specified time limit - @retval 0 if no event occurred - @retval < 0 on failure - @remarks enet_host_service should be called fairly regularly for adequate performance - @ingroup host -*/ -int -enet_host_service (ENetHost * host, ENetEvent * event, enet_uint32 timeout) -{ - enet_uint32 waitCondition; - - if (event != NULL) - { - event -> type = ENET_EVENT_TYPE_NONE; - event -> peer = NULL; - event -> packet = NULL; - - switch (enet_protocol_dispatch_incoming_commands (host, event)) - { - case 1: - return 1; - - case -1: -#ifdef ENET_DEBUG - perror ("Error dispatching incoming packets"); -#endif - - return -1; - - default: - break; - } - } - - host -> serviceTime = enet_time_get (); - - timeout += host -> serviceTime; - - do - { - if (ENET_TIME_DIFFERENCE (host -> serviceTime, host -> bandwidthThrottleEpoch) >= ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL) - enet_host_bandwidth_throttle (host); - - switch (enet_protocol_send_outgoing_commands (host, event, 1)) - { - case 1: - return 1; - - case -1: -#ifdef ENET_DEBUG - perror ("Error sending outgoing packets"); -#endif - - return -1; - - default: - break; - } - - switch (enet_protocol_receive_incoming_commands (host, event)) - { - case 1: - return 1; - - case -1: -#ifdef ENET_DEBUG - perror ("Error receiving incoming packets"); -#endif - - return -1; - - default: - break; - } - - switch (enet_protocol_send_outgoing_commands (host, event, 1)) - { - case 1: - return 1; - - case -1: -#ifdef ENET_DEBUG - perror ("Error sending outgoing packets"); -#endif - - return -1; - - default: - break; - } - - if (event != NULL) - { - switch (enet_protocol_dispatch_incoming_commands (host, event)) - { - case 1: - return 1; - - case -1: -#ifdef ENET_DEBUG - perror ("Error dispatching incoming packets"); -#endif - - return -1; - - default: - break; - } - } - - if (ENET_TIME_GREATER_EQUAL (host -> serviceTime, timeout)) - return 0; - - do - { - host -> serviceTime = enet_time_get (); - - if (ENET_TIME_GREATER_EQUAL (host -> serviceTime, timeout)) - return 0; - - waitCondition = ENET_SOCKET_WAIT_RECEIVE | ENET_SOCKET_WAIT_INTERRUPT; - - if (enet_socket_wait (host -> socket, & waitCondition, ENET_TIME_DIFFERENCE (timeout, host -> serviceTime)) != 0) - return -1; - } - while (waitCondition & ENET_SOCKET_WAIT_INTERRUPT); - - host -> serviceTime = enet_time_get (); - } while (waitCondition & ENET_SOCKET_WAIT_RECEIVE); - - return 0; -} - diff --git a/modules/enet/register_types.cpp b/modules/enet/register_types.cpp index 630b76ced8..2b4dd35d33 100644 --- a/modules/enet/register_types.cpp +++ b/modules/enet/register_types.cpp @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -40,7 +40,7 @@ void register_enet_types() { enet_ok=true; } - ObjectTypeDB::register_type<NetworkedMultiplayerENet>(); + ClassDB::register_class<NetworkedMultiplayerENet>(); } void unregister_enet_types() { diff --git a/modules/enet/register_types.h b/modules/enet/register_types.h index 50f34dc67f..14cb1ba868 100644 --- a/modules/enet/register_types.h +++ b/modules/enet/register_types.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/modules/enet/unix.c b/modules/enet/unix.c deleted file mode 100644 index 3138cc04b6..0000000000 --- a/modules/enet/unix.c +++ /dev/null @@ -1,616 +0,0 @@ -/** - @file unix.c - @brief ENet Unix system specific functions -*/ -#ifndef _WIN32 - -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/ioctl.h> -#include <sys/time.h> -#include <arpa/inet.h> -#include <netinet/tcp.h> -#include <netdb.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> -#include <time.h> - -#define ENET_BUILDING_LIB 1 -#include "enet/enet.h" - -//@godot: added this since enet takes them fromt he build system -#define HAS_POLL -#define HAS_FCNTL -#define HAS_SOCKLEN_T - - -#ifdef __APPLE__ -#ifdef HAS_POLL -#undef HAS_POLL -#endif -#ifndef HAS_FCNTL -#define HAS_FCNTL 1 -#endif -#ifndef HAS_INET_PTON -#define HAS_INET_PTON 1 -#endif -#ifndef HAS_INET_NTOP -#define HAS_INET_NTOP 1 -#endif -#ifndef HAS_MSGHDR_FLAGS -#define HAS_MSGHDR_FLAGS 1 -#endif -#ifndef HAS_SOCKLEN_T -#define HAS_SOCKLEN_T 1 -#endif -#ifndef HAS_GETADDRINFO -#define HAS_GETADDRINFO 1 -#endif -#ifndef HAS_GETNAMEINFO -#define HAS_GETNAMEINFO 1 -#endif -#endif - -#ifdef HAS_FCNTL -#include <fcntl.h> -#endif - -#ifdef HAS_POLL -#include <sys/poll.h> -#endif - -#ifndef HAS_SOCKLEN_T -typedef int socklen_t; -#endif - -#ifndef MSG_NOSIGNAL -#define MSG_NOSIGNAL 0 -#endif - -static enet_uint32 timeBase = 0; - -int -enet_initialize (void) -{ - return 0; -} - -void -enet_deinitialize (void) -{ -} - -enet_uint32 -enet_host_random_seed (void) -{ - return (enet_uint32) time (NULL); -} - -enet_uint32 -enet_time_get (void) -{ - struct timeval timeVal; - - gettimeofday (& timeVal, NULL); - - return timeVal.tv_sec * 1000 + timeVal.tv_usec / 1000 - timeBase; -} - -void -enet_time_set (enet_uint32 newTimeBase) -{ - struct timeval timeVal; - - gettimeofday (& timeVal, NULL); - - timeBase = timeVal.tv_sec * 1000 + timeVal.tv_usec / 1000 - newTimeBase; -} - -int -enet_address_set_host (ENetAddress * address, const char * name) -{ -#ifdef HAS_GETADDRINFO - struct addrinfo hints, * resultList = NULL, * result = NULL; - - memset (& hints, 0, sizeof (hints)); - hints.ai_family = AF_INET; - - if (getaddrinfo (name, NULL, NULL, & resultList) != 0) - return -1; - - for (result = resultList; result != NULL; result = result -> ai_next) - { - if (result -> ai_family == AF_INET && result -> ai_addr != NULL && result -> ai_addrlen >= sizeof (struct sockaddr_in)) - { - struct sockaddr_in * sin = (struct sockaddr_in *) result -> ai_addr; - - address -> host = sin -> sin_addr.s_addr; - - freeaddrinfo (resultList); - - return 0; - } - } - - if (resultList != NULL) - freeaddrinfo (resultList); -#else - struct hostent * hostEntry = NULL; -#ifdef HAS_GETHOSTBYNAME_R - struct hostent hostData; - char buffer [2048]; - int errnum; - -#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) - gethostbyname_r (name, & hostData, buffer, sizeof (buffer), & hostEntry, & errnum); -#else - hostEntry = gethostbyname_r (name, & hostData, buffer, sizeof (buffer), & errnum); -#endif -#else - hostEntry = gethostbyname (name); -#endif - - if (hostEntry != NULL && hostEntry -> h_addrtype == AF_INET) - { - address -> host = * (enet_uint32 *) hostEntry -> h_addr_list [0]; - - return 0; - } -#endif - -#ifdef HAS_INET_PTON - if (! inet_pton (AF_INET, name, & address -> host)) -#else - if (! inet_aton (name, (struct in_addr *) & address -> host)) -#endif - return -1; - - return 0; -} - -int -enet_address_get_host_ip (const ENetAddress * address, char * name, size_t nameLength) -{ -#ifdef HAS_INET_NTOP - if (inet_ntop (AF_INET, & address -> host, name, nameLength) == NULL) -#else - char * addr = inet_ntoa (* (struct in_addr *) & address -> host); - if (addr != NULL) - { - size_t addrLen = strlen(addr); - if (addrLen >= nameLength) - return -1; - memcpy (name, addr, addrLen + 1); - } - else -#endif - return -1; - return 0; -} - -int -enet_address_get_host (const ENetAddress * address, char * name, size_t nameLength) -{ -#ifdef HAS_GETNAMEINFO - struct sockaddr_in sin; - int err; - - memset (& sin, 0, sizeof (struct sockaddr_in)); - - sin.sin_family = AF_INET; - sin.sin_port = ENET_HOST_TO_NET_16 (address -> port); - sin.sin_addr.s_addr = address -> host; - - err = getnameinfo ((struct sockaddr *) & sin, sizeof (sin), name, nameLength, NULL, 0, NI_NAMEREQD); - if (! err) - { - if (name != NULL && nameLength > 0 && ! memchr (name, '\0', nameLength)) - return -1; - return 0; - } - if (err != EAI_NONAME) - return -1; -#else - struct in_addr in; - struct hostent * hostEntry = NULL; -#ifdef HAS_GETHOSTBYADDR_R - struct hostent hostData; - char buffer [2048]; - int errnum; - - in.s_addr = address -> host; - -#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) - gethostbyaddr_r ((char *) & in, sizeof (struct in_addr), AF_INET, & hostData, buffer, sizeof (buffer), & hostEntry, & errnum); -#else - hostEntry = gethostbyaddr_r ((char *) & in, sizeof (struct in_addr), AF_INET, & hostData, buffer, sizeof (buffer), & errnum); -#endif -#else - in.s_addr = address -> host; - - hostEntry = gethostbyaddr ((char *) & in, sizeof (struct in_addr), AF_INET); -#endif - - if (hostEntry != NULL) - { - size_t hostLen = strlen (hostEntry -> h_name); - if (hostLen >= nameLength) - return -1; - memcpy (name, hostEntry -> h_name, hostLen + 1); - return 0; - } -#endif - - return enet_address_get_host_ip (address, name, nameLength); -} - -int -enet_socket_bind (ENetSocket socket, const ENetAddress * address) -{ - struct sockaddr_in sin; - - memset (& sin, 0, sizeof (struct sockaddr_in)); - - sin.sin_family = AF_INET; - - if (address != NULL) - { - sin.sin_port = ENET_HOST_TO_NET_16 (address -> port); - sin.sin_addr.s_addr = address -> host; - } - else - { - sin.sin_port = 0; - sin.sin_addr.s_addr = INADDR_ANY; - } - - return bind (socket, - (struct sockaddr *) & sin, - sizeof (struct sockaddr_in)); -} - -int -enet_socket_get_address (ENetSocket socket, ENetAddress * address) -{ - struct sockaddr_in sin; - socklen_t sinLength = sizeof (struct sockaddr_in); - - if (getsockname (socket, (struct sockaddr *) & sin, & sinLength) == -1) - return -1; - - address -> host = (enet_uint32) sin.sin_addr.s_addr; - address -> port = ENET_NET_TO_HOST_16 (sin.sin_port); - - return 0; -} - -int -enet_socket_listen (ENetSocket socket, int backlog) -{ - return listen (socket, backlog < 0 ? SOMAXCONN : backlog); -} - -ENetSocket -enet_socket_create (ENetSocketType type) -{ - return socket (PF_INET, type == ENET_SOCKET_TYPE_DATAGRAM ? SOCK_DGRAM : SOCK_STREAM, 0); -} - -int -enet_socket_set_option (ENetSocket socket, ENetSocketOption option, int value) -{ - int result = -1; - switch (option) - { - case ENET_SOCKOPT_NONBLOCK: -#ifdef HAS_FCNTL - result = fcntl (socket, F_SETFL, (value ? O_NONBLOCK : 0) | (fcntl (socket, F_GETFL) & ~O_NONBLOCK)); -#else - result = ioctl (socket, FIONBIO, & value); -#endif - break; - - case ENET_SOCKOPT_BROADCAST: - result = setsockopt (socket, SOL_SOCKET, SO_BROADCAST, (char *) & value, sizeof (int)); - break; - - case ENET_SOCKOPT_REUSEADDR: - result = setsockopt (socket, SOL_SOCKET, SO_REUSEADDR, (char *) & value, sizeof (int)); - break; - - case ENET_SOCKOPT_RCVBUF: - result = setsockopt (socket, SOL_SOCKET, SO_RCVBUF, (char *) & value, sizeof (int)); - break; - - case ENET_SOCKOPT_SNDBUF: - result = setsockopt (socket, SOL_SOCKET, SO_SNDBUF, (char *) & value, sizeof (int)); - break; - - case ENET_SOCKOPT_RCVTIMEO: - { - struct timeval timeVal; - timeVal.tv_sec = value / 1000; - timeVal.tv_usec = (value % 1000) * 1000; - result = setsockopt (socket, SOL_SOCKET, SO_RCVTIMEO, (char *) & timeVal, sizeof (struct timeval)); - break; - } - - case ENET_SOCKOPT_SNDTIMEO: - { - struct timeval timeVal; - timeVal.tv_sec = value / 1000; - timeVal.tv_usec = (value % 1000) * 1000; - result = setsockopt (socket, SOL_SOCKET, SO_SNDTIMEO, (char *) & timeVal, sizeof (struct timeval)); - break; - } - - case ENET_SOCKOPT_NODELAY: - result = setsockopt (socket, IPPROTO_TCP, TCP_NODELAY, (char *) & value, sizeof (int)); - break; - - default: - break; - } - return result == -1 ? -1 : 0; -} - -int -enet_socket_get_option (ENetSocket socket, ENetSocketOption option, int * value) -{ - int result = -1; - socklen_t len; - switch (option) - { - case ENET_SOCKOPT_ERROR: - len = sizeof (int); - result = getsockopt (socket, SOL_SOCKET, SO_ERROR, value, & len); - break; - - default: - break; - } - return result == -1 ? -1 : 0; -} - -int -enet_socket_connect (ENetSocket socket, const ENetAddress * address) -{ - struct sockaddr_in sin; - int result; - - memset (& sin, 0, sizeof (struct sockaddr_in)); - - sin.sin_family = AF_INET; - sin.sin_port = ENET_HOST_TO_NET_16 (address -> port); - sin.sin_addr.s_addr = address -> host; - - result = connect (socket, (struct sockaddr *) & sin, sizeof (struct sockaddr_in)); - if (result == -1 && errno == EINPROGRESS) - return 0; - - return result; -} - -ENetSocket -enet_socket_accept (ENetSocket socket, ENetAddress * address) -{ - int result; - struct sockaddr_in sin; - socklen_t sinLength = sizeof (struct sockaddr_in); - - result = accept (socket, - address != NULL ? (struct sockaddr *) & sin : NULL, - address != NULL ? & sinLength : NULL); - - if (result == -1) - return ENET_SOCKET_NULL; - - if (address != NULL) - { - address -> host = (enet_uint32) sin.sin_addr.s_addr; - address -> port = ENET_NET_TO_HOST_16 (sin.sin_port); - } - - return result; -} - -int -enet_socket_shutdown (ENetSocket socket, ENetSocketShutdown how) -{ - return shutdown (socket, (int) how); -} - -void -enet_socket_destroy (ENetSocket socket) -{ - if (socket != -1) - close (socket); -} - -int -enet_socket_send (ENetSocket socket, - const ENetAddress * address, - const ENetBuffer * buffers, - size_t bufferCount) -{ - struct msghdr msgHdr; - struct sockaddr_in sin; - int sentLength; - - memset (& msgHdr, 0, sizeof (struct msghdr)); - - if (address != NULL) - { - memset (& sin, 0, sizeof (struct sockaddr_in)); - - sin.sin_family = AF_INET; - sin.sin_port = ENET_HOST_TO_NET_16 (address -> port); - sin.sin_addr.s_addr = address -> host; - - msgHdr.msg_name = & sin; - msgHdr.msg_namelen = sizeof (struct sockaddr_in); - } - - msgHdr.msg_iov = (struct iovec *) buffers; - msgHdr.msg_iovlen = bufferCount; - - sentLength = sendmsg (socket, & msgHdr, MSG_NOSIGNAL); - - if (sentLength == -1) - { - if (errno == EWOULDBLOCK) - return 0; - - return -1; - } - - return sentLength; -} - -int -enet_socket_receive (ENetSocket socket, - ENetAddress * address, - ENetBuffer * buffers, - size_t bufferCount) -{ - struct msghdr msgHdr; - struct sockaddr_in sin; - int recvLength; - - memset (& msgHdr, 0, sizeof (struct msghdr)); - - if (address != NULL) - { - msgHdr.msg_name = & sin; - msgHdr.msg_namelen = sizeof (struct sockaddr_in); - } - - msgHdr.msg_iov = (struct iovec *) buffers; - msgHdr.msg_iovlen = bufferCount; - - recvLength = recvmsg (socket, & msgHdr, MSG_NOSIGNAL); - - if (recvLength == -1) - { - if (errno == EWOULDBLOCK) - return 0; - - return -1; - } - -#ifdef HAS_MSGHDR_FLAGS - if (msgHdr.msg_flags & MSG_TRUNC) - return -1; -#endif - - if (address != NULL) - { - address -> host = (enet_uint32) sin.sin_addr.s_addr; - address -> port = ENET_NET_TO_HOST_16 (sin.sin_port); - } - - return recvLength; -} - -int -enet_socketset_select (ENetSocket maxSocket, ENetSocketSet * readSet, ENetSocketSet * writeSet, enet_uint32 timeout) -{ - struct timeval timeVal; - - timeVal.tv_sec = timeout / 1000; - timeVal.tv_usec = (timeout % 1000) * 1000; - - return select (maxSocket + 1, readSet, writeSet, NULL, & timeVal); -} - -int -enet_socket_wait (ENetSocket socket, enet_uint32 * condition, enet_uint32 timeout) -{ -#ifdef HAS_POLL - struct pollfd pollSocket; - int pollCount; - - pollSocket.fd = socket; - pollSocket.events = 0; - - if (* condition & ENET_SOCKET_WAIT_SEND) - pollSocket.events |= POLLOUT; - - if (* condition & ENET_SOCKET_WAIT_RECEIVE) - pollSocket.events |= POLLIN; - - pollCount = poll (& pollSocket, 1, timeout); - - if (pollCount < 0) - { - if (errno == EINTR && * condition & ENET_SOCKET_WAIT_INTERRUPT) - { - * condition = ENET_SOCKET_WAIT_INTERRUPT; - - return 0; - } - - return -1; - } - - * condition = ENET_SOCKET_WAIT_NONE; - - if (pollCount == 0) - return 0; - - if (pollSocket.revents & POLLOUT) - * condition |= ENET_SOCKET_WAIT_SEND; - - if (pollSocket.revents & POLLIN) - * condition |= ENET_SOCKET_WAIT_RECEIVE; - - return 0; -#else - fd_set readSet, writeSet; - struct timeval timeVal; - int selectCount; - - timeVal.tv_sec = timeout / 1000; - timeVal.tv_usec = (timeout % 1000) * 1000; - - FD_ZERO (& readSet); - FD_ZERO (& writeSet); - - if (* condition & ENET_SOCKET_WAIT_SEND) - FD_SET (socket, & writeSet); - - if (* condition & ENET_SOCKET_WAIT_RECEIVE) - FD_SET (socket, & readSet); - - selectCount = select (socket + 1, & readSet, & writeSet, NULL, & timeVal); - - if (selectCount < 0) - { - if (errno == EINTR && * condition & ENET_SOCKET_WAIT_INTERRUPT) - { - * condition = ENET_SOCKET_WAIT_INTERRUPT; - - return 0; - } - - return -1; - } - - * condition = ENET_SOCKET_WAIT_NONE; - - if (selectCount == 0) - return 0; - - if (FD_ISSET (socket, & writeSet)) - * condition |= ENET_SOCKET_WAIT_SEND; - - if (FD_ISSET (socket, & readSet)) - * condition |= ENET_SOCKET_WAIT_RECEIVE; - - return 0; -#endif -} - -#endif - diff --git a/modules/enet/win32.c b/modules/enet/win32.c deleted file mode 100644 index d77fa9a49a..0000000000 --- a/modules/enet/win32.c +++ /dev/null @@ -1,422 +0,0 @@ -/** - @file win32.c - @brief ENet Win32 system specific functions -*/ -#ifdef _WIN32 - -#define ENET_BUILDING_LIB 0 -#include "enet/enet.h" -#include <windows.h> -#include <mmsystem.h> - -static enet_uint32 timeBase = 0; - -int -enet_initialize (void) -{ - WORD versionRequested = MAKEWORD (1, 1); - WSADATA wsaData; - - if (WSAStartup (versionRequested, & wsaData)) - return -1; - - if (LOBYTE (wsaData.wVersion) != 1|| - HIBYTE (wsaData.wVersion) != 1) - { - WSACleanup (); - - return -1; - } - - timeBeginPeriod (1); - - return 0; -} - -void -enet_deinitialize (void) -{ - timeEndPeriod (1); - - WSACleanup (); -} - -enet_uint32 -enet_host_random_seed (void) -{ - return (enet_uint32) timeGetTime (); -} - -enet_uint32 -enet_time_get (void) -{ - return (enet_uint32) timeGetTime () - timeBase; -} - -void -enet_time_set (enet_uint32 newTimeBase) -{ - timeBase = (enet_uint32) timeGetTime () - newTimeBase; -} - -int -enet_address_set_host (ENetAddress * address, const char * name) -{ - struct hostent * hostEntry; - - hostEntry = gethostbyname (name); - if (hostEntry == NULL || - hostEntry -> h_addrtype != AF_INET) - { - unsigned long host = inet_addr (name); - if (host == INADDR_NONE) - return -1; - address -> host = host; - return 0; - } - - address -> host = * (enet_uint32 *) hostEntry -> h_addr_list [0]; - - return 0; -} - -int -enet_address_get_host_ip (const ENetAddress * address, char * name, size_t nameLength) -{ - char * addr = inet_ntoa (* (struct in_addr *) & address -> host); - if (addr == NULL) - return -1; - else - { - size_t addrLen = strlen(addr); - if (addrLen >= nameLength) - return -1; - memcpy (name, addr, addrLen + 1); - } - return 0; -} - -int -enet_address_get_host (const ENetAddress * address, char * name, size_t nameLength) -{ - struct in_addr in; - struct hostent * hostEntry; - - in.s_addr = address -> host; - - hostEntry = gethostbyaddr ((char *) & in, sizeof (struct in_addr), AF_INET); - if (hostEntry == NULL) - return enet_address_get_host_ip (address, name, nameLength); - else - { - size_t hostLen = strlen (hostEntry -> h_name); - if (hostLen >= nameLength) - return -1; - memcpy (name, hostEntry -> h_name, hostLen + 1); - } - - return 0; -} - -int -enet_socket_bind (ENetSocket socket, const ENetAddress * address) -{ - struct sockaddr_in sin; - - memset (& sin, 0, sizeof (struct sockaddr_in)); - - sin.sin_family = AF_INET; - - if (address != NULL) - { - sin.sin_port = ENET_HOST_TO_NET_16 (address -> port); - sin.sin_addr.s_addr = address -> host; - } - else - { - sin.sin_port = 0; - sin.sin_addr.s_addr = INADDR_ANY; - } - - return bind (socket, - (struct sockaddr *) & sin, - sizeof (struct sockaddr_in)) == SOCKET_ERROR ? -1 : 0; -} - -int -enet_socket_get_address (ENetSocket socket, ENetAddress * address) -{ - struct sockaddr_in sin; - int sinLength = sizeof (struct sockaddr_in); - - if (getsockname (socket, (struct sockaddr *) & sin, & sinLength) == -1) - return -1; - - address -> host = (enet_uint32) sin.sin_addr.s_addr; - address -> port = ENET_NET_TO_HOST_16 (sin.sin_port); - - return 0; -} - -int -enet_socket_listen (ENetSocket socket, int backlog) -{ - return listen (socket, backlog < 0 ? SOMAXCONN : backlog) == SOCKET_ERROR ? -1 : 0; -} - -ENetSocket -enet_socket_create (ENetSocketType type) -{ - return socket (PF_INET, type == ENET_SOCKET_TYPE_DATAGRAM ? SOCK_DGRAM : SOCK_STREAM, 0); -} - -int -enet_socket_set_option (ENetSocket socket, ENetSocketOption option, int value) -{ - int result = SOCKET_ERROR; - switch (option) - { - case ENET_SOCKOPT_NONBLOCK: - { - u_long nonBlocking = (u_long) value; - result = ioctlsocket (socket, FIONBIO, & nonBlocking); - break; - } - - case ENET_SOCKOPT_BROADCAST: - result = setsockopt (socket, SOL_SOCKET, SO_BROADCAST, (char *) & value, sizeof (int)); - break; - - case ENET_SOCKOPT_REUSEADDR: - result = setsockopt (socket, SOL_SOCKET, SO_REUSEADDR, (char *) & value, sizeof (int)); - break; - - case ENET_SOCKOPT_RCVBUF: - result = setsockopt (socket, SOL_SOCKET, SO_RCVBUF, (char *) & value, sizeof (int)); - break; - - case ENET_SOCKOPT_SNDBUF: - result = setsockopt (socket, SOL_SOCKET, SO_SNDBUF, (char *) & value, sizeof (int)); - break; - - case ENET_SOCKOPT_RCVTIMEO: - result = setsockopt (socket, SOL_SOCKET, SO_RCVTIMEO, (char *) & value, sizeof (int)); - break; - - case ENET_SOCKOPT_SNDTIMEO: - result = setsockopt (socket, SOL_SOCKET, SO_SNDTIMEO, (char *) & value, sizeof (int)); - break; - - case ENET_SOCKOPT_NODELAY: - result = setsockopt (socket, IPPROTO_TCP, TCP_NODELAY, (char *) & value, sizeof (int)); - break; - - default: - break; - } - return result == SOCKET_ERROR ? -1 : 0; -} - -int -enet_socket_get_option (ENetSocket socket, ENetSocketOption option, int * value) -{ - int result = SOCKET_ERROR, len; - switch (option) - { - case ENET_SOCKOPT_ERROR: - len = sizeof(int); - result = getsockopt (socket, SOL_SOCKET, SO_ERROR, (char *) value, & len); - break; - - default: - break; - } - return result == SOCKET_ERROR ? -1 : 0; -} - -int -enet_socket_connect (ENetSocket socket, const ENetAddress * address) -{ - struct sockaddr_in sin; - int result; - - memset (& sin, 0, sizeof (struct sockaddr_in)); - - sin.sin_family = AF_INET; - sin.sin_port = ENET_HOST_TO_NET_16 (address -> port); - sin.sin_addr.s_addr = address -> host; - - result = connect (socket, (struct sockaddr *) & sin, sizeof (struct sockaddr_in)); - if (result == SOCKET_ERROR && WSAGetLastError () != WSAEWOULDBLOCK) - return -1; - - return 0; -} - -ENetSocket -enet_socket_accept (ENetSocket socket, ENetAddress * address) -{ - SOCKET result; - struct sockaddr_in sin; - int sinLength = sizeof (struct sockaddr_in); - - result = accept (socket, - address != NULL ? (struct sockaddr *) & sin : NULL, - address != NULL ? & sinLength : NULL); - - if (result == INVALID_SOCKET) - return ENET_SOCKET_NULL; - - if (address != NULL) - { - address -> host = (enet_uint32) sin.sin_addr.s_addr; - address -> port = ENET_NET_TO_HOST_16 (sin.sin_port); - } - - return result; -} - -int -enet_socket_shutdown (ENetSocket socket, ENetSocketShutdown how) -{ - return shutdown (socket, (int) how) == SOCKET_ERROR ? -1 : 0; -} - -void -enet_socket_destroy (ENetSocket socket) -{ - if (socket != INVALID_SOCKET) - closesocket (socket); -} - -int -enet_socket_send (ENetSocket socket, - const ENetAddress * address, - const ENetBuffer * buffers, - size_t bufferCount) -{ - struct sockaddr_in sin; - DWORD sentLength; - - if (address != NULL) - { - memset (& sin, 0, sizeof (struct sockaddr_in)); - - sin.sin_family = AF_INET; - sin.sin_port = ENET_HOST_TO_NET_16 (address -> port); - sin.sin_addr.s_addr = address -> host; - } - - if (WSASendTo (socket, - (LPWSABUF) buffers, - (DWORD) bufferCount, - & sentLength, - 0, - address != NULL ? (struct sockaddr *) & sin : NULL, - address != NULL ? sizeof (struct sockaddr_in) : 0, - NULL, - NULL) == SOCKET_ERROR) - { - if (WSAGetLastError () == WSAEWOULDBLOCK) - return 0; - - return -1; - } - - return (int) sentLength; -} - -int -enet_socket_receive (ENetSocket socket, - ENetAddress * address, - ENetBuffer * buffers, - size_t bufferCount) -{ - INT sinLength = sizeof (struct sockaddr_in); - DWORD flags = 0, - recvLength; - struct sockaddr_in sin; - - if (WSARecvFrom (socket, - (LPWSABUF) buffers, - (DWORD) bufferCount, - & recvLength, - & flags, - address != NULL ? (struct sockaddr *) & sin : NULL, - address != NULL ? & sinLength : NULL, - NULL, - NULL) == SOCKET_ERROR) - { - switch (WSAGetLastError ()) - { - case WSAEWOULDBLOCK: - case WSAECONNRESET: - return 0; - } - - return -1; - } - - if (flags & MSG_PARTIAL) - return -1; - - if (address != NULL) - { - address -> host = (enet_uint32) sin.sin_addr.s_addr; - address -> port = ENET_NET_TO_HOST_16 (sin.sin_port); - } - - return (int) recvLength; -} - -int -enet_socketset_select (ENetSocket maxSocket, ENetSocketSet * readSet, ENetSocketSet * writeSet, enet_uint32 timeout) -{ - struct timeval timeVal; - - timeVal.tv_sec = timeout / 1000; - timeVal.tv_usec = (timeout % 1000) * 1000; - - return select (maxSocket + 1, readSet, writeSet, NULL, & timeVal); -} - -int -enet_socket_wait (ENetSocket socket, enet_uint32 * condition, enet_uint32 timeout) -{ - fd_set readSet, writeSet; - struct timeval timeVal; - int selectCount; - - timeVal.tv_sec = timeout / 1000; - timeVal.tv_usec = (timeout % 1000) * 1000; - - FD_ZERO (& readSet); - FD_ZERO (& writeSet); - - if (* condition & ENET_SOCKET_WAIT_SEND) - FD_SET (socket, & writeSet); - - if (* condition & ENET_SOCKET_WAIT_RECEIVE) - FD_SET (socket, & readSet); - - selectCount = select (socket + 1, & readSet, & writeSet, NULL, & timeVal); - - if (selectCount < 0) - return -1; - - * condition = ENET_SOCKET_WAIT_NONE; - - if (selectCount == 0) - return 0; - - if (FD_ISSET (socket, & writeSet)) - * condition |= ENET_SOCKET_WAIT_SEND; - - if (FD_ISSET (socket, & readSet)) - * condition |= ENET_SOCKET_WAIT_RECEIVE; - - return 0; -} - -#endif - diff --git a/modules/etc1/SCsub b/modules/etc1/SCsub new file mode 100644 index 0000000000..0c5dc66d2e --- /dev/null +++ b/modules/etc1/SCsub @@ -0,0 +1,20 @@ +#!/usr/bin/env python + +Import('env') +Import('env_modules') + +env_etc1 = env_modules.Clone() + +# Thirdparty source files +# Not unbundled so far since not widespread as shared library +thirdparty_dir = "#thirdparty/rg-etc1/" +thirdparty_sources = [ + "rg_etc1.cpp", +] +thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] + +env_etc1.add_source_files(env.modules_sources, thirdparty_sources) +env_etc1.Append(CPPPATH=[thirdparty_dir]) + +# Godot source files +env_etc1.add_source_files(env.modules_sources, "*.cpp") diff --git a/modules/etc1/config.py b/modules/etc1/config.py new file mode 100644 index 0000000000..fb920482f5 --- /dev/null +++ b/modules/etc1/config.py @@ -0,0 +1,7 @@ + +def can_build(platform): + return True + + +def configure(env): + pass diff --git a/modules/etc1/image_etc.cpp b/modules/etc1/image_etc.cpp new file mode 100644 index 0000000000..2d883bff0f --- /dev/null +++ b/modules/etc1/image_etc.cpp @@ -0,0 +1,202 @@ +/*************************************************************************/ +/* image_etc.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#include "image_etc.h" +#include "image.h" +#include "rg_etc1.h" +#include "print_string.h" +#include "os/copymem.h" +static void _decompress_etc(Image *p_img) { + + ERR_FAIL_COND(p_img->get_format()!=Image::FORMAT_ETC); + + int imgw = p_img->get_width(); + int imgh = p_img->get_height(); + PoolVector<uint8_t> src=p_img->get_data(); + PoolVector<uint8_t> dst; + + PoolVector<uint8_t>::Read r = src.read(); + + int mmc=p_img->get_mipmap_count(); + + + for(int i=0;i<=mmc;i++) { + + dst.resize(dst.size()+imgw*imgh*3); + const uint8_t *srcbr=&r[p_img->get_mipmap_offset(i)]; + PoolVector<uint8_t>::Write w = dst.write(); + + uint8_t *wptr = &w[dst.size()-imgw*imgh*3]; + + int bw=MAX(imgw/4,1); + int bh=MAX(imgh/4,1); + + for(int y=0;y<bh;y++) { + + for(int x=0;x<bw;x++) { + + uint8_t block[4*4*4]; + + + rg_etc1::unpack_etc1_block(srcbr,(unsigned int*)block); + srcbr+=8; + + int maxx=MIN(imgw,4); + int maxy=MIN(imgh,4); + + for(int yy=0;yy<maxy;yy++) { + + for(int xx=0;xx<maxx;xx++) { + + uint32_t src_ofs = (yy*4+xx)*4; + uint32_t dst_ofs = ((y*4+yy)*imgw+x*4+xx)*3; + wptr[dst_ofs+0]=block[src_ofs+0]; + wptr[dst_ofs+1]=block[src_ofs+1]; + wptr[dst_ofs+2]=block[src_ofs+2]; + + } + } + + } + + } + + imgw=MAX(1,imgw/2); + imgh=MAX(1,imgh/2); + } + + + r=PoolVector<uint8_t>::Read(); + //print_line("Re Creating ETC into regular image: w "+itos(p_img->get_width())+" h "+itos(p_img->get_height())+" mm "+itos(p_img->get_mipmaps())); + *p_img=Image(p_img->get_width(),p_img->get_height(),p_img->has_mipmaps(),Image::FORMAT_RGB8,dst); + if (p_img->has_mipmaps()) + p_img->generate_mipmaps(); + + +} + +static void _compress_etc(Image *p_img) { + + Image img = *p_img; + + int imgw=img.get_width(),imgh=img.get_height(); + + ERR_FAIL_COND( nearest_power_of_2(imgw)!=imgw || nearest_power_of_2(imgh)!=imgh ); + + if (img.get_format()!=Image::FORMAT_RGB8) + img.convert(Image::FORMAT_RGB8); + + + PoolVector<uint8_t> res_data; + PoolVector<uint8_t> dst_data; + PoolVector<uint8_t>::Read r = img.get_data().read(); + + int target_size = Image::get_image_data_size(p_img->get_width(),p_img->get_height(),Image::FORMAT_ETC,p_img->has_mipmaps()?-1:0); + int mmc = p_img->has_mipmaps() ? Image::get_image_required_mipmaps(p_img->get_width(),p_img->get_height(),Image::FORMAT_ETC) : 0; + + dst_data.resize(target_size); + int mc=0; + int ofs=0; + PoolVector<uint8_t>::Write w=dst_data.write(); + + + rg_etc1::etc1_pack_params pp; + pp.m_quality=rg_etc1::cLowQuality; + for(int i=0;i<=mmc;i++) { + + + int bw=MAX(imgw/4,1); + int bh=MAX(imgh/4,1); + const uint8_t *src = &r[img.get_mipmap_offset(i)]; + int mmsize = MAX(bw,1)*MAX(bh,1)*8; + + uint8_t *dst = &w[ofs]; + ofs+=mmsize; + + + //print_line("bh: "+itos(bh)+" bw: "+itos(bw)); + + for(int y=0;y<bh;y++) { + + for(int x=0;x<bw;x++) { + + //print_line("x: "+itos(x)+" y: "+itos(y)); + + uint8_t block[4*4*4]; + zeromem(block,4*4*4); + uint8_t cblock[8]; + + int maxy = MIN(imgh,4); + int maxx = MIN(imgw,4); + + + for(int yy=0;yy<maxy;yy++) { + + for(int xx=0;xx<maxx;xx++) { + + + uint32_t dst_ofs = (yy*4+xx)*4; + uint32_t src_ofs = ((y*4+yy)*imgw+x*4+xx)*3; + block[dst_ofs+0]=src[src_ofs+0]; + block[dst_ofs+1]=src[src_ofs+1]; + block[dst_ofs+2]=src[src_ofs+2]; + block[dst_ofs+3]=255; + + } + } + + rg_etc1::pack_etc1_block(cblock, (const unsigned int*)block, pp); + for(int j=0;j<8;j++) { + + dst[j]=cblock[j]; + } + + dst+=8; + } + + } + + imgw=MAX(1,imgw/2); + imgh=MAX(1,imgh/2); + mc++; + + } + + *p_img=Image(p_img->get_width(),p_img->get_height(),(mc-1)?true:false,Image::FORMAT_ETC,dst_data); + + +} + +void _register_etc1_compress_func() { + + rg_etc1::pack_etc1_block_init(); + Image::_image_compress_etc_func=_compress_etc; + Image::_image_decompress_etc=_decompress_etc; + + +} diff --git a/modules/etc1/image_etc.h b/modules/etc1/image_etc.h new file mode 100644 index 0000000000..6ab10126f8 --- /dev/null +++ b/modules/etc1/image_etc.h @@ -0,0 +1,35 @@ +/*************************************************************************/ +/* image_etc.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#ifndef IMAGE_ETC1_H +#define IMAGE_ETC1_H + + +void _register_etc1_compress_func(); + +#endif // IMAGE_ETC_H diff --git a/modules/etc1/register_types.cpp b/modules/etc1/register_types.cpp new file mode 100644 index 0000000000..d02ef83478 --- /dev/null +++ b/modules/etc1/register_types.cpp @@ -0,0 +1,47 @@ +/*************************************************************************/ +/* register_types.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#include "register_types.h" + +#include "image_etc.h" +#include "texture_loader_pkm.h" + +static ResourceFormatPKM *resource_loader_pkm = NULL; + +void register_etc1_types() { + + resource_loader_pkm = memnew( ResourceFormatPKM ); + ResourceLoader::add_resource_format_loader(resource_loader_pkm); + + _register_etc1_compress_func(); +} + +void unregister_etc1_types() { + + memdelete(resource_loader_pkm); +} diff --git a/modules/etc1/register_types.h b/modules/etc1/register_types.h new file mode 100644 index 0000000000..fe92496cea --- /dev/null +++ b/modules/etc1/register_types.h @@ -0,0 +1,30 @@ +/*************************************************************************/ +/* register_types.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +void register_etc1_types(); +void unregister_etc1_types(); diff --git a/modules/etc1/texture_loader_pkm.cpp b/modules/etc1/texture_loader_pkm.cpp new file mode 100644 index 0000000000..e720e1fb4c --- /dev/null +++ b/modules/etc1/texture_loader_pkm.cpp @@ -0,0 +1,84 @@ +#include "texture_loader_pkm.h" +#include "os/file_access.h" +#include <string.h> + +struct ETC1Header { + char tag[6]; // "PKM 10" + uint16_t format; // Format == number of mips (== zero) + uint16_t texWidth; // Texture dimensions, multiple of 4 (big-endian) + uint16_t texHeight; + uint16_t origWidth; // Original dimensions (big-endian) + uint16_t origHeight; +}; + +RES ResourceFormatPKM::load(const String &p_path, const String& p_original_path, Error *r_error) { + + if (r_error) + *r_error=ERR_CANT_OPEN; + + Error err; + FileAccess *f = FileAccess::open(p_path,FileAccess::READ,&err); + if (!f) + return RES(); + + FileAccessRef fref(f); + if (r_error) + *r_error=ERR_FILE_CORRUPT; + + ERR_EXPLAIN("Unable to open PKM texture file: "+p_path); + ERR_FAIL_COND_V(err!=OK,RES()); + + // big endian + f->set_endian_swap(true); + + ETC1Header h; + ERR_EXPLAIN("Invalid or Unsupported PKM texture file: "+p_path); + f->get_buffer((uint8_t *) &h.tag, sizeof(h.tag)); + if(strncmp(h.tag, "PKM 10", sizeof(h.tag))) + ERR_FAIL_V(RES()); + + h.format = f->get_16(); + h.texWidth = f->get_16(); + h.texHeight = f->get_16(); + h.origWidth = f->get_16(); + h.origHeight = f->get_16(); + + PoolVector<uint8_t> src_data; + + uint32_t size = h.texWidth * h.texHeight / 2; + src_data.resize(size); + PoolVector<uint8_t>::Write wb = src_data.write(); + f->get_buffer(wb.ptr(),size); + wb=PoolVector<uint8_t>::Write(); + + int mipmaps = h.format; + int width = h.origWidth; + int height = h.origHeight; + + Image img(width,height,mipmaps,Image::FORMAT_ETC,src_data); + + Ref<ImageTexture> texture = memnew( ImageTexture ); + texture->create_from_image(img); + + if (r_error) + *r_error=OK; + + return texture; +} + +void ResourceFormatPKM::get_recognized_extensions(List<String> *p_extensions) const { + + p_extensions->push_back("pkm"); +} + +bool ResourceFormatPKM::handles_type(const String& p_type) const { + + return ClassDB::is_parent_class(p_type,"Texture"); +} + +String ResourceFormatPKM::get_resource_type(const String &p_path) const { + + if (p_path.get_extension().to_lower()=="pkm") + return "ImageTexture"; + return ""; +} diff --git a/modules/etc1/texture_loader_pkm.h b/modules/etc1/texture_loader_pkm.h new file mode 100644 index 0000000000..5788716d9f --- /dev/null +++ b/modules/etc1/texture_loader_pkm.h @@ -0,0 +1,18 @@ +#ifndef TEXTURE_LOADER_PKM_H +#define TEXTURE_LOADER_PKM_H + +#include "scene/resources/texture.h" +#include "io/resource_loader.h" + +class ResourceFormatPKM : public ResourceFormatLoader{ +public: + + virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL); + virtual void get_recognized_extensions(List<String> *p_extensions) const; + virtual bool handles_type(const String& p_type) const; + virtual String get_resource_type(const String &p_path) const; + + virtual ~ResourceFormatPKM() {} +}; + +#endif // TEXTURE_LOADER_PKM_H diff --git a/modules/freetype/SCsub b/modules/freetype/SCsub new file mode 100644 index 0000000000..e4dd1c36a0 --- /dev/null +++ b/modules/freetype/SCsub @@ -0,0 +1,90 @@ +#!/usr/bin/env python + +Import('env') + +# Not building in a separate env as core needs it + +# Thirdparty source files +if (env['builtin_freetype'] != 'no'): + thirdparty_dir = "#thirdparty/freetype/" + thirdparty_sources = [ + "src/autofit/autofit.c", + "src/base/ftapi.c", + "src/base/ftbase.c", + "src/base/ftbbox.c", + "src/base/ftbdf.c", + "src/base/ftbitmap.c", + "src/base/ftcid.c", + "src/base/ftdebug.c", + "src/base/ftfntfmt.c", + "src/base/ftfstype.c", + "src/base/ftgasp.c", + "src/base/ftglyph.c", + "src/base/ftgxval.c", + "src/base/ftinit.c", + "src/base/ftlcdfil.c", + "src/base/ftmm.c", + "src/base/ftotval.c", + "src/base/ftpatent.c", + "src/base/ftpfr.c", + "src/base/ftpic.c", + "src/base/ftstroke.c", + "src/base/ftsynth.c", + "src/base/ftsystem.c", + "src/base/fttype1.c", + "src/base/ftwinfnt.c", + "src/bdf/bdf.c", + "src/cache/ftcache.c", + "src/cff/cff.c", + "src/cid/type1cid.c", + "src/gxvalid/gxvalid.c", + "src/otvalid/otvalid.c", + "src/pcf/pcf.c", + "src/pfr/pfr.c", + "src/psaux/psaux.c", + "src/pshinter/pshinter.c", + "src/psnames/psnames.c", + "src/raster/raster.c", + "src/sfnt/sfnt.c", + "src/smooth/smooth.c", + "src/truetype/truetype.c", + "src/type1/type1.c", + "src/type42/type42.c", + "src/winfonts/winfnt.c", + ] + thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] + + # Include header for UWP to fix build issues + if "platform" in env and env["platform"] == "uwp": + env.Append(CCFLAGS=['/FI', '"modules/freetype/uwpdef.h"']) + + env.Append(CPPPATH=[thirdparty_dir, thirdparty_dir + "/include"]) + + # also requires libpng headers + if (env['builtin_libpng'] != 'no'): + env.Append(CPPPATH=["#thirdparty/libpng"]) + + """ FIXME: Remove this commented code if Windows can handle the monolithic lib + # fix for Windows' shell miserably failing on long lines, split in two libraries + half1 = [] + half2 = [] + for x in thirdparty_sources: + if (x.find("src/base") != -1 and x.find("src/sfnt") != -1): + half1.append(x) + else: + half2.append(x) + + lib = env.Library("freetype_builtin1", half2) + env.Append(LIBS = [lib]) + lib = env.Library("freetype_builtin2", half1) + env.Append(LIBS = [lib]) + """ + + lib = env.Library("freetype_builtin", thirdparty_sources) + env.Append(LIBS=[lib]) + +# Godot source files +env.add_source_files(env.modules_sources, "*.cpp") +env.Append(CCFLAGS=['-DFREETYPE_ENABLED']) + +Export('env') diff --git a/modules/freetype/config.py b/modules/freetype/config.py new file mode 100644 index 0000000000..fb920482f5 --- /dev/null +++ b/modules/freetype/config.py @@ -0,0 +1,7 @@ + +def can_build(platform): + return True + + +def configure(env): + pass diff --git a/modules/freetype/register_types.cpp b/modules/freetype/register_types.cpp new file mode 100644 index 0000000000..2579a925d4 --- /dev/null +++ b/modules/freetype/register_types.cpp @@ -0,0 +1,33 @@ +/*************************************************************************/ +/* register_types.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#include "register_types.h" + +void register_freetype_types() {} + +void unregister_freetype_types() {} diff --git a/modules/freetype/register_types.h b/modules/freetype/register_types.h new file mode 100644 index 0000000000..2837898123 --- /dev/null +++ b/modules/freetype/register_types.h @@ -0,0 +1,30 @@ +/*************************************************************************/ +/* register_types.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +void register_freetype_types(); +void unregister_freetype_types(); diff --git a/modules/freetype/uwpdef.h b/modules/freetype/uwpdef.h new file mode 100644 index 0000000000..b4aabb1929 --- /dev/null +++ b/modules/freetype/uwpdef.h @@ -0,0 +1,32 @@ +/*************************************************************************/ +/* uwpdef.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +// "generic" is a reserved keyword in C++/CX code +// this avoids the errors in the variable name from Freetype code +#define generic freetype_generic diff --git a/modules/gdscript/SCsub b/modules/gdscript/SCsub index 403fe68f66..0882406761 100644 --- a/modules/gdscript/SCsub +++ b/modules/gdscript/SCsub @@ -1,5 +1,7 @@ +#!/usr/bin/env python + Import('env') -env.add_source_files(env.modules_sources,"*.cpp") +env.add_source_files(env.modules_sources, "*.cpp") Export('env') diff --git a/modules/gdscript/config.py b/modules/gdscript/config.py index ea7e83378a..5698a37295 100644 --- a/modules/gdscript/config.py +++ b/modules/gdscript/config.py @@ -1,11 +1,8 @@ def can_build(platform): - return True + return True def configure(env): - pass - - - + pass diff --git a/modules/gdscript/gd_compiler.cpp b/modules/gdscript/gd_compiler.cpp index ce8b6a6ea4..398c2cf82a 100644 --- a/modules/gdscript/gd_compiler.cpp +++ b/modules/gdscript/gd_compiler.cpp @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -29,6 +29,31 @@ #include "gd_compiler.h" #include "gd_script.h" +bool GDCompiler::_is_class_member_property(CodeGen & codegen, const StringName & p_name) { + + if (!codegen.function_node || codegen.function_node->_static) + return false; + + return _is_class_member_property(codegen.script,p_name); +} + +bool GDCompiler::_is_class_member_property(GDScript *owner, const StringName & p_name) { + + + GDScript *scr = owner; + GDNativeClass *nc=NULL; + while(scr) { + + if (scr->native.is_valid()) + nc=scr->native.ptr(); + scr=scr->_base; + } + + ERR_FAIL_COND_V(!nc,false); + + return ClassDB::has_property(nc->get_name(),p_name); +} + void GDCompiler::_set_error(const String& p_error,const GDParser::Node *p_node) { @@ -164,6 +189,17 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre StringName identifier = in->name; + + if (_is_class_member_property(codegen,identifier)) { + //get property + codegen.opcodes.push_back(GDFunction::OPCODE_GET_MEMBER); // perform operator + codegen.opcodes.push_back(codegen.get_name_map_pos(identifier)); // argument 2 (unary only takes one parameter) + int dst_addr=(p_stack_level)|(GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS); + codegen.opcodes.push_back(dst_addr); // append the stack level as destination address of the opcode + codegen.alloc_stack(p_stack_level); + return dst_addr; + } + // TRY STACK! if (!p_initializer && codegen.stack_identifiers.has(identifier)) { @@ -208,7 +244,7 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre if (nc) { bool success=false; - int constant = ObjectTypeDB::get_integer_constant(nc->get_name(),identifier,&success); + int constant = ClassDB::get_integer_constant(nc->get_name(),identifier,&success); if (success) { Variant key=constant; int idx; @@ -662,6 +698,46 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre return p_stack_level|GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS; } break; + // ternary operators + case GDParser::OperatorNode::OP_TERNARY_IF: { + + // x IF a ELSE y operator with early out on failure + + int res = _parse_expression(codegen,on->arguments[0],p_stack_level); + if (res<0) + return res; + codegen.opcodes.push_back(GDFunction::OPCODE_JUMP_IF_NOT); + codegen.opcodes.push_back(res); + int jump_fail_pos=codegen.opcodes.size(); + codegen.opcodes.push_back(0); + + + res = _parse_expression(codegen,on->arguments[1],p_stack_level); + if (res<0) + return res; + + codegen.alloc_stack(p_stack_level); //it will be used.. + codegen.opcodes.push_back(GDFunction::OPCODE_ASSIGN); + codegen.opcodes.push_back(p_stack_level|GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS); + codegen.opcodes.push_back(res); + codegen.opcodes.push_back(GDFunction::OPCODE_JUMP); + int jump_past_pos=codegen.opcodes.size(); + codegen.opcodes.push_back(0); + + codegen.opcodes[jump_fail_pos]=codegen.opcodes.size(); + res = _parse_expression(codegen,on->arguments[2],p_stack_level); + if (res<0) + return res; + + codegen.opcodes.push_back(GDFunction::OPCODE_ASSIGN); + codegen.opcodes.push_back(p_stack_level|GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS); + codegen.opcodes.push_back(res); + + codegen.opcodes[jump_past_pos]=codegen.opcodes.size(); + + return p_stack_level|GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS; + + } break; //unary operators case GDParser::OperatorNode::OP_NEG: { if (!_create_unary_operator(codegen,on,Variant::OP_NEGATE,p_stack_level)) return -1;} break; case GDParser::OperatorNode::OP_NOT: { if (!_create_unary_operator(codegen,on,Variant::OP_NOT,p_stack_level)) return -1;} break; @@ -736,6 +812,8 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre /* Find chain of sets */ + StringName assign_property; + List<GDParser::OperatorNode*> chain; { @@ -744,8 +822,20 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre while(true) { chain.push_back(n); - if (n->arguments[0]->type!=GDParser::Node::TYPE_OPERATOR) + if (n->arguments[0]->type!=GDParser::Node::TYPE_OPERATOR) { + + //check for a built-in property + if (n->arguments[0]->type==GDParser::Node::TYPE_IDENTIFIER) { + + GDParser::IdentifierNode *identifier = static_cast<GDParser::IdentifierNode*>(n->arguments[0]); + if (_is_class_member_property(codegen,identifier->name)) { + assign_property = identifier->name; + + } + + } break; + } n = static_cast<GDParser::OperatorNode*>(n->arguments[0]); if (n->op!=GDParser::OperatorNode::OP_INDEX && n->op!=GDParser::OperatorNode::OP_INDEX_NAMED) break; @@ -770,6 +860,17 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre Vector<int> setchain; + + if (assign_property!=StringName()) { + + // recover and assign at the end, this allows stuff like + // position.x+=2.0 + // in Node2D + setchain.push_back(prev_pos); + setchain.push_back(codegen.get_name_map_pos(assign_property)); + setchain.push_back(GDFunction::OPCODE_SET_MEMBER); + } + for(List<GDParser::OperatorNode*>::Element *E=chain.back();E;E=E->prev()) { @@ -800,7 +901,7 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre } - if (key_idx<0) + if (key_idx<0) //error return key_idx; codegen.opcodes.push_back(named ? GDFunction::OPCODE_GET_NAMED : GDFunction::OPCODE_GET); @@ -812,7 +913,10 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre codegen.opcodes.push_back(dst_pos); + //add in reverse order, since it will be reverted + + setchain.push_back(dst_pos); setchain.push_back(key_idx); setchain.push_back(prev_pos); @@ -841,7 +945,7 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre } - if (set_index<0) + if (set_index<0) //error return set_index; if (set_index&GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS) { @@ -851,7 +955,7 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre int set_value = _parse_assign_right_expression(codegen,on,slevel+1); - if (set_value<0) + if (set_value<0) //error return set_value; codegen.opcodes.push_back(named?GDFunction::OPCODE_SET_NAMED:GDFunction::OPCODE_SET); @@ -859,20 +963,36 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre codegen.opcodes.push_back(set_index); codegen.opcodes.push_back(set_value); - for(int i=0;i<setchain.size();i+=4) { + for(int i=0;i<setchain.size();i++) { - codegen.opcodes.push_back(setchain[i+0]); - codegen.opcodes.push_back(setchain[i+1]); - codegen.opcodes.push_back(setchain[i+2]); - codegen.opcodes.push_back(setchain[i+3]); + codegen.opcodes.push_back(setchain[i]); } return retval; + } else if (on->arguments[0]->type==GDParser::Node::TYPE_IDENTIFIER && _is_class_member_property(codegen,static_cast<GDParser::IdentifierNode*>(on->arguments[0])->name)) { + //assignment to member property + + int slevel = p_stack_level; + + int src_address = _parse_assign_right_expression(codegen,on,slevel); + if (src_address<0) + return -1; + + StringName name = static_cast<GDParser::IdentifierNode*>(on->arguments[0])->name; + + codegen.opcodes.push_back(GDFunction::OPCODE_SET_MEMBER); + codegen.opcodes.push_back(codegen.get_name_map_pos(name)); + codegen.opcodes.push_back(src_address); + + return GDFunction::ADDR_TYPE_NIL<<GDFunction::ADDR_BITS; } else { - //ASSIGNMENT MODE!! + + + + //REGULAR ASSIGNMENT MODE!! int slevel = p_stack_level; @@ -965,12 +1085,12 @@ Error GDCompiler::_parse_block(CodeGen& codegen,const GDParser::BlockNode *p_blo switch(s->type) { case GDParser::Node::TYPE_NEWLINE: { - +#ifdef DEBUG_ENABLED const GDParser::NewLineNode *nl = static_cast<const GDParser::NewLineNode*>(s); codegen.opcodes.push_back(GDFunction::OPCODE_LINE); codegen.opcodes.push_back(nl->line); codegen.current_line=nl->line; - +#endif } break; case GDParser::Node::TYPE_CONTROL_FLOW: { // try subblocks @@ -979,7 +1099,72 @@ Error GDCompiler::_parse_block(CodeGen& codegen,const GDParser::BlockNode *p_blo switch(cf->cf_type) { - + case GDParser::ControlFlowNode::CF_MATCH: { + GDParser::MatchNode *match = cf->match; + + GDParser::IdentifierNode *id = memnew(GDParser::IdentifierNode); + id->name = "#match_value"; + + // var #match_value + // copied because there is no _parse_statement :( + codegen.add_stack_identifier(id->name, p_stack_level++); + codegen.alloc_stack(p_stack_level); + new_identifiers++; + + GDParser::OperatorNode *op = memnew(GDParser::OperatorNode); + op->op=GDParser::OperatorNode::OP_ASSIGN; + op->arguments.push_back(id); + op->arguments.push_back(match->val_to_match); + + int ret = _parse_expression(codegen, op, p_stack_level); + if (ret < 0) { + return ERR_PARSE_ERROR; + } + + // break address + codegen.opcodes.push_back(GDFunction::OPCODE_JUMP); + codegen.opcodes.push_back(codegen.opcodes.size() + 3); + int break_addr = codegen.opcodes.size(); + codegen.opcodes.push_back(GDFunction::OPCODE_JUMP); + codegen.opcodes.push_back(0); // break addr + + for (int j = 0; j < match->compiled_pattern_branches.size(); j++) { + GDParser::MatchNode::CompiledPatternBranch branch = match->compiled_pattern_branches[j]; + + // jump over continue + // jump unconditionally + // continue address + // compile the condition + int ret = _parse_expression(codegen, branch.compiled_pattern, p_stack_level); + if (ret < 0) { + return ERR_PARSE_ERROR; + } + + codegen.opcodes.push_back(GDFunction::OPCODE_JUMP_IF); + codegen.opcodes.push_back(ret); + codegen.opcodes.push_back(codegen.opcodes.size() + 3); + int continue_addr = codegen.opcodes.size(); + codegen.opcodes.push_back(GDFunction::OPCODE_JUMP); + codegen.opcodes.push_back(0); + + + + Error err = _parse_block(codegen, branch.body, p_stack_level, p_break_addr, continue_addr); + if (err) { + return ERR_PARSE_ERROR; + } + + codegen.opcodes.push_back(GDFunction::OPCODE_JUMP); + codegen.opcodes.push_back(break_addr); + + codegen.opcodes[continue_addr + 1] = codegen.opcodes.size(); + } + + codegen.opcodes[break_addr + 1] = codegen.opcodes.size(); + + + } break; + case GDParser::ControlFlowNode::CF_IF: { #ifdef DEBUG_ENABLED @@ -1161,14 +1346,21 @@ Error GDCompiler::_parse_block(CodeGen& codegen,const GDParser::BlockNode *p_blo codegen.opcodes.push_back(ret); } break; case GDParser::Node::TYPE_BREAKPOINT: { +#ifdef DEBUG_ENABLED // try subblocks codegen.opcodes.push_back(GDFunction::OPCODE_BREAKPOINT); +#endif } break; case GDParser::Node::TYPE_LOCAL_VAR: { const GDParser::LocalVarNode *lv = static_cast<const GDParser::LocalVarNode*>(s); + if (_is_class_member_property(codegen,lv->name)) { + _set_error("Name for local variable '"+String(lv->name)+"' can't shadow class property of the same name.",lv); + return ERR_ALREADY_EXISTS; + } + codegen.add_stack_identifier(lv->name,p_stack_level++); codegen.alloc_stack(p_stack_level); new_identifiers++; @@ -1207,6 +1399,10 @@ Error GDCompiler::_parse_function(GDScript *p_script,const GDParser::ClassNode * if (p_func) { for(int i=0;i<p_func->arguments.size();i++) { + if (_is_class_member_property(p_script,p_func->arguments[i])) { + _set_error("Name for argument '"+String(p_func->arguments[i])+"' can't shadow class property of the same name.",p_func); + return ERR_ALREADY_EXISTS; + } codegen.add_stack_identifier(p_func->arguments[i],i); #ifdef TOOLS_ENABLED argnames.push_back(p_func->arguments[i]); @@ -1289,9 +1485,10 @@ Error GDCompiler::_parse_function(GDScript *p_script,const GDParser::ClassNode * GDFunction *gdfunc=NULL; - //if (String(p_func->name)=="") { //initializer func - // gdfunc = &p_script->initializer; - + /* + if (String(p_func->name)=="") { //initializer func + gdfunc = &p_script->initializer; + */ //} else { //regular func p_script->member_functions[func_name]=memnew(GDFunction); gdfunc = p_script->member_functions[func_name]; @@ -1379,7 +1576,7 @@ Error GDCompiler::_parse_function(GDScript *p_script,const GDParser::ClassNode * //funciton and class if (p_class->name) { - signature+="::"+String(p_class->name)+"."+String(func_name);; + signature+="::"+String(p_class->name)+"."+String(func_name); } else { signature+="::"+String(func_name); } @@ -1403,6 +1600,10 @@ Error GDCompiler::_parse_function(GDScript *p_script,const GDParser::ClassNode * #endif if (p_func) { gdfunc->_initial_line=p_func->line; +#ifdef TOOLS_ENABLED + + p_script->member_lines[func_name]=p_func->line; +#endif } else { gdfunc->_initial_line=0; } @@ -1594,9 +1795,14 @@ Error GDCompiler::_parse_class(GDScript *p_script, GDScript *p_owner, const GDPa } + }else { + // without extends, implicitly extend Reference + int native_idx = GDScriptLanguage::get_singleton()->get_global_map()["Reference"]; + native = GDScriptLanguage::get_singleton()->get_global_array()[native_idx]; + ERR_FAIL_COND_V(native.is_null(), ERR_BUG); + p_script->native=native; } - //print_line("Script: "+p_script->get_path()+" indices: "+itos(p_script->member_indices.size())); @@ -1607,6 +1813,10 @@ Error GDCompiler::_parse_class(GDScript *p_script, GDScript *p_owner, const GDPa _set_error("Member '"+name+"' already exists (in current or parent class)",p_class); return ERR_ALREADY_EXISTS; } + if (_is_class_member_property(p_script,name)) { + _set_error("Member '"+name+"' already exists as a class property.",p_class); + return ERR_ALREADY_EXISTS; + } if (p_class->variables[i]._export.type!=Variant::NIL) { @@ -1632,6 +1842,12 @@ Error GDCompiler::_parse_class(GDScript *p_script, GDScript *p_owner, const GDPa p_script->member_indices[name]=minfo; p_script->members.insert(name); +#ifdef TOOLS_ENABLED + + p_script->member_lines[name]=p_class->variables[i].line; +#endif + + } for(int i=0;i<p_class->constant_expressions.size();i++) { @@ -1639,10 +1855,20 @@ Error GDCompiler::_parse_class(GDScript *p_script, GDScript *p_owner, const GDPa StringName name = p_class->constant_expressions[i].identifier; ERR_CONTINUE( p_class->constant_expressions[i].expression->type!=GDParser::Node::TYPE_CONSTANT ); + if (_is_class_member_property(p_script,name)) { + _set_error("Member '"+name+"' already exists as a class property.",p_class); + return ERR_ALREADY_EXISTS; + } + GDParser::ConstantNode *constant = static_cast<GDParser::ConstantNode*>(p_class->constant_expressions[i].expression); p_script->constants.insert(name,constant->value); //p_script->constants[constant->value].make_const(); +#ifdef TOOLS_ENABLED + + p_script->member_lines[name]=p_class->constant_expressions[i].expression->line; +#endif + } for(int i=0;i<p_class->_signals.size();i++) { @@ -1666,7 +1892,7 @@ Error GDCompiler::_parse_class(GDScript *p_script, GDScript *p_owner, const GDPa } if (native.is_valid()) { - if (ObjectTypeDB::has_signal(native->get_name(),name)) { + if (ClassDB::has_signal(native->get_name(),name)) { _set_error("Signal '"+name+"' redefined (original in native class '"+String(native->get_name())+"')",p_class); return ERR_ALREADY_EXISTS; } @@ -1691,6 +1917,10 @@ Error GDCompiler::_parse_class(GDScript *p_script, GDScript *p_owner, const GDPa if (err) return err; +#ifdef TOOLS_ENABLED + + p_script->member_lines[name]=p_class->subclasses[i]->line; +#endif p_script->constants.insert(name,subclass); //once parsed, goes to the list of constants p_script->subclasses.insert(name,subclass); diff --git a/modules/gdscript/gd_compiler.h b/modules/gdscript/gd_compiler.h index 7cf575e3d6..eb6079e8e0 100644 --- a/modules/gdscript/gd_compiler.h +++ b/modules/gdscript/gd_compiler.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -37,6 +37,7 @@ class GDCompiler { const GDParser *parser; struct CodeGen { + GDScript *script; const GDParser::ClassNode *class_node; const GDParser::FunctionNode *function_node; @@ -92,7 +93,7 @@ class GDCompiler { //int get_identifier_pos(const StringName& p_dentifier) const; - HashMap<Variant,int,VariantHasher> constant_map; + HashMap<Variant,int,VariantHasher,VariantComparator> constant_map; Map<StringName,int> name_map; int get_name_map_pos(const StringName& p_identifier) { @@ -134,6 +135,9 @@ class GDCompiler { Ref<GDScript> _parse_class(GDParser::ClassNode *p_class); #endif + bool _is_class_member_property(CodeGen & codegen, const StringName & p_name); + bool _is_class_member_property(GDScript *owner, const StringName & p_name); + void _set_error(const String& p_error,const GDParser::Node *p_node); bool _create_unary_operator(CodeGen& codegen,const GDParser::OperatorNode *on,Variant::Operator op, int p_stack_level); diff --git a/modules/gdscript/gd_editor.cpp b/modules/gdscript/gd_editor.cpp index 2a80531ec5..352016b2d2 100644 --- a/modules/gdscript/gd_editor.cpp +++ b/modules/gdscript/gd_editor.cpp @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,7 +28,7 @@ /*************************************************************************/ #include "gd_script.h" #include "gd_compiler.h" -#include "globals.h" +#include "global_config.h" #include "os/file_access.h" void GDScriptLanguage::get_comment_delimiters(List<String> *p_delimiters) const { @@ -325,7 +325,7 @@ void GDScriptLanguage::get_public_constants(List<Pair<String,Variant> > *p_const p_constants->push_back(pi); } -String GDScriptLanguage::make_function(const String& p_class,const String& p_name,const StringArray& p_args) const { +String GDScriptLanguage::make_function(const String& p_class,const String& p_name,const PoolStringArray& p_args) const { String s="func "+p_name+"("; if (p_args.size()) { @@ -351,6 +351,7 @@ struct GDCompletionIdentifier { Ref<GDScript> script; Variant::Type type; Variant value; //im case there is a value, also return it + }; @@ -363,11 +364,13 @@ static GDCompletionIdentifier _get_type_from_variant(const Variant& p_variant) { if (p_variant.get_type()==Variant::OBJECT) { Object *obj = p_variant; if (obj) { - //if (obj->cast_to<GDNativeClass>()) { - // t.obj_type=obj->cast_to<GDNativeClass>()->get_name(); - // t.value=Variant(); - //} else { - t.obj_type=obj->get_type(); + /* + if (obj->cast_to<GDNativeClass>()) { + t.obj_type=obj->cast_to<GDNativeClass>()->get_name(); + t.value=Variant(); + } else { + */ + t.obj_type=obj->get_class(); //} } } @@ -613,10 +616,10 @@ static bool _guess_expression_type(GDCompletionContext& context,const GDParser:: } } - if (ObjectTypeDB::has_method(base.obj_type,id)) { + if (ClassDB::has_method(base.obj_type,id)) { #ifdef TOOLS_ENABLED - MethodBind *mb = ObjectTypeDB::get_method(base.obj_type,id); + MethodBind *mb = ClassDB::get_method(base.obj_type,id); PropertyInfo pi = mb->get_argument_info(-1); //try calling the function if constant and all args are constant, should not crash.. @@ -642,14 +645,14 @@ static bool _guess_expression_type(GDCompletionContext& context,const GDParser:: } } - if (all_valid && String(id)=="get_node" && ObjectTypeDB::is_type(base.obj_type,"Node") && args.size()) { + if (all_valid && String(id)=="get_node" && ClassDB::is_parent_class(base.obj_type,"Node") && args.size()) { String arg1=args[0]; if (arg1.begins_with("/root/")) { String which = arg1.get_slice("/",2); if (which!="") { List<PropertyInfo> props; - Globals::get_singleton()->get_property_list(&props); + GlobalConfig::get_singleton()->get_property_list(&props); //print_line("find singleton"); for(List<PropertyInfo>::Element *E=props.front();E;E=E->next()) { @@ -661,7 +664,7 @@ static bool _guess_expression_type(GDCompletionContext& context,const GDParser:: String name = s.get_slice("/",1); //print_line("name: "+name+", which: "+which); if (name==which) { - String script = Globals::get_singleton()->get(s); + String script = GlobalConfig::get_singleton()->get(s); if (!script.begins_with("res://")) { script="res://"+script; @@ -670,7 +673,7 @@ static bool _guess_expression_type(GDCompletionContext& context,const GDParser:: if (!script.ends_with(".gd")) { //not a script, try find the script anyway, //may have some success - script=script.basename()+".gd"; + script=script.get_basename()+".gd"; } if (FileAccess::exists(script)) { @@ -935,9 +938,19 @@ static bool _guess_expression_type(GDCompletionContext& context,const GDParser:: return false; } + static bool _guess_identifier_type_in_block(GDCompletionContext& context,int p_line,const StringName& p_identifier,GDCompletionIdentifier &r_type) { + GDCompletionIdentifier gdi = _get_native_class(context); + if (gdi.obj_type!=StringName()) { + bool valid; + Variant::Type t = ClassDB::get_property_type(gdi.obj_type,p_identifier,&valid); + if (t!=Variant::NIL && valid) { + r_type.type=t; + return true; + } + } const GDParser::Node *last_assign=NULL; int last_assign_line=-1; @@ -1066,7 +1079,7 @@ static bool _guess_identifier_type(GDCompletionContext& context,int p_line,const //this kinda sucks but meh List<MethodInfo> vmethods; - ObjectTypeDB::get_virtual_methods(id.obj_type,&vmethods); + ClassDB::get_virtual_methods(id.obj_type,&vmethods); for (List<MethodInfo>::Element *E=vmethods.front();E;E=E->next()) { @@ -1140,7 +1153,7 @@ static bool _guess_identifier_type(GDCompletionContext& context,int p_line,const //autoloads as singletons List<PropertyInfo> props; - Globals::get_singleton()->get_property_list(&props); + GlobalConfig::get_singleton()->get_property_list(&props); for(List<PropertyInfo>::Element *E=props.front();E;E=E->next()) { @@ -1150,14 +1163,14 @@ static bool _guess_identifier_type(GDCompletionContext& context,int p_line,const String name = s.get_slice("/",1); if (name==String(p_identifier)) { - String path = Globals::get_singleton()->get(s); + String path = GlobalConfig::get_singleton()->get(s); if (path.begins_with("*")) { String script =path.substr(1,path.length()); if (!script.ends_with(".gd")) { //not a script, try find the script anyway, //may have some success - script=script.basename()+".gd"; + script=script.get_basename()+".gd"; } if (FileAccess::exists(script)) { @@ -1296,26 +1309,43 @@ static void _find_identifiers_in_class(GDCompletionContext& context,bool p_stati base=script->get_native(); } else if (nc.is_valid()) { + StringName type = nc->get_name(); + if (!p_only_functions) { - StringName type = nc->get_name(); + List<String> constants; - ObjectTypeDB::get_integer_constant_list(type,&constants); + ClassDB::get_integer_constant_list(type,&constants); for(List<String>::Element *E=constants.front();E;E=E->next()) { result.insert(E->get()); } - List<MethodInfo> methods; - ObjectTypeDB::get_method_list(type,&methods); - for(List<MethodInfo>::Element *E=methods.front();E;E=E->next()) { - if (E->get().name.begins_with("_")) + List<PropertyInfo> pinfo; + + ClassDB::get_property_list(type,&pinfo); + + for (List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) { + if (E->get().usage&(PROPERTY_USAGE_GROUP|PROPERTY_USAGE_CATEGORY)) continue; - if (E->get().arguments.size()) - result.insert(E->get().name+"("); - else - result.insert(E->get().name+"()"); + if (E->get().name.find("/")!=-1) + continue; + result.insert(E->get().name); } + } + List<MethodInfo> methods; + ClassDB::get_method_list(type,&methods); + for(List<MethodInfo>::Element *E=methods.front();E;E=E->next()) { + if (E->get().name.begins_with("_")) + continue; + if (E->get().arguments.size()) + result.insert(E->get().name+"("); + else + result.insert(E->get().name+"()"); + } + + + break; } else break; @@ -1365,7 +1395,7 @@ static void _find_identifiers(GDCompletionContext& context,int p_line,bool p_onl } static const char*_type_names[Variant::VARIANT_MAX]={ - "null","bool","int","float","String","Vector2","Rect2","Vector3","Matrix32","Plane","Quat","AABB","Matrix3","Transform", + "null","bool","int","float","String","Vector2","Rect2","Vector3","Transform2D","Plane","Quat","AABB","Basis","Transform", "Color","Image","NodePath","RID","Object","InputEvent","Dictionary","Array","RawArray","IntArray","FloatArray","StringArray", "Vector2Array","Vector3Array","ColorArray"}; @@ -1375,7 +1405,7 @@ static void _find_identifiers(GDCompletionContext& context,int p_line,bool p_onl //autoload singletons List<PropertyInfo> props; - Globals::get_singleton()->get_property_list(&props); + GlobalConfig::get_singleton()->get_property_list(&props); for(List<PropertyInfo>::Element *E=props.front();E;E=E->next()) { @@ -1383,7 +1413,7 @@ static void _find_identifiers(GDCompletionContext& context,int p_line,bool p_onl if (!s.begins_with("autoload/")) continue; String name = s.get_slice("/",1); - String path = Globals::get_singleton()->get(s); + String path = GlobalConfig::get_singleton()->get(s); if (path.begins_with("*")) { result.insert(name); } @@ -1468,7 +1498,7 @@ static void _find_type_arguments(GDCompletionContext& context,const GDParser::No if (id.type==Variant::INPUT_EVENT && String(p_method)=="is_action" && p_argidx==0) { List<PropertyInfo> pinfo; - Globals::get_singleton()->get_property_list(&pinfo); + GlobalConfig::get_singleton()->get_property_list(&pinfo); for(List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) { const PropertyInfo &pi=E->get(); @@ -1484,7 +1514,7 @@ static void _find_type_arguments(GDCompletionContext& context,const GDParser::No } else if (id.type==Variant::OBJECT && id.obj_type!=StringName()) { - MethodBind *m = ObjectTypeDB::get_method(id.obj_type,p_method); + MethodBind *m = ClassDB::get_method(id.obj_type,p_method); if (!m) { //not in static method, see script @@ -1697,7 +1727,7 @@ static void _find_type_arguments(GDCompletionContext& context,const GDParser::No if (p_argidx==0) { List<MethodInfo> sigs; - ObjectTypeDB::get_signal_list(id.obj_type,&sigs); + ClassDB::get_signal_list(id.obj_type,&sigs); if (id.script.is_valid()) { id.script->get_script_signal_list(&sigs); @@ -1733,17 +1763,17 @@ static void _find_type_arguments(GDCompletionContext& context,const GDParser::No }*/ } else { - if (p_argidx==0 && (String(p_method)=="get_node" || String(p_method)=="has_node") && ObjectTypeDB::is_type(id.obj_type,"Node")) { + if (p_argidx==0 && (String(p_method)=="get_node" || String(p_method)=="has_node") && ClassDB::is_parent_class(id.obj_type,"Node")) { List<PropertyInfo> props; - Globals::get_singleton()->get_property_list(&props); + GlobalConfig::get_singleton()->get_property_list(&props); for(List<PropertyInfo>::Element *E=props.front();E;E=E->next()) { String s = E->get().name; if (!s.begins_with("autoload/")) continue; - // print_line("found "+s); + //print_line("found "+s); String name = s.get_slice("/",1); result.insert("\"/root/"+name+"\""); } @@ -1968,12 +1998,12 @@ static void _find_call_arguments(GDCompletionContext& context,const GDParser::No //guess type.. /* List<MethodInfo> methods; - ObjectTypeDB::get_method_list(type,&methods); + ClassDB::get_method_list(type,&methods); for(List<MethodInfo>::Element *E=methods.front();E;E=E->next()) { - //if (E->get().arguments.size()) - // result.insert(E->get().name+"("); - //else - // result.insert(E->get().name+"()"); + if (E->get().arguments.size()) + result.insert(E->get().name+"("); + else + result.insert(E->get().name+"()"); }*/ } break; @@ -2061,13 +2091,13 @@ static void _find_call_arguments(GDCompletionContext& context,const GDParser::No StringName type = nc->get_name(); List<String> constants; - ObjectTypeDB::get_integer_constant_list(type,&constants); + ClassDB::get_integer_constant_list(type,&constants); for(List<String>::Element *E=constants.front();E;E=E->next()) { result.insert(E->get()); } List<MethodInfo> methods; - ObjectTypeDB::get_method_list(type,&methods); + ClassDB::get_method_list(type,&methods); for(List<MethodInfo>::Element *E=methods.front();E;E=E->next()) { if (E->get().arguments.size()) result.insert(E->get().name+"("); @@ -2094,7 +2124,7 @@ Error GDScriptLanguage::complete_code(const String& p_code, const String& p_base GDParser p; - Error err = p.parse(p_code,p_base_path,false,"",true); + p.parse(p_code,p_base_path,false,"",true); bool isfunction=false; Set<String> options; @@ -2127,6 +2157,27 @@ Error GDScriptLanguage::complete_code(const String& p_code, const String& p_base case GDParser::COMPLETION_PARENT_FUNCTION: { } break; + case GDParser::COMPLETION_GET_NODE: { + + if (p_owner) { + List<String> opts; + p_owner->get_argument_options("get_node",0,&opts); + + for (List<String>::Element *E=opts.front();E;E=E->next()) { + + String opt = E->get().strip_edges(); + if (opt.begins_with("\"") && opt.ends_with("\"")) { + String idopt=opt.substr(1,opt.length()-2); + if (idopt.replace("/","_").is_valid_identifier()) { + options.insert(idopt); + } else { + options.insert(opt); + } + } + } + + } + } break; case GDParser::COMPLETION_METHOD: isfunction=true; case GDParser::COMPLETION_INDEX: { @@ -2141,7 +2192,29 @@ Error GDScriptLanguage::complete_code(const String& p_code, const String& p_base GDCompletionIdentifier t; if (_guess_expression_type(context,static_cast<const GDParser::OperatorNode *>(node)->arguments[0],p.get_completion_line(),t)) { - if (t.type==Variant::OBJECT && t.obj_type!=StringName()) { + if (t.type==Variant::OBJECT && t.obj_type=="GDNativeClass") { + //native enum + Ref<GDNativeClass> gdn = t.value; + if (gdn.is_valid()) { + StringName cn = gdn->get_name(); + List<String> cnames; + ClassDB::get_integer_constant_list(cn,&cnames); + for (List<String>::Element *E=cnames.front();E;E=E->next()) { + options.insert(E->get()); + } + + List<PropertyInfo> pinfo; + ClassDB::get_property_list(cn,&pinfo); + + for (List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) { + if (E->get().usage&(PROPERTY_USAGE_GROUP|PROPERTY_USAGE_CATEGORY)) + continue; + if (E->get().name.find("/")!=-1) + continue; + options.insert(E->get().name); + } + } + } else if (t.type==Variant::OBJECT && t.obj_type!=StringName()) { Ref<GDScript> on_script; @@ -2275,10 +2348,23 @@ Error GDScriptLanguage::complete_code(const String& p_code, const String& p_base if (!isfunction) { - ObjectTypeDB::get_integer_constant_list(t.obj_type,r_options); + ClassDB::get_integer_constant_list(t.obj_type,r_options); + + List<PropertyInfo> pinfo; + ClassDB::get_property_list(t.obj_type,&pinfo); + + for (List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) { + if (E->get().usage&(PROPERTY_USAGE_GROUP|PROPERTY_USAGE_CATEGORY)) + continue; + if (E->get().name.find("/")!=-1) + continue; + r_options->push_back(E->get().name); + } } + + List<MethodInfo> mi; - ObjectTypeDB::get_method_list(t.obj_type,&mi); + ClassDB::get_method_list(t.obj_type,&mi); for (List<MethodInfo>::Element *E=mi.front();E;E=E->next()) { if (E->get().name.begins_with("_")) @@ -2307,8 +2393,8 @@ Error GDScriptLanguage::complete_code(const String& p_code, const String& p_base "# Key", "# MouseMotion", "# MouseButton", - "# JoystickMotion", - "# JoystickButton", + "# JoypadMotion", + "# JoypadButton", "# ScreenTouch", "# ScreenDrag", "# Action" @@ -2384,7 +2470,7 @@ Error GDScriptLanguage::complete_code(const String& p_code, const String& p_base if (cid.obj_type!=StringName()) { List<MethodInfo> vm; - ObjectTypeDB::get_virtual_methods(cid.obj_type,&vm); + ClassDB::get_virtual_methods(cid.obj_type,&vm); for(List<MethodInfo>::Element *E=vm.front();E;E=E->next()) { MethodInfo &mi=E->get(); @@ -2420,7 +2506,7 @@ Error GDScriptLanguage::complete_code(const String& p_code, const String& p_base if (t.type==Variant::OBJECT && t.obj_type!=StringName()) { List<MethodInfo> sigs; - ObjectTypeDB::get_signal_list(t.obj_type,&sigs); + ClassDB::get_signal_list(t.obj_type,&sigs); for (List<MethodInfo>::Element *E=sigs.front();E;E=E->next()) { options.insert("\""+E->get().name+"\""); } @@ -2511,3 +2597,457 @@ void GDScriptLanguage::auto_indent_code(String& p_code,int p_from_line,int p_to_ } } + +#ifdef TOOLS_ENABLED + +Error GDScriptLanguage::lookup_code(const String& p_code, const String& p_symbol,const String& p_base_path, Object*p_owner,LookupResult& r_result) { + + + //before parsing, try the usual stuff + if (ClassDB::class_exists(p_symbol)) { + r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS; + r_result.class_name=p_symbol; + return OK; + } + + for(int i=0;i<Variant::VARIANT_MAX;i++) { + Variant::Type t = Variant::Type(i); + if (Variant::get_type_name(t)==p_symbol) { + r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS; + r_result.class_name=Variant::get_type_name(t); + return OK; + } + } + + for(int i=0;i<GDFunctions::FUNC_MAX;i++) { + if (GDFunctions::get_func_name(GDFunctions::Function(i))==p_symbol) { + r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS_METHOD; + r_result.class_name="@GDScript"; + r_result.class_member=p_symbol; + return OK; + } + } + + GDParser p; + p.parse(p_code,p_base_path,false,"",true); + + if (p.get_completion_type()==GDParser::COMPLETION_NONE) + return ERR_CANT_RESOLVE; + + GDCompletionContext context; + + context._class=p.get_completion_class(); + context.block=p.get_completion_block(); + context.function=p.get_completion_function(); + context.base=p_owner; + context.base_path=p_base_path; + bool isfunction=false; + + switch(p.get_completion_type()) { + + case GDParser::COMPLETION_GET_NODE: + case GDParser::COMPLETION_NONE: { + } break; + case GDParser::COMPLETION_BUILT_IN_TYPE_CONSTANT: { + + r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS_CONSTANT; + r_result.class_name=Variant::get_type_name(p.get_completion_built_in_constant()); + r_result.class_member=p_symbol; + return OK; + + } break; + case GDParser::COMPLETION_FUNCTION: { + + + if (context._class && context._class->functions.size()) { + for(int i=0;i<context._class->functions.size();i++) { + if (context._class->functions[i]->name==p_symbol) { + r_result.type=ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION; + r_result.location=context._class->functions[i]->line; + return OK; + } + } + } + + Ref<GDScript> parent = _get_parent_class(context); + while(parent.is_valid()) { + int line = parent->get_member_line(p_symbol); + if (line>=0) { + r_result.type=ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION; + r_result.location=line; + r_result.script=parent; + return OK; + + } + + parent=parent->get_base(); + } + + GDCompletionIdentifier identifier = _get_native_class(context); + print_line("identifier: "+String(identifier.obj_type)); + + if (ClassDB::has_method(identifier.obj_type,p_symbol)) { + + r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS_METHOD; + r_result.class_name=identifier.obj_type; + r_result.class_member=p_symbol; + return OK; + } + + + } break; + case GDParser::COMPLETION_IDENTIFIER: { + + //check if a function + if (p.get_completion_identifier_is_function()) { + if (context._class && context._class->functions.size()) { + for(int i=0;i<context._class->functions.size();i++) { + if (context._class->functions[i]->name==p_symbol) { + r_result.type=ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION; + r_result.location=context._class->functions[i]->line; + return OK; + } + } + } + + Ref<GDScript> parent = _get_parent_class(context); + while(parent.is_valid()) { + int line = parent->get_member_line(p_symbol); + if (line>=0) { + r_result.type=ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION; + r_result.location=line; + r_result.script=parent; + return OK; + + } + + parent=parent->get_base(); + } + + GDCompletionIdentifier identifier = _get_native_class(context); + + + if (ClassDB::has_method(identifier.obj_type,p_symbol)) { + + r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS_METHOD; + r_result.class_name=identifier.obj_type; + r_result.class_member=p_symbol; + return OK; + } + } else { + + + GDCompletionIdentifier gdi = _get_native_class(context); + if (gdi.obj_type!=StringName()) { + bool valid; + Variant::Type t = ClassDB::get_property_type(gdi.obj_type,p_symbol,&valid); + if (t!=Variant::NIL && valid) { + r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS_PROPERTY; + r_result.class_name=gdi.obj_type; + r_result.class_member=p_symbol; + return OK; + + } + } + + const GDParser::BlockNode *block=context.block; + //search in blocks going up (local var?) + while(block) { + + + + for (int i=0;i<block->statements.size();i++) { + + if (block->statements[i]->line>p.get_completion_line()) + continue; + + + if (block->statements[i]->type==GDParser::BlockNode::TYPE_LOCAL_VAR) { + + const GDParser::LocalVarNode *lv=static_cast<const GDParser::LocalVarNode *>(block->statements[i]); + + if (lv->assign && lv->name==p_symbol) { + + r_result.type=ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION; + r_result.location=block->statements[i]->line; + return OK; + } + } + } + block=block->parent_block; + } + + //guess from function arguments + if (context.function && context.function->name!=StringName()) { + + for(int i=0;i<context.function->arguments.size();i++) { + + if (context.function->arguments[i]==p_symbol) { + r_result.type=ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION; + r_result.location=context.function->line; + return OK; + } + + } + } + + //guess in class constants + + for(int i=0;i<context._class->constant_expressions.size();i++) { + + if (context._class->constant_expressions[i].identifier==p_symbol) { + r_result.type=ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION; + r_result.location=context._class->constant_expressions[i].expression->line; + return OK; + } + } + + //guess in class variables + if (!(context.function && context.function->_static)) { + + for(int i=0;i<context._class->variables.size();i++) { + + if (context._class->variables[i].identifier==p_symbol) { + + r_result.type=ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION; + r_result.location=context._class->variables[i].line; + return OK; + } + } + } + + //guess in autoloads as singletons + List<PropertyInfo> props; + GlobalConfig::get_singleton()->get_property_list(&props); + + for(List<PropertyInfo>::Element *E=props.front();E;E=E->next()) { + + String s = E->get().name; + if (!s.begins_with("autoload/")) + continue; + String name = s.get_slice("/",1); + if (name==String(p_symbol)) { + + String path = GlobalConfig::get_singleton()->get(s); + if (path.begins_with("*")) { + String script =path.substr(1,path.length()); + + if (!script.ends_with(".gd")) { + //not a script, try find the script anyway, + //may have some success + script=script.get_basename()+".gd"; + } + + if (FileAccess::exists(script)) { + + r_result.type=ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION; + r_result.location=0; + r_result.script=ResourceLoader::load(script); + return OK; + } + } + } + } + + //global + for(Map<StringName,int>::Element *E=GDScriptLanguage::get_singleton()->get_global_map().front();E;E=E->next()) { + if (E->key()==p_symbol) { + + Variant value = GDScriptLanguage::get_singleton()->get_global_array()[E->get()]; + if (value.get_type()==Variant::OBJECT) { + Object *obj = value; + if (obj) { + + if (obj->cast_to<GDNativeClass>()) { + r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS; + r_result.class_name=obj->cast_to<GDNativeClass>()->get_name(); + + } else { + r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS; + r_result.class_name=obj->get_class(); + } + return OK; + } + } else { + + r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS_CONSTANT; + r_result.class_name="@Global Scope"; + r_result.class_member=p_symbol; + return OK; + } + } + + } +#if 0 + GDCompletionIdentifier identifier; + if (_guess_identifier_type(context,p.get_completion_line(),p_symbol,identifier)) { + + print_line("var type: "+Variant::get_type_name(identifier.type)); + if (identifier.script.is_valid()) { + print_line("var script: "+identifier.script->get_path()); + } + print_line("obj type: "+String(identifier.obj_type)); + print_line("value: "+String(identifier.value)); + } +#endif + } + + } break; + case GDParser::COMPLETION_PARENT_FUNCTION: { + + } break; + case GDParser::COMPLETION_METHOD: + isfunction=true; + case GDParser::COMPLETION_INDEX: { + + const GDParser::Node *node = p.get_completion_node(); + if (node->type!=GDParser::Node::TYPE_OPERATOR) + break; + + + + + GDCompletionIdentifier t; + if (_guess_expression_type(context,static_cast<const GDParser::OperatorNode *>(node)->arguments[0],p.get_completion_line(),t)) { + + if (t.type==Variant::OBJECT && t.obj_type=="GDNativeClass") { + //native enum + Ref<GDNativeClass> gdn = t.value; + if (gdn.is_valid()) { + r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS_CONSTANT; + r_result.class_name=gdn->get_name(); + r_result.class_member=p_symbol; + return OK; + + } + } else if (t.type==Variant::OBJECT && t.obj_type!=StringName()) { + + Ref<GDScript> on_script; + + if (t.value.get_type()) { + Object *obj=t.value; + + + if (obj) { + + + on_script=obj->get_script(); + + if (on_script.is_valid()) { + int loc = on_script->get_member_line(p_symbol); + if (loc>=0) { + r_result.script=on_script; + r_result.type=ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION; + r_result.location=loc; + return OK; + } + } + } + } + + if (ClassDB::has_method(t.obj_type,p_symbol)) { + + r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS_METHOD; + r_result.class_name=t.obj_type; + r_result.class_member=p_symbol; + return OK; + + } + + bool success; + ClassDB::get_integer_constant(t.obj_type,p_symbol,&success); + if (success) { + r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS_CONSTANT; + r_result.class_name=t.obj_type; + r_result.class_member=p_symbol; + return OK; + } + + + ClassDB::get_property_type(t.obj_type,p_symbol,&success); + + if (success) { + r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS_PROPERTY; + r_result.class_name=t.obj_type; + r_result.class_member=p_symbol; + return OK; + } + + + } else { + + Variant::CallError ce; + Variant v = Variant::construct(t.type,NULL,0,ce); + + bool valid; + v.get_numeric_constant_value(t.type,p_symbol,&valid); + if (valid) { + r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS_CONSTANT; + r_result.class_name=Variant::get_type_name(t.type); + r_result.class_member=p_symbol; + return OK; + } + + //todo check all inputevent types for property + + v.get(p_symbol,&valid); + + if (valid) { + r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS_PROPERTY; + r_result.class_name=Variant::get_type_name(t.type); + r_result.class_member=p_symbol; + return OK; + } + + if (v.has_method(p_symbol)) { + + r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS_METHOD; + r_result.class_name=Variant::get_type_name(t.type); + r_result.class_member=p_symbol; + return OK; + + } + + + } + } + + + } break; + case GDParser::COMPLETION_CALL_ARGUMENTS: { + + return ERR_CANT_RESOLVE; + } break; + case GDParser::COMPLETION_VIRTUAL_FUNC: { + + GDCompletionIdentifier cid = _get_native_class(context); + + if (cid.obj_type!=StringName()) { + List<MethodInfo> vm; + ClassDB::get_virtual_methods(cid.obj_type,&vm); + for(List<MethodInfo>::Element *E=vm.front();E;E=E->next()) { + + if (p_symbol==E->get().name) { + + r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS_METHOD; + r_result.class_name=cid.obj_type; + r_result.class_member=p_symbol; + return OK; + + } + } + } + } break; + case GDParser::COMPLETION_YIELD: { + + return ERR_CANT_RESOLVE; + + } break; + + } + + + return ERR_CANT_RESOLVE; +} + +#endif diff --git a/modules/gdscript/gd_function.cpp b/modules/gdscript/gd_function.cpp index b2cc6341c1..31bac2748a 100644 --- a/modules/gdscript/gd_function.cpp +++ b/modules/gdscript/gd_function.cpp @@ -119,9 +119,9 @@ static String _get_var_type(const Variant* p_type) { #ifdef DEBUG_ENABLED if (ObjectDB::instance_validate(bobj)) { if (bobj->get_script_instance()) - basestr= bobj->get_type()+" ("+bobj->get_script_instance()->get_script()->get_path().get_file()+")"; + basestr= bobj->get_class()+" ("+bobj->get_script_instance()->get_script()->get_path().get_file()+")"; else - basestr = bobj->get_type(); + basestr = bobj->get_class(); } else { basestr="previously freed instance"; } @@ -171,7 +171,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a if (p_state) { //use existing (supplied) state (yielded) stack=(Variant*)p_state->stack.ptr(); - call_args=(Variant**)&p_state->stack[sizeof(Variant)*p_state->stack_size]; + call_args=(Variant**)stack + sizeof(Variant)*p_state->stack_size; line=p_state->line; ip=p_state->ip; alloca_size=p_state->stack.size(); @@ -331,8 +331,8 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a #endif ip+=5; - - } continue; + continue; + } case OPCODE_EXTENDS_TEST: { CHECK_SPACE(4); @@ -395,17 +395,17 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a if (!nc) { - err_text="Right operand of 'extends' is not a class (type: '"+obj_B->get_type()+"')."; + err_text="Right operand of 'extends' is not a class (type: '"+obj_B->get_class()+"')."; break; } - extends_ok=ObjectTypeDB::is_type(obj_A->get_type_name(),nc->get_name()); + extends_ok=ClassDB::is_parent_class(obj_A->get_class_name(),nc->get_name()); } *dst=extends_ok; ip+=4; - - } continue; + continue; + } case OPCODE_SET: { CHECK_SPACE(3); @@ -429,7 +429,8 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a } ip+=4; - } continue; + continue; + } case OPCODE_GET: { CHECK_SPACE(3); @@ -460,7 +461,8 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a *dst=ret; #endif ip+=4; - } continue; + continue; + } case OPCODE_SET_NAMED: { CHECK_SPACE(3); @@ -483,11 +485,12 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a } ip+=4; - } continue; + continue; + } case OPCODE_GET_NAMED: { - CHECK_SPACE(3); + CHECK_SPACE(4); GET_VARIANT_PTR(src,1); GET_VARIANT_PTR(dst,3); @@ -518,7 +521,49 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a *dst=ret; #endif ip+=4; - } continue; + continue; + } + case OPCODE_SET_MEMBER: { + + CHECK_SPACE(3); + int indexname = _code_ptr[ip+1]; + ERR_BREAK(indexname<0 || indexname>=_global_names_count); + const StringName *index = &_global_names_ptr[indexname]; + GET_VARIANT_PTR(src,2); + + bool valid; + bool ok = ClassDB::set_property(p_instance->owner,*index,*src,&valid); +#ifdef DEBUG_ENABLED + if (!ok) { + err_text="Internal error setting property: "+String(*index); + break; + } else if (!valid) { + err_text="Error setting property '"+String(*index)+"' with value of type "+Variant::get_type_name(src->get_type())+"."; + break; + + } +#endif + ip+=3; + continue; + } + case OPCODE_GET_MEMBER: { + + CHECK_SPACE(3); + int indexname = _code_ptr[ip+1]; + ERR_BREAK(indexname<0 || indexname>=_global_names_count); + const StringName *index = &_global_names_ptr[indexname]; + GET_VARIANT_PTR(dst,2); + bool ok = ClassDB::get_property(p_instance->owner,*index,*dst); + +#ifdef DEBUG_ENABLED + if (!ok) { + err_text="Internal error getting property: "+String(*index); + break; + } +#endif + ip+=3; + continue; + } case OPCODE_ASSIGN: { CHECK_SPACE(3); @@ -528,8 +573,8 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a *dst = *src; ip+=3; - - } continue; + continue; + } case OPCODE_ASSIGN_TRUE: { CHECK_SPACE(2); @@ -538,7 +583,8 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a *dst = true; ip+=2; - } continue; + continue; + } case OPCODE_ASSIGN_FALSE: { CHECK_SPACE(2); @@ -547,7 +593,8 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a *dst = false; ip+=2; - } continue; + continue; + } case OPCODE_CONSTRUCT: { CHECK_SPACE(2); @@ -572,12 +619,13 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a ip+=4+argc; //construct a basic type - } continue; + continue; + } case OPCODE_CONSTRUCT_ARRAY: { CHECK_SPACE(1); int argc=_code_ptr[ip+1]; - Array array(true); //arrays are always shared + Array array; //arrays are always shared array.resize(argc); CHECK_SPACE(argc+2); @@ -592,13 +640,13 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a *dst=array; ip+=3+argc; - - } continue; + continue; + } case OPCODE_CONSTRUCT_DICTIONARY: { CHECK_SPACE(1); int argc=_code_ptr[ip+1]; - Dictionary dict(true); //arrays are always shared + Dictionary dict; //arrays are always shared CHECK_SPACE(argc*2+2); @@ -615,8 +663,8 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a *dst=dict; ip+=3+argc*2; - - } continue; + continue; + } case OPCODE_CALL_RETURN: case OPCODE_CALL: { @@ -697,8 +745,8 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a //_call_func(NULL,base,*methodname,ip,argc,p_instance,stack); ip+=argc+1; - - } continue; + continue; + } case OPCODE_CALL_BUILT_IN: { CHECK_SPACE(4); @@ -735,12 +783,12 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a break; } ip+=argc+1; - - } continue; + continue; + } case OPCODE_CALL_SELF: { - - } break; + break; + } case OPCODE_CALL_SELF_BASE: { CHECK_SPACE(2); @@ -788,7 +836,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a if (*methodname!=GDScriptLanguage::get_singleton()->strings._init) { - MethodBind *mb = ObjectTypeDB::get_method(gds->native->get_name(),*methodname); + MethodBind *mb = ClassDB::get_method(gds->native->get_name(),*methodname); if (!mb) { err.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; } else { @@ -817,8 +865,8 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a } ip+=4+argc; - - } continue; + continue; + } case OPCODE_YIELD: case OPCODE_YIELD_SIGNAL: { @@ -898,8 +946,8 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a } exit_ok=true; - - } break; + break; + } case OPCODE_YIELD_RESUME: { CHECK_SPACE(2); @@ -910,8 +958,8 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a GET_VARIANT_PTR(result,1); *result=p_state->result; ip+=2; - - } continue; + continue; + } case OPCODE_JUMP: { CHECK_SPACE(2); @@ -919,8 +967,8 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a ERR_BREAK(to<0 || to>_code_size); ip=to; - - } continue; + continue; + } case OPCODE_JUMP_IF: { CHECK_SPACE(3); @@ -943,7 +991,8 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a continue; } ip+=3; - } continue; + continue; + } case OPCODE_JUMP_IF_NOT: { CHECK_SPACE(3); @@ -966,21 +1015,22 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a continue; } ip+=3; - } continue; + continue; + } case OPCODE_JUMP_TO_DEF_ARGUMENT: { CHECK_SPACE(2); ip=_default_arg_ptr[defarg]; - - } continue; + continue; + } case OPCODE_RETURN: { CHECK_SPACE(2); GET_VARIANT_PTR(r,1); retvalue=*r; exit_ok=true; - - } break; + break; + } case OPCODE_ITERATE_BEGIN: { CHECK_SPACE(8); //space for this an regular iterate @@ -1010,8 +1060,8 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a ip+=5; //skip regular iterate which is always next - - } continue; + continue; + } case OPCODE_ITERATE: { CHECK_SPACE(4); @@ -1039,7 +1089,8 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a } ip+=5; //loop again - } continue; + continue; + } case OPCODE_ASSERT: { CHECK_SPACE(2); GET_VARIANT_PTR(test,1); @@ -1065,7 +1116,8 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a #endif ip+=2; - } continue; + continue; + } case OPCODE_BREAKPOINT: { #ifdef DEBUG_ENABLED if (ScriptDebugger::get_singleton()) { @@ -1073,7 +1125,8 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a } #endif ip+=1; - } continue; + continue; + } case OPCODE_LINE: { CHECK_SPACE(2); @@ -1102,17 +1155,19 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a ScriptDebugger::get_singleton()->line_poll(); } - } continue; + continue; + } case OPCODE_END: { exit_ok=true; break; - } break; + } default: { err_text="Illegal opcode "+itos(_code_ptr[ip])+" at address "+itos(ip); - } break; + break; + } } @@ -1435,9 +1490,9 @@ Variant GDFunctionState::resume(const Variant& p_arg) { void GDFunctionState::_bind_methods() { - ObjectTypeDB::bind_method(_MD("resume:Variant","arg"),&GDFunctionState::resume,DEFVAL(Variant())); - ObjectTypeDB::bind_method(_MD("is_valid"),&GDFunctionState::is_valid); - ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"_signal_callback",&GDFunctionState::_signal_callback,MethodInfo("_signal_callback")); + ClassDB::bind_method(D_METHOD("resume:Variant","arg"),&GDFunctionState::resume,DEFVAL(Variant())); + ClassDB::bind_method(D_METHOD("is_valid"),&GDFunctionState::is_valid); + ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT,"_signal_callback",&GDFunctionState::_signal_callback,MethodInfo("_signal_callback")); } diff --git a/modules/gdscript/gd_function.h b/modules/gdscript/gd_function.h index f1c5b13ca1..e5262e8ad7 100644 --- a/modules/gdscript/gd_function.h +++ b/modules/gdscript/gd_function.h @@ -23,6 +23,8 @@ public: OPCODE_GET, OPCODE_SET_NAMED, OPCODE_GET_NAMED, + OPCODE_SET_MEMBER, + OPCODE_GET_MEMBER, OPCODE_ASSIGN, OPCODE_ASSIGN_TRUE, OPCODE_ASSIGN_FALSE, @@ -204,7 +206,7 @@ public: class GDFunctionState : public Reference { - OBJ_TYPE(GDFunctionState,Reference); + GDCLASS(GDFunctionState,Reference); friend class GDFunction; GDFunction *function; GDFunction::CallState state; diff --git a/modules/gdscript/gd_functions.cpp b/modules/gdscript/gd_functions.cpp index a565e866d0..d0fc241734 100644 --- a/modules/gdscript/gd_functions.cpp +++ b/modules/gdscript/gd_functions.cpp @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,13 +28,14 @@ /*************************************************************************/ #include "gd_functions.h" #include "math_funcs.h" -#include "object_type_db.h" +#include "class_db.h" #include "reference.h" #include "gd_script.h" #include "func_ref.h" #include "os/os.h" #include "variant_parser.h" #include "io/marshalls.h" +#include "io/json.h" const char *GDFunctions::get_func_name(Function p_func) { @@ -88,6 +89,7 @@ const char *GDFunctions::get_func_name(Function p_func) { "convert", "typeof", "type_exists", + "char", "str", "print", "printt", @@ -102,8 +104,12 @@ const char *GDFunctions::get_func_name(Function p_func) { "load", "inst2dict", "dict2inst", + "validate_json", + "parse_json", + "to_json", "hash", "Color8", + "ColorN", "print_stack", "instance_from_id", }; @@ -153,85 +159,85 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va case MATH_SIN: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); - r_ret=Math::sin(*p_args[0]); + r_ret=Math::sin((double)*p_args[0]); } break; case MATH_COS: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); - r_ret=Math::cos(*p_args[0]); + r_ret=Math::cos((double)*p_args[0]); } break; case MATH_TAN: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); - r_ret=Math::tan(*p_args[0]); + r_ret=Math::tan((double)*p_args[0]); } break; case MATH_SINH: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); - r_ret=Math::sinh(*p_args[0]); + r_ret=Math::sinh((double)*p_args[0]); } break; case MATH_COSH: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); - r_ret=Math::cosh(*p_args[0]); + r_ret=Math::cosh((double)*p_args[0]); } break; case MATH_TANH: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); - r_ret=Math::tanh(*p_args[0]); + r_ret=Math::tanh((double)*p_args[0]); } break; case MATH_ASIN: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); - r_ret=Math::asin(*p_args[0]); + r_ret=Math::asin((double)*p_args[0]); } break; case MATH_ACOS: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); - r_ret=Math::acos(*p_args[0]); + r_ret=Math::acos((double)*p_args[0]); } break; case MATH_ATAN: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); - r_ret=Math::atan(*p_args[0]); + r_ret=Math::atan((double)*p_args[0]); } break; case MATH_ATAN2: { VALIDATE_ARG_COUNT(2); VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); - r_ret=Math::atan2(*p_args[0],*p_args[1]); + r_ret=Math::atan2((double)*p_args[0],(double)*p_args[1]); } break; case MATH_SQRT: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); - r_ret=Math::sqrt(*p_args[0]); + r_ret=Math::sqrt((double)*p_args[0]); } break; case MATH_FMOD: { VALIDATE_ARG_COUNT(2); VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); - r_ret=Math::fmod(*p_args[0],*p_args[1]); + r_ret=Math::fmod((double)*p_args[0],(double)*p_args[1]); } break; case MATH_FPOSMOD: { VALIDATE_ARG_COUNT(2); VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); - r_ret=Math::fposmod(*p_args[0],*p_args[1]); + r_ret=Math::fposmod((double)*p_args[0],(double)*p_args[1]); } break; case MATH_FLOOR: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); - r_ret=Math::floor(*p_args[0]); + r_ret=Math::floor((double)*p_args[0]); } break; case MATH_CEIL: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); - r_ret=Math::ceil(*p_args[0]); + r_ret=Math::ceil((double)*p_args[0]); } break; case MATH_ROUND: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); - r_ret=Math::round(*p_args[0]); + r_ret=Math::round((double)*p_args[0]); } break; case MATH_ABS: { VALIDATE_ARG_COUNT(1); @@ -241,7 +247,7 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va r_ret=ABS(i); } else if (p_args[0]->get_type()==Variant::REAL) { - real_t r = *p_args[0]; + double r = *p_args[0]; r_ret=Math::abs(r); } else { @@ -273,58 +279,58 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va VALIDATE_ARG_COUNT(2); VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); - r_ret=Math::pow(*p_args[0],*p_args[1]); + r_ret=Math::pow((double)*p_args[0],(double)*p_args[1]); } break; case MATH_LOG: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); - r_ret=Math::log(*p_args[0]); + r_ret=Math::log((double)*p_args[0]); } break; case MATH_EXP: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); - r_ret=Math::exp(*p_args[0]); + r_ret=Math::exp((double)*p_args[0]); } break; case MATH_ISNAN: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); - r_ret=Math::is_nan(*p_args[0]); + r_ret=Math::is_nan((double)*p_args[0]); } break; case MATH_ISINF: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); - r_ret=Math::is_inf(*p_args[0]); + r_ret=Math::is_inf((double)*p_args[0]); } break; case MATH_EASE: { VALIDATE_ARG_COUNT(2); VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); - r_ret=Math::ease(*p_args[0],*p_args[1]); + r_ret=Math::ease((double)*p_args[0],(double)*p_args[1]); } break; case MATH_DECIMALS: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); - r_ret=Math::step_decimals(*p_args[0]); + r_ret=Math::step_decimals((double)*p_args[0]); } break; case MATH_STEPIFY: { VALIDATE_ARG_COUNT(2); VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); - r_ret=Math::stepify(*p_args[0],*p_args[1]); + r_ret=Math::stepify((double)*p_args[0],(double)*p_args[1]); } break; case MATH_LERP: { VALIDATE_ARG_COUNT(3); VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); VALIDATE_ARG_NUM(2); - r_ret=Math::lerp(*p_args[0],*p_args[1],*p_args[2]); + r_ret=Math::lerp((double)*p_args[0],(double)*p_args[1],(double)*p_args[2]); } break; case MATH_DECTIME: { VALIDATE_ARG_COUNT(3); VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); VALIDATE_ARG_NUM(2); - r_ret=Math::dectime(*p_args[0],*p_args[1],*p_args[2]); + r_ret=Math::dectime((double)*p_args[0],(double)*p_args[1],(double)*p_args[2]); } break; case MATH_RANDOMIZE: { Math::randomize(); @@ -340,19 +346,19 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va VALIDATE_ARG_COUNT(2); VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); - r_ret=Math::random(*p_args[0],*p_args[1]); + r_ret=Math::random((double)*p_args[0],(double)*p_args[1]); } break; case MATH_SEED: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); - uint32_t seed=*p_args[0]; + uint64_t seed=*p_args[0]; Math::seed(seed); r_ret=Variant(); } break; case MATH_RANDSEED: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); - uint32_t seed=*p_args[0]; + uint64_t seed=*p_args[0]; int ret = Math::rand_from_seed(&seed); Array reta; reta.push_back(ret); @@ -363,22 +369,22 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va case MATH_DEG2RAD: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); - r_ret=Math::deg2rad(*p_args[0]); + r_ret=Math::deg2rad((double)*p_args[0]); } break; case MATH_RAD2DEG: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); - r_ret=Math::rad2deg(*p_args[0]); + r_ret=Math::rad2deg((double)*p_args[0]); } break; case MATH_LINEAR2DB: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); - r_ret=Math::linear2db(*p_args[0]); + r_ret=Math::linear2db((double)*p_args[0]); } break; case MATH_DB2LINEAR: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); - r_ret=Math::db2linear(*p_args[0]); + r_ret=Math::db2linear((double)*p_args[0]); } break; case LOGIC_MAX: { VALIDATE_ARG_COUNT(2); @@ -535,15 +541,21 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va case TYPE_EXISTS: { VALIDATE_ARG_COUNT(1); - r_ret = ObjectTypeDB::type_exists(*p_args[0]); + r_ret = ClassDB::class_exists(*p_args[0]); } break; + case TEXT_CHAR: { + VALIDATE_ARG_COUNT(1); + VALIDATE_ARG_NUM(0); + CharType result[2] = {*p_args[0], 0}; + r_ret=String(result); + } break; case TEXT_STR: { String str; for(int i=0;i<p_arg_count;i++) { - String os = p_args[i]->operator String();; + String os = p_args[i]->operator String(); if (i==0) str=os; @@ -661,7 +673,7 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va case VAR_TO_BYTES: { VALIDATE_ARG_COUNT(1); - ByteArray barr; + PoolByteArray barr; int len; Error err = encode_variant(*p_args[0],NULL,len); if (err) { @@ -674,7 +686,7 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va barr.resize(len); { - ByteArray::Write w = barr.write(); + PoolByteArray::Write w = barr.write(); encode_variant(*p_args[0],w.ptr(),len); } @@ -682,24 +694,24 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va } break; case BYTES_TO_VAR: { VALIDATE_ARG_COUNT(1); - if (p_args[0]->get_type()!=Variant::RAW_ARRAY) { + if (p_args[0]->get_type()!=Variant::POOL_BYTE_ARRAY) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; - r_error.expected=Variant::RAW_ARRAY; + r_error.expected=Variant::POOL_BYTE_ARRAY; r_ret=Variant(); return; } - ByteArray varr=*p_args[0]; + PoolByteArray varr=*p_args[0]; Variant ret; { - ByteArray::Read r=varr.read(); + PoolByteArray::Read r=varr.read(); Error err = decode_variant(ret,r.ptr(),varr.size(),NULL); if (err!=OK) { r_ret=RTR("Not enough bytes for decoding bytes, or invalid format."); r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; - r_error.expected=Variant::RAW_ARRAY; + r_error.expected=Variant::POOL_BYTE_ARRAY; return; } @@ -723,7 +735,7 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va VALIDATE_ARG_NUM(0); int count=*p_args[0]; - Array arr(true); + Array arr; if (count<=0) { r_ret=arr; return; @@ -749,7 +761,7 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va int from=*p_args[0]; int to=*p_args[1]; - Array arr(true); + Array arr; if (from>=to) { r_ret=arr; return; @@ -780,7 +792,7 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va return; } - Array arr(true); + Array arr; if (from>=to && incr>0) { r_ret=arr; return; @@ -839,9 +851,11 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va if (p_args[0]->get_type()!=Variant::STRING) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; + r_error.expected=Variant::STRING; r_ret=Variant(); + } else { + r_ret=ResourceLoader::load(*p_args[0]); } - r_ret=ResourceLoader::load(*p_args[0]); } break; case INST2DICT: { @@ -907,7 +921,7 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va NodePath cp(sname,Vector<StringName>(),false); - Dictionary d(true); + Dictionary d; d["@subpath"]=cp; d["@path"]=p->path; @@ -1016,6 +1030,57 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va } } break; + case VALIDATE_JSON: { + + VALIDATE_ARG_COUNT(1); + + if (p_args[0]->get_type()!=Variant::STRING) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=0; + r_error.expected=Variant::STRING; + r_ret=Variant(); + return; + } + + String errs; + int errl; + + Error err = JSON::parse(*p_args[0],r_ret,errs,errl); + + if (err!=OK) { + r_ret=itos(errl)+":"+errs; + } else { + r_ret=""; + } + + } break; + case PARSE_JSON: { + + VALIDATE_ARG_COUNT(1); + + if (p_args[0]->get_type()!=Variant::STRING) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=0; + r_error.expected=Variant::STRING; + r_ret=Variant(); + return; + } + + String errs; + int errl; + + Error err = JSON::parse(*p_args[0],r_ret,errs,errl); + + if (err!=OK) { + r_ret=Variant(); + } + + } break; + case TO_JSON: { + VALIDATE_ARG_COUNT(1); + + r_ret = JSON::print(*p_args[0]); + } break; case HASH: { VALIDATE_ARG_COUNT(1); @@ -1053,6 +1118,36 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va r_ret=color; } break; + case COLORN: { + + if (p_arg_count<1) { + r_error.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; + r_error.argument=1; + r_ret=Variant(); + return; + } + + if (p_arg_count>2) { + r_error.error=Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; + r_error.argument=2; + r_ret=Variant(); + return; + } + + if (p_args[0]->get_type()!=Variant::STRING) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=0; + r_ret=Variant(); + } else { + Color color = Color::named(*p_args[0]); + if (p_arg_count==2) { + VALIDATE_ARG_NUM(1); + color.a=*p_args[1]; + } + r_ret=color; + } + + } break; case PRINT_STACK: { @@ -1133,6 +1228,7 @@ bool GDFunctions::is_deterministic(Function p_func) { case TYPE_CONVERT: case TYPE_OF: case TYPE_EXISTS: + case TEXT_CHAR: case TEXT_STR: case COLOR8: // enable for debug only, otherwise not desirable - case GEN_RANGE: @@ -1403,6 +1499,13 @@ MethodInfo GDFunctions::get_info(Function p_func) { return mi; } break; + case TEXT_CHAR: { + + MethodInfo mi("char",PropertyInfo(Variant::INT,"ascii")); + mi.return_val.type=Variant::STRING; + return mi; + + } break; case TEXT_STR: { MethodInfo mi("str",PropertyInfo(Variant::NIL,"what"),PropertyInfo(Variant::NIL,"...")); @@ -1459,13 +1562,13 @@ MethodInfo GDFunctions::get_info(Function p_func) { } break; case VAR_TO_BYTES: { MethodInfo mi("var2bytes",PropertyInfo(Variant::NIL,"var")); - mi.return_val.type=Variant::RAW_ARRAY; + mi.return_val.type=Variant::POOL_BYTE_ARRAY; return mi; } break; case BYTES_TO_VAR: { - MethodInfo mi("bytes2var:Variant",PropertyInfo(Variant::RAW_ARRAY,"bytes")); + MethodInfo mi("bytes2var:Variant",PropertyInfo(Variant::POOL_BYTE_ARRAY,"bytes")); mi.return_val.type=Variant::NIL; return mi; } break; @@ -1494,6 +1597,24 @@ MethodInfo GDFunctions::get_info(Function p_func) { mi.return_val.type=Variant::OBJECT; return mi; } break; + case VALIDATE_JSON: { + + MethodInfo mi("validate_json:Variant",PropertyInfo(Variant::STRING,"json")); + mi.return_val.type=Variant::STRING; + return mi; + } break; + case PARSE_JSON: { + + MethodInfo mi("parse_json:Variant",PropertyInfo(Variant::STRING,"json")); + mi.return_val.type=Variant::NIL; + return mi; + } break; + case TO_JSON: { + + MethodInfo mi("to_json",PropertyInfo(Variant::NIL,"var:Variant")); + mi.return_val.type=Variant::STRING; + return mi; + } break; case HASH: { MethodInfo mi("hash",PropertyInfo(Variant::NIL,"var:Variant")); @@ -1506,6 +1627,12 @@ MethodInfo GDFunctions::get_info(Function p_func) { mi.return_val.type=Variant::COLOR; return mi; } break; + case COLORN: { + + MethodInfo mi("ColorN",PropertyInfo(Variant::STRING,"name"),PropertyInfo(Variant::REAL,"alpha")); + mi.return_val.type=Variant::COLOR; + return mi; + } break; case PRINT_STACK: { MethodInfo mi("print_stack"); diff --git a/modules/gdscript/gd_functions.h b/modules/gdscript/gd_functions.h index c78956fe20..6e30b4dbb5 100644 --- a/modules/gdscript/gd_functions.h +++ b/modules/gdscript/gd_functions.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -82,6 +82,7 @@ public: TYPE_CONVERT, TYPE_OF, TYPE_EXISTS, + TEXT_CHAR, TEXT_STR, TEXT_PRINT, TEXT_PRINT_TABBED, @@ -96,8 +97,12 @@ public: RESOURCE_LOAD, INST2DICT, DICT2INST, + VALIDATE_JSON, + PARSE_JSON, + TO_JSON, HASH, COLOR8, + COLORN, PRINT_STACK, INSTANCE_FROM_ID, FUNC_MAX diff --git a/modules/gdscript/gd_parser.cpp b/modules/gdscript/gd_parser.cpp index e5a8dc0152..350f596f71 100644 --- a/modules/gdscript/gd_parser.cpp +++ b/modules/gdscript/gd_parser.cpp @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -121,6 +121,7 @@ bool GDParser::_parse_arguments(Node* p_parent,Vector<Node*>& p_args,bool p_stat tokenizer->advance(); } else { + parenthesis ++; int argidx=0; while(true) { @@ -165,6 +166,7 @@ bool GDParser::_parse_arguments(Node* p_parent,Vector<Node*>& p_args,bool p_stat } } + parenthesis --; } return true; @@ -203,6 +205,7 @@ bool GDParser::_get_completable_identifier(CompletionType p_type,StringName& ide completion_line=tokenizer->get_token_line(); completion_block=current_block; completion_found=true; + completion_ident_is_call=false; tokenizer->advance(); if (tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER) { @@ -210,6 +213,9 @@ bool GDParser::_get_completable_identifier(CompletionType p_type,StringName& ide tokenizer->advance(); } + if (tokenizer->get_token()==GDTokenizer::TK_PARENTHESIS_OPEN) { + completion_ident_is_call=true; + } return true; } @@ -219,8 +225,8 @@ bool GDParser::_get_completable_identifier(CompletionType p_type,StringName& ide GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_allow_assign,bool p_parsing_constant) { -// Vector<Node*> expressions; -// Vector<OperatorNode::Operator> operators; + //Vector<Node*> expressions; + //Vector<OperatorNode::Operator> operators; Vector<Expression> expression; @@ -259,6 +265,98 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_ tokenizer->advance(); expr=subexpr; + } else if (tokenizer->get_token()==GDTokenizer::TK_DOLLAR) { + tokenizer->advance(); + + String path; + + bool need_identifier=true; + bool done=false; + + while(!done) { + + switch(tokenizer->get_token()) { + case GDTokenizer::TK_CURSOR: { + completion_cursor=StringName(); + completion_type=COMPLETION_GET_NODE; + completion_class=current_class; + completion_function=current_function; + completion_line=tokenizer->get_token_line(); + completion_cursor=path; + completion_argument=0; + completion_block=current_block; + completion_found=true; + tokenizer->advance(); + } break; + case GDTokenizer::TK_CONSTANT: { + + if (!need_identifier) { + done=true; + break; + } + + if (tokenizer->get_token_constant().get_type()!=Variant::STRING) { + _set_error("Expected string constant or identifier after '$' or '/'."); + return NULL; + } + + path+=String(tokenizer->get_token_constant()); + tokenizer->advance(); + need_identifier=false; + + } break; + case GDTokenizer::TK_IDENTIFIER: { + if (!need_identifier) { + done=true; + break; + } + + path+=String(tokenizer->get_token_identifier()); + tokenizer->advance(); + need_identifier=false; + + } break; + case GDTokenizer::TK_OP_DIV: { + + if (need_identifier) { + done=true; + break; + } + + path+="/"; + tokenizer->advance(); + need_identifier=true; + + } break; + default: { + done=true; + break; + } + } + } + + if (path=="") { + _set_error("Path expected after $."); + return NULL; + + } + + OperatorNode *op = alloc_node<OperatorNode>(); + op->op=OperatorNode::OP_CALL; + + op->arguments.push_back(alloc_node<SelfNode>()); + + IdentifierNode *funcname = alloc_node<IdentifierNode>(); + funcname->name="get_node"; + + op->arguments.push_back(funcname); + + ConstantNode *nodepath = alloc_node<ConstantNode>(); + nodepath->value = NodePath(StringName(path)); + op->arguments.push_back(nodepath); + + expr=op; + } else if (tokenizer->get_token()==GDTokenizer::TK_CURSOR) { tokenizer->advance(); continue; //no point in cursor in the middle of expression @@ -288,21 +386,42 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_ tokenizer->advance(); String path; + bool found_constant = false; bool valid = false; + ConstantNode *cn; + Node *subexpr = _parse_and_reduce_expression(p_parent, p_static); if (subexpr) { if (subexpr->type == Node::TYPE_CONSTANT) { - ConstantNode *cn = static_cast<ConstantNode*>(subexpr); - if (cn->value.get_type() == Variant::STRING) { - valid = true; - path = (String) cn->value; + cn = static_cast<ConstantNode*>(subexpr); + found_constant = true; + } + if (subexpr->type == Node::TYPE_IDENTIFIER) { + IdentifierNode *in = static_cast<IdentifierNode*>(subexpr); + Vector<ClassNode::Constant> ce = current_class->constant_expressions; + + // Try to find the constant expression by the identifier + for(int i=0; i < ce.size(); ++i){ + if(ce[i].identifier == in->name) { + if(ce[i].expression->type == Node::TYPE_CONSTANT) { + cn = static_cast<ConstantNode*>(ce[i].expression); + found_constant = true; + } + } } } + + if (found_constant && cn->value.get_type() == Variant::STRING) { + valid = true; + path = (String) cn->value; + } } + if (!valid) { _set_error("expected string constant as 'preload' argument."); return NULL; } + if (!path.is_abs_path() && base_path!="") path=base_path+"/"+path; path = path.replace("///","//").simplify_path(); @@ -360,18 +479,23 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_ OperatorNode *yield = alloc_node<OperatorNode>(); yield->op=OperatorNode::OP_YIELD; + while (tokenizer->get_token()==GDTokenizer::TK_NEWLINE) { + tokenizer->advance(); + } + if (tokenizer->get_token()==GDTokenizer::TK_PARENTHESIS_CLOSE) { expr=yield; tokenizer->advance(); } else { + parenthesis ++; + Node *object = _parse_and_reduce_expression(p_parent,p_static); if (!object) return NULL; yield->arguments.push_back(object); if (tokenizer->get_token()!=GDTokenizer::TK_COMMA) { - _set_error("Expected ',' after first argument of 'yield'"); return NULL; } @@ -399,11 +523,12 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_ yield->arguments.push_back(signal); if (tokenizer->get_token()!=GDTokenizer::TK_PARENTHESIS_CLOSE) { - _set_error("Expected ')' after second argument of 'yield'"); return NULL; } + parenthesis --; + tokenizer->advance(); expr=yield; @@ -528,17 +653,18 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_ expr = id; } - } else if (/*tokenizer->get_token()==GDTokenizer::TK_OP_ADD ||*/ tokenizer->get_token()==GDTokenizer::TK_OP_SUB || tokenizer->get_token()==GDTokenizer::TK_OP_NOT || tokenizer->get_token()==GDTokenizer::TK_OP_BIT_INVERT) { + } else if (tokenizer->get_token()==GDTokenizer::TK_OP_ADD || tokenizer->get_token()==GDTokenizer::TK_OP_SUB || tokenizer->get_token()==GDTokenizer::TK_OP_NOT || tokenizer->get_token()==GDTokenizer::TK_OP_BIT_INVERT) { - //single prefix operators like !expr -expr ++expr --expr + //single prefix operators like !expr +expr -expr ++expr --expr alloc_node<OperatorNode>(); Expression e; e.is_op=true; switch(tokenizer->get_token()) { + case GDTokenizer::TK_OP_ADD: e.op=OperatorNode::OP_POS; break; case GDTokenizer::TK_OP_SUB: e.op=OperatorNode::OP_NEG; break; case GDTokenizer::TK_OP_NOT: e.op=OperatorNode::OP_NOT; break; - case GDTokenizer::TK_OP_BIT_INVERT: e.op=OperatorNode::OP_BIT_INVERT;; break; + case GDTokenizer::TK_OP_BIT_INVERT: e.op=OperatorNode::OP_BIT_INVERT; break; default: {} } @@ -619,6 +745,7 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_ }; Node *key=NULL; + Set<Variant> keys; DictExpect expecting=DICT_EXPECT_KEY; @@ -714,6 +841,16 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_ return NULL; expecting=DICT_EXPECT_COMMA; + if (key->type == GDParser::Node::TYPE_CONSTANT) { + Variant const& keyName = static_cast<const GDParser::ConstantNode*>(key)->value; + + if (keys.has(keyName)) { + _set_error("Duplicate key found in Dictionary literal"); + return NULL; + } + keys.insert(keyName); + } + DictionaryNode::Pair pair; pair.key=key; pair.value=value; @@ -927,8 +1064,8 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_ case GDTokenizer::TK_OP_ASSIGN_MUL: _VALIDATE_ASSIGN op=OperatorNode::OP_ASSIGN_MUL ; break; case GDTokenizer::TK_OP_ASSIGN_DIV: _VALIDATE_ASSIGN op=OperatorNode::OP_ASSIGN_DIV ; break; case GDTokenizer::TK_OP_ASSIGN_MOD: _VALIDATE_ASSIGN op=OperatorNode::OP_ASSIGN_MOD ; break; - case GDTokenizer::TK_OP_ASSIGN_SHIFT_LEFT: _VALIDATE_ASSIGN op=OperatorNode::OP_ASSIGN_SHIFT_LEFT; ; break; - case GDTokenizer::TK_OP_ASSIGN_SHIFT_RIGHT: _VALIDATE_ASSIGN op=OperatorNode::OP_ASSIGN_SHIFT_RIGHT; ; break; + case GDTokenizer::TK_OP_ASSIGN_SHIFT_LEFT: _VALIDATE_ASSIGN op=OperatorNode::OP_ASSIGN_SHIFT_LEFT; break; + case GDTokenizer::TK_OP_ASSIGN_SHIFT_RIGHT: _VALIDATE_ASSIGN op=OperatorNode::OP_ASSIGN_SHIFT_RIGHT; break; case GDTokenizer::TK_OP_ASSIGN_BIT_AND: _VALIDATE_ASSIGN op=OperatorNode::OP_ASSIGN_BIT_AND ; break; case GDTokenizer::TK_OP_ASSIGN_BIT_OR: _VALIDATE_ASSIGN op=OperatorNode::OP_ASSIGN_BIT_OR ; break; case GDTokenizer::TK_OP_ASSIGN_BIT_XOR: _VALIDATE_ASSIGN op=OperatorNode::OP_ASSIGN_BIT_XOR ; break; @@ -936,6 +1073,8 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_ case GDTokenizer::TK_OP_BIT_OR: op=OperatorNode::OP_BIT_OR ; break; case GDTokenizer::TK_OP_BIT_XOR: op=OperatorNode::OP_BIT_XOR ; break; case GDTokenizer::TK_PR_EXTENDS: op=OperatorNode::OP_EXTENDS; break; + case GDTokenizer::TK_CF_IF: op=OperatorNode::OP_TERNARY_IF; break; + case GDTokenizer::TK_CF_ELSE: op=OperatorNode::OP_TERNARY_ELSE; break; default: valid=false; break; } @@ -958,6 +1097,7 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_ int next_op=-1; int min_priority=0xFFFFF; bool is_unary=false; + bool is_ternary=false; for(int i=0;i<expression.size();i++) { @@ -971,6 +1111,8 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_ int priority; bool unary=false; + bool ternary=false; + bool error=false; switch(expression[i].op) { @@ -978,6 +1120,7 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_ case OperatorNode::OP_BIT_INVERT: priority=0; unary=true; break; case OperatorNode::OP_NEG: priority=1; unary=true; break; + case OperatorNode::OP_POS: priority=1; unary=true; break; case OperatorNode::OP_MUL: priority=2; break; case OperatorNode::OP_DIV: priority=2; break; @@ -1001,25 +1144,27 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_ case OperatorNode::OP_EQUAL: priority=8; break; case OperatorNode::OP_NOT_EQUAL: priority=8; break; + case OperatorNode::OP_IN: priority=10; break; - + case OperatorNode::OP_NOT: priority=11; unary=true; break; case OperatorNode::OP_AND: priority=12; break; case OperatorNode::OP_OR: priority=13; break; - - // ?: = 10 - - case OperatorNode::OP_ASSIGN: priority=14; break; - case OperatorNode::OP_ASSIGN_ADD: priority=14; break; - case OperatorNode::OP_ASSIGN_SUB: priority=14; break; - case OperatorNode::OP_ASSIGN_MUL: priority=14; break; - case OperatorNode::OP_ASSIGN_DIV: priority=14; break; - case OperatorNode::OP_ASSIGN_MOD: priority=14; break; - case OperatorNode::OP_ASSIGN_SHIFT_LEFT: priority=14; break; - case OperatorNode::OP_ASSIGN_SHIFT_RIGHT: priority=14; break; - case OperatorNode::OP_ASSIGN_BIT_AND: priority=14; break; - case OperatorNode::OP_ASSIGN_BIT_OR: priority=14; break; - case OperatorNode::OP_ASSIGN_BIT_XOR: priority=14; break; + + case OperatorNode::OP_TERNARY_IF: priority=14; ternary=true; break; + case OperatorNode::OP_TERNARY_ELSE: priority=14; error=true; break; // Errors out when found without IF (since IF would consume it) + + case OperatorNode::OP_ASSIGN: priority=15; break; + case OperatorNode::OP_ASSIGN_ADD: priority=15; break; + case OperatorNode::OP_ASSIGN_SUB: priority=15; break; + case OperatorNode::OP_ASSIGN_MUL: priority=15; break; + case OperatorNode::OP_ASSIGN_DIV: priority=15; break; + case OperatorNode::OP_ASSIGN_MOD: priority=15; break; + case OperatorNode::OP_ASSIGN_SHIFT_LEFT: priority=15; break; + case OperatorNode::OP_ASSIGN_SHIFT_RIGHT: priority=15; break; + case OperatorNode::OP_ASSIGN_BIT_AND: priority=15; break; + case OperatorNode::OP_ASSIGN_BIT_OR: priority=15; break; + case OperatorNode::OP_ASSIGN_BIT_XOR: priority=15; break; default: { @@ -1030,11 +1175,16 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_ } if (priority<min_priority) { + if(error) { + _set_error("Unexpected operator"); + return NULL; + } // < is used for left to right (default) // <= is used for right to left next_op=i; min_priority=priority; is_unary=unary; + is_ternary=ternary; } } @@ -1075,6 +1225,62 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_ } + } else if(is_ternary) { + if (next_op <1 || next_op>=(expression.size()-1)) { + _set_error("Parser bug.."); + ERR_FAIL_V(NULL); + } + + if(next_op>=(expression.size()-2) || expression[next_op+2].op != OperatorNode::OP_TERNARY_ELSE) { + _set_error("Expected else after ternary if."); + ERR_FAIL_V(NULL); + } + if(next_op>=(expression.size()-3)) { + _set_error("Expected value after ternary else."); + ERR_FAIL_V(NULL); + } + + OperatorNode *op = alloc_node<OperatorNode>(); + op->op=expression[next_op].op; + op->line=op_line; //line might have been changed from a \n + + if (expression[next_op-1].is_op) { + + _set_error("Parser bug.."); + ERR_FAIL_V(NULL); + } + + if (expression[next_op+1].is_op) { + // this is not invalid and can really appear + // but it becomes invalid anyway because no binary op + // can be followed by an unary op in a valid combination, + // due to how precedence works, unaries will always dissapear first + + _set_error("Unexpected two consecutive operators after ternary if."); + return NULL; + } + + if (expression[next_op+3].is_op) { + // this is not invalid and can really appear + // but it becomes invalid anyway because no binary op + // can be followed by an unary op in a valid combination, + // due to how precedence works, unaries will always dissapear first + + _set_error("Unexpected two consecutive operators after ternary else."); + return NULL; + } + + + op->arguments.push_back(expression[next_op+1].node); //next expression goes as first + op->arguments.push_back(expression[next_op-1].node); //left expression goes as when-true + op->arguments.push_back(expression[next_op+3].node); //expression after next goes as when-false + + //replace all 3 nodes by this operator and make it an expression + expression[next_op-1].node=op; + expression.remove(next_op); + expression.remove(next_op); + expression.remove(next_op); + expression.remove(next_op); } else { if (next_op <1 || next_op>=(expression.size()-1)) { @@ -1143,7 +1349,7 @@ GDParser::Node* GDParser::_reduce_expression(Node *p_node,bool p_to_const) { //reduce constant array expression ConstantNode *cn = alloc_node<ConstantNode>(); - Array arr(!p_to_const); + Array arr; //print_line("mk array "+itos(!p_to_const)); arr.resize(an->elements.size()); for(int i=0;i<an->elements.size();i++) { @@ -1178,7 +1384,7 @@ GDParser::Node* GDParser::_reduce_expression(Node *p_node,bool p_to_const) { //reduce constant array expression ConstantNode *cn = alloc_node<ConstantNode>(); - Dictionary dict(!p_to_const); + Dictionary dict; for(int i=0;i<dn->elements.size();i++) { ConstantNode *key_c = static_cast<ConstantNode*>(dn->elements[i].key); ConstantNode *value_c = static_cast<ConstantNode*>(dn->elements[i].value); @@ -1396,6 +1602,15 @@ GDParser::Node* GDParser::_reduce_expression(Node *p_node,bool p_to_const) { return op; } + if (op->arguments[0]->type==Node::TYPE_OPERATOR) { + OperatorNode *on = static_cast<OperatorNode*>(op->arguments[0]); + if (on->op != OperatorNode::OP_INDEX && on->op != OperatorNode::OP_INDEX_NAMED) { + _set_error("Can't assign to an expression",tokenizer->get_token_line()-1); + error_line=op->line; + return op; + } + } + } break; default: { break; } } @@ -1432,6 +1647,7 @@ GDParser::Node* GDParser::_reduce_expression(Node *p_node,bool p_to_const) { //unary operators case OperatorNode::OP_NEG: { _REDUCE_UNARY(Variant::OP_NEGATE); } break; + case OperatorNode::OP_POS: { _REDUCE_UNARY(Variant::OP_POSITIVE); } break; case OperatorNode::OP_NOT: { _REDUCE_UNARY(Variant::OP_NOT); } break; case OperatorNode::OP_BIT_INVERT: { _REDUCE_UNARY(Variant::OP_BIT_NEGATE); } break; //binary operators (in precedence order) @@ -1495,6 +1711,541 @@ bool GDParser::_recover_from_completion() { return true; } +GDParser::PatternNode *GDParser::_parse_pattern(bool p_static) +{ + + PatternNode *pattern = alloc_node<PatternNode>(); + + GDTokenizer::Token token = tokenizer->get_token(); + if (error_set) + return NULL; + + if (token == GDTokenizer::TK_EOF) { + return NULL; + } + + switch (token) { + // array + case GDTokenizer::TK_BRACKET_OPEN: { + tokenizer->advance(); + pattern->pt_type = GDParser::PatternNode::PT_ARRAY; + while (true) { + + if (tokenizer->get_token() == GDTokenizer::TK_BRACKET_CLOSE) { + tokenizer->advance(); + break; + } + + if (tokenizer->get_token() == GDTokenizer::TK_PERIOD && tokenizer->get_token(1) == GDTokenizer::TK_PERIOD) { + // match everything + tokenizer->advance(2); + PatternNode *sub_pattern = alloc_node<PatternNode>(); + sub_pattern->pt_type = GDParser::PatternNode::PT_IGNORE_REST; + pattern->array.push_back(sub_pattern); + if (tokenizer->get_token() == GDTokenizer::TK_COMMA && tokenizer->get_token(1) == GDTokenizer::TK_BRACKET_CLOSE) { + tokenizer->advance(2); + break; + } else if (tokenizer->get_token() == GDTokenizer::TK_BRACKET_CLOSE) { + tokenizer->advance(1); + break; + } else { + _set_error("'..' pattern only allowed at the end of an array pattern"); + return NULL; + } + } + + PatternNode *sub_pattern = _parse_pattern(p_static); + if (!sub_pattern) { + return NULL; + } + + pattern->array.push_back(sub_pattern); + + if (tokenizer->get_token() == GDTokenizer::TK_COMMA) { + tokenizer->advance(); + continue; + } else if (tokenizer->get_token() == GDTokenizer::TK_BRACKET_CLOSE) { + tokenizer->advance(); + break; + } else { + _set_error("Not a valid pattern"); + return NULL; + } + } + } break; + // bind + case GDTokenizer::TK_PR_VAR: { + tokenizer->advance(); + pattern->pt_type = GDParser::PatternNode::PT_BIND; + pattern->bind = tokenizer->get_token_identifier(); + tokenizer->advance(); + } break; + // dictionary + case GDTokenizer::TK_CURLY_BRACKET_OPEN: { + tokenizer->advance(); + pattern->pt_type = GDParser::PatternNode::PT_DICTIONARY; + while (true) { + + if (tokenizer->get_token() == GDTokenizer::TK_CURLY_BRACKET_CLOSE) { + tokenizer->advance(); + break; + } + + if (tokenizer->get_token() == GDTokenizer::TK_PERIOD && tokenizer->get_token(1) == GDTokenizer::TK_PERIOD) { + // match everything + tokenizer->advance(2); + PatternNode *sub_pattern = alloc_node<PatternNode>(); + sub_pattern->pt_type = PatternNode::PT_IGNORE_REST; + pattern->array.push_back(sub_pattern); + if (tokenizer->get_token() == GDTokenizer::TK_COMMA && tokenizer->get_token(1) == GDTokenizer::TK_CURLY_BRACKET_CLOSE) { + tokenizer->advance(2); + break; + } else if (tokenizer->get_token() == GDTokenizer::TK_CURLY_BRACKET_CLOSE) { + tokenizer->advance(1); + break; + } else { + _set_error("'..' pattern only allowed at the end of an dictionary pattern"); + return NULL; + } + } + + Node *key = _parse_and_reduce_expression(pattern, p_static); + if (!key) { + _set_error("Not a valid key in pattern"); + return NULL; + } + + if (key->type != GDParser::Node::TYPE_CONSTANT) { + _set_error("Not a constant expression as key"); + return NULL; + } + + if (tokenizer->get_token() == GDTokenizer::TK_COLON) { + tokenizer->advance(); + + PatternNode *value = _parse_pattern(p_static); + if (!value) { + _set_error("Expected pattern in dictionary value"); + return NULL; + } + + pattern->dictionary.insert(static_cast<ConstantNode*>(key), value); + } else { + pattern->dictionary.insert(static_cast<ConstantNode*>(key), NULL); + } + + + if (tokenizer->get_token() == GDTokenizer::TK_COMMA) { + tokenizer->advance(); + continue; + } else if (tokenizer->get_token() == GDTokenizer::TK_CURLY_BRACKET_CLOSE) { + tokenizer->advance(); + break; + } else { + _set_error("Not a valid pattern"); + return NULL; + } + } + } break; + case GDTokenizer::TK_WILDCARD: { + tokenizer->advance(); + pattern->pt_type = PatternNode::PT_WILDCARD; + } break; + // all the constants like strings and numbers + default: { + Node *value = _parse_and_reduce_expression(pattern, p_static); + if (error_set) { + return NULL; + } + + if (value->type != Node::TYPE_IDENTIFIER && value->type != Node::TYPE_CONSTANT) { + _set_error("Only constant expressions or variables allowed in a pattern"); + return NULL; + } + + pattern->pt_type = PatternNode::PT_CONSTANT; + pattern->constant = value; + } break; + } + + return pattern; +} + +void GDParser::_parse_pattern_block(BlockNode *p_block, Vector<PatternBranchNode*> &p_branches, bool p_static) +{ + int indent_level = tab_level.back()->get(); + + while (true) { + + while (tokenizer->get_token() == GDTokenizer::TK_NEWLINE && _parse_newline()); + + // GDTokenizer::Token token = tokenizer->get_token(); + if (error_set) + return; + + if (indent_level > tab_level.back()->get()) { + return; // go back a level + } + + if (pending_newline!=-1) { + pending_newline=-1; + } + + PatternBranchNode *branch = alloc_node<PatternBranchNode>(); + + branch->patterns.push_back(_parse_pattern(p_static)); + if (!branch->patterns[0]) { + return; + } + + while (tokenizer->get_token() == GDTokenizer::TK_COMMA) { + tokenizer->advance(); + branch->patterns.push_back(_parse_pattern(p_static)); + if (!branch->patterns[branch->patterns.size() - 1]) { + return; + } + } + + if(!_enter_indent_block()) { + _set_error("Expected block in pattern branch"); + return; + } + + branch->body = alloc_node<BlockNode>(); + branch->body->parent_block = p_block; + p_block->sub_blocks.push_back(branch->body); + current_block = branch->body; + + _parse_block(branch->body, p_static); + + current_block = p_block; + + p_branches.push_back(branch); + } +} + + +void GDParser::_generate_pattern(PatternNode *p_pattern, Node *p_node_to_match, Node *&p_resulting_node, Map<StringName, Node*> &p_bindings) +{ + switch (p_pattern->pt_type) { + case PatternNode::PT_CONSTANT: { + + // typecheck + BuiltInFunctionNode *typeof_node = alloc_node<BuiltInFunctionNode>(); + typeof_node->function = GDFunctions::TYPE_OF; + + OperatorNode *typeof_match_value = alloc_node<OperatorNode>(); + typeof_match_value->op = OperatorNode::OP_CALL; + typeof_match_value->arguments.push_back(typeof_node); + typeof_match_value->arguments.push_back(p_node_to_match); + + OperatorNode *typeof_pattern_value = alloc_node<OperatorNode>(); + typeof_pattern_value->op = OperatorNode::OP_CALL; + typeof_pattern_value->arguments.push_back(typeof_node); + typeof_pattern_value->arguments.push_back(p_pattern->constant); + + OperatorNode *type_comp = alloc_node<OperatorNode>(); + type_comp->op = OperatorNode::OP_EQUAL; + type_comp->arguments.push_back(typeof_match_value); + type_comp->arguments.push_back(typeof_pattern_value); + + + // comare the actual values + OperatorNode *value_comp = alloc_node<OperatorNode>(); + value_comp->op = OperatorNode::OP_EQUAL; + value_comp->arguments.push_back(p_pattern->constant); + value_comp->arguments.push_back(p_node_to_match); + + + OperatorNode *comparison = alloc_node<OperatorNode>(); + comparison->op = OperatorNode::OP_AND; + comparison->arguments.push_back(type_comp); + comparison->arguments.push_back(value_comp); + + p_resulting_node = comparison; + + } break; + case PatternNode::PT_BIND: { + p_bindings[p_pattern->bind] = p_node_to_match; + + // a bind always matches + ConstantNode *true_value = alloc_node<ConstantNode>(); + true_value->value = Variant(true); + p_resulting_node = true_value; + } break; + case PatternNode::PT_ARRAY: { + + bool open_ended = false; + + if (p_pattern->array.size() > 0) { + if (p_pattern->array[p_pattern->array.size() - 1]->pt_type == PatternNode::PT_IGNORE_REST) { + open_ended = true; + } + } + + // typeof(value_to_match) == TYPE_ARRAY && value_to_match.size() >= length + // typeof(value_to_match) == TYPE_ARRAY && value_to_match.size() == length + + { + // typecheck + BuiltInFunctionNode *typeof_node = alloc_node<BuiltInFunctionNode>(); + typeof_node->function = GDFunctions::TYPE_OF; + + OperatorNode *typeof_match_value = alloc_node<OperatorNode>(); + typeof_match_value->op = OperatorNode::OP_CALL; + typeof_match_value->arguments.push_back(typeof_node); + typeof_match_value->arguments.push_back(p_node_to_match); + + IdentifierNode *typeof_array = alloc_node<IdentifierNode>(); + typeof_array->name = "TYPE_ARRAY"; + + OperatorNode *type_comp = alloc_node<OperatorNode>(); + type_comp->op = OperatorNode::OP_EQUAL; + type_comp->arguments.push_back(typeof_match_value); + type_comp->arguments.push_back(typeof_array); + + + // size + ConstantNode *length = alloc_node<ConstantNode>(); + length->value = Variant(open_ended ? p_pattern->array.size() - 1 : p_pattern->array.size()); + + OperatorNode *call = alloc_node<OperatorNode>(); + call->op = OperatorNode::OP_CALL; + call->arguments.push_back(p_node_to_match); + + IdentifierNode *size = alloc_node<IdentifierNode>(); + size->name = "size"; + call->arguments.push_back(size); + + OperatorNode *length_comparison = alloc_node<OperatorNode>(); + length_comparison->op = open_ended ? OperatorNode::OP_GREATER_EQUAL : OperatorNode::OP_EQUAL; + length_comparison->arguments.push_back(call); + length_comparison->arguments.push_back(length); + + OperatorNode *type_and_length_comparison = alloc_node<OperatorNode>(); + type_and_length_comparison->op = OperatorNode::OP_AND; + type_and_length_comparison->arguments.push_back(type_comp); + type_and_length_comparison->arguments.push_back(length_comparison); + + p_resulting_node = type_and_length_comparison; + } + + + + for (int i = 0; i < p_pattern->array.size(); i++) { + PatternNode *pattern = p_pattern->array[i]; + + Node *condition = NULL; + + ConstantNode *index = alloc_node<ConstantNode>(); + index->value = Variant(i); + + OperatorNode *indexed_value = alloc_node<OperatorNode>(); + indexed_value->op = OperatorNode::OP_INDEX; + indexed_value->arguments.push_back(p_node_to_match); + indexed_value->arguments.push_back(index); + + _generate_pattern(pattern, indexed_value, condition, p_bindings); + + // concatenate all the patterns with && + OperatorNode *and_node = alloc_node<OperatorNode>(); + and_node->op = OperatorNode::OP_AND; + and_node->arguments.push_back(p_resulting_node); + and_node->arguments.push_back(condition); + + p_resulting_node = and_node; + } + + + } break; + case PatternNode::PT_DICTIONARY: { + + bool open_ended = false; + + if (p_pattern->array.size() > 0) { + open_ended = true; + } + + // typeof(value_to_match) == TYPE_DICTIONARY && value_to_match.size() >= length + // typeof(value_to_match) == TYPE_DICTIONARY && value_to_match.size() == length + + + { + // typecheck + BuiltInFunctionNode *typeof_node = alloc_node<BuiltInFunctionNode>(); + typeof_node->function = GDFunctions::TYPE_OF; + + OperatorNode *typeof_match_value = alloc_node<OperatorNode>(); + typeof_match_value->op = OperatorNode::OP_CALL; + typeof_match_value->arguments.push_back(typeof_node); + typeof_match_value->arguments.push_back(p_node_to_match); + + IdentifierNode *typeof_dictionary = alloc_node<IdentifierNode>(); + typeof_dictionary->name = "TYPE_DICTIONARY"; + + OperatorNode *type_comp = alloc_node<OperatorNode>(); + type_comp->op = OperatorNode::OP_EQUAL; + type_comp->arguments.push_back(typeof_match_value); + type_comp->arguments.push_back(typeof_dictionary); + + // size + ConstantNode *length = alloc_node<ConstantNode>(); + length->value = Variant(open_ended ? p_pattern->dictionary.size() - 1 : p_pattern->dictionary.size()); + + OperatorNode *call = alloc_node<OperatorNode>(); + call->op = OperatorNode::OP_CALL; + call->arguments.push_back(p_node_to_match); + + IdentifierNode *size = alloc_node<IdentifierNode>(); + size->name = "size"; + call->arguments.push_back(size); + + OperatorNode *length_comparison = alloc_node<OperatorNode>(); + length_comparison->op = open_ended ? OperatorNode::OP_GREATER_EQUAL : OperatorNode::OP_EQUAL; + length_comparison->arguments.push_back(call); + length_comparison->arguments.push_back(length); + + OperatorNode *type_and_length_comparison = alloc_node<OperatorNode>(); + type_and_length_comparison->op = OperatorNode::OP_AND; + type_and_length_comparison->arguments.push_back(type_comp); + type_and_length_comparison->arguments.push_back(length_comparison); + + p_resulting_node = type_and_length_comparison; + } + + + + for (Map<ConstantNode*, PatternNode*>::Element *e = p_pattern->dictionary.front(); e; e = e->next()) { + + Node *condition = NULL; + + // chech for has, then for pattern + + IdentifierNode *has = alloc_node<IdentifierNode>(); + has->name = "has"; + + OperatorNode *has_call = alloc_node<OperatorNode>(); + has_call->op = OperatorNode::OP_CALL; + has_call->arguments.push_back(p_node_to_match); + has_call->arguments.push_back(has); + has_call->arguments.push_back(e->key()); + + + if (e->value()) { + + OperatorNode *indexed_value = alloc_node<OperatorNode>(); + indexed_value->op = OperatorNode::OP_INDEX; + indexed_value->arguments.push_back(p_node_to_match); + indexed_value->arguments.push_back(e->key()); + + _generate_pattern(e->value(), indexed_value, condition, p_bindings); + + OperatorNode *has_and_pattern = alloc_node<OperatorNode>(); + has_and_pattern->op = OperatorNode::OP_AND; + has_and_pattern->arguments.push_back(has_call); + has_and_pattern->arguments.push_back(condition); + + condition = has_and_pattern; + + } else { + condition = has_call; + } + + + + // concatenate all the patterns with && + OperatorNode *and_node = alloc_node<OperatorNode>(); + and_node->op = OperatorNode::OP_AND; + and_node->arguments.push_back(p_resulting_node); + and_node->arguments.push_back(condition); + + p_resulting_node = and_node; + } + + } break; + case PatternNode::PT_IGNORE_REST: + case PatternNode::PT_WILDCARD: { + // simply generate a `true` + ConstantNode *true_value = alloc_node<ConstantNode>(); + true_value->value = Variant(true); + p_resulting_node = true_value; + } break; + default: { + + } break; + } +} + +void GDParser::_transform_match_statment(BlockNode *p_block, MatchNode *p_match_statement) +{ + IdentifierNode *id = alloc_node<IdentifierNode>(); + id->name = "#match_value"; + + for (int i = 0; i < p_match_statement->branches.size(); i++) { + + PatternBranchNode *branch = p_match_statement->branches[i]; + + MatchNode::CompiledPatternBranch compiled_branch; + compiled_branch.compiled_pattern = NULL; + + Map<StringName, Node*> binding; + + for (int j = 0; j < branch->patterns.size(); j++) { + PatternNode *pattern = branch->patterns[j]; + + Map<StringName, Node*> bindings; + Node *resulting_node; + _generate_pattern(pattern, id, resulting_node, bindings); + + if (!binding.empty() && !bindings.empty()) { + _set_error("Multipatterns can't contain bindings"); + return; + } else { + binding = bindings; + } + + if (compiled_branch.compiled_pattern) { + OperatorNode *or_node = alloc_node<OperatorNode>(); + or_node->op = OperatorNode::OP_OR; + or_node->arguments.push_back(compiled_branch.compiled_pattern); + or_node->arguments.push_back(resulting_node); + + compiled_branch.compiled_pattern = or_node; + } else { + // single pattern | first one + compiled_branch.compiled_pattern = resulting_node; + } + + } + + + // prepare the body ...hehe + for (Map<StringName, Node*>::Element *e = binding.front(); e; e = e->next()) { + LocalVarNode *local_var = alloc_node<LocalVarNode>(); + local_var->name = e->key(); + local_var->assign = e->value(); + + + IdentifierNode *id = alloc_node<IdentifierNode>(); + id->name = local_var->name; + + OperatorNode *op = alloc_node<OperatorNode>(); + op->op=OperatorNode::OP_ASSIGN; + op->arguments.push_back(id); + op->arguments.push_back(local_var->assign); + + branch->body->statements.push_front(op); + branch->body->statements.push_front(local_var); + } + + compiled_branch.body = branch->body; + + + p_match_statement->compiled_pattern_branches.push_back(compiled_branch); + } + +} + void GDParser::_parse_block(BlockNode *p_block,bool p_static) { int indent_level = tab_level.back()->get(); @@ -1578,6 +2329,24 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) { } StringName n = tokenizer->get_token_identifier(); tokenizer->advance(); + if (current_function){ + for (int i=0;i<current_function->arguments.size();i++){ + if (n == current_function->arguments[i]){ + _set_error("Variable '"+String(n)+"' already defined in the scope (at line: "+itos(current_function->line)+")."); + return; + } + } + } + BlockNode *check_block = p_block; + while (check_block){ + for (int i=0;i<check_block->variables.size();i++){ + if (n == check_block->variables[i]){ + _set_error("Variable '"+String(n)+"' already defined in the scope (at line: "+itos(check_block->variable_lines[i])+")."); + return; + } + } + check_block = check_block->parent_block; + } p_block->variables.push_back(n); //line? p_block->variable_lines.push_back(tokenizer->get_token_line()); @@ -1633,6 +2402,7 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) { case GDTokenizer::TK_CF_IF: { tokenizer->advance(); + Node *condition = _parse_and_reduce_expression(p_block,p_static); if (!condition) { if (_recover_from_completion()) { @@ -1819,6 +2589,65 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) { return; } + if (container->type==Node::TYPE_OPERATOR) { + + OperatorNode* op = static_cast<OperatorNode*>(container); + if (op->op==OperatorNode::OP_CALL && op->arguments[0]->type==Node::TYPE_BUILT_IN_FUNCTION && static_cast<BuiltInFunctionNode*>(op->arguments[0])->function==GDFunctions::GEN_RANGE) { + //iterating a range, so see if range() can be optimized without allocating memory, by replacing it by vectors (which can work as iterable too!) + + Vector<Node*> args; + Vector<double> constants; + + bool constant=false; + + for(int i=1;i<op->arguments.size();i++) { + args.push_back(op->arguments[i]); + if (constant && op->arguments[i]->type==Node::TYPE_CONSTANT) { + ConstantNode *c = static_cast<ConstantNode*>(op->arguments[i]); + if (c->value.get_type()==Variant::REAL || c->value.get_type()==Variant::INT) { + constants.push_back(c->value); + constant=true; + } + } else { + constant=false; + } + } + + if (args.size()>0 && args.size()<4) { + + if (constant) { + + ConstantNode *cn = alloc_node<ConstantNode>(); + switch(args.size()) { + case 1: cn->value=constants[0]; break; + case 2: cn->value=Vector2(constants[0],constants[1]); break; + case 3: cn->value=Vector3(constants[0],constants[1],constants[2]); break; + } + container=cn; + } else { + OperatorNode *on = alloc_node<OperatorNode>(); + on->op=OperatorNode::OP_CALL; + + TypeNode *tn = alloc_node<TypeNode>(); + on->arguments.push_back(tn); + + switch(args.size()) { + case 1: tn->vtype=Variant::REAL; break; + case 2: tn->vtype=Variant::VECTOR2; break; + case 3: tn->vtype=Variant::VECTOR3; break; + } + + for(int i=0;i<args.size();i++) { + on->arguments.push_back(args[i]); + } + + container=on; + } + } + } + + } + ControlFlowNode *cf_for = alloc_node<ControlFlowNode>(); cf_for->cf_type=ControlFlowNode::CF_FOR; @@ -1836,7 +2665,14 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) { } current_block=cf_for->body; + + // this is for checking variable for redefining + // inside this _parse_block + cf_for->body->variables.push_back(id->name); + cf_for->body->variable_lines.push_back(id->line); _parse_block(cf_for->body,p_static); + cf_for->body->variables.remove(0); + cf_for->body->variable_lines.remove(0); current_block=p_block; if (error_set) @@ -1898,6 +2734,46 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) { } break; + case GDTokenizer::TK_CF_MATCH: { + + tokenizer->advance(); + + MatchNode *match_node = alloc_node<MatchNode>(); + + Node *val_to_match = _parse_and_reduce_expression(p_block, p_static); + + if (!val_to_match) { + if (_recover_from_completion()) { + break; + } + return; + } + + match_node->val_to_match = val_to_match; + + if (!_enter_indent_block()) { + _set_error("Expected indented pattern matching block after 'match'"); + return; + } + + BlockNode *compiled_branches = alloc_node<BlockNode>(); + compiled_branches->parent_block = p_block; + compiled_branches->parent_class = p_block->parent_class; + + p_block->sub_blocks.push_back(compiled_branches); + + _parse_pattern_block(compiled_branches, match_node->branches, p_static); + + _transform_match_statment(compiled_branches, match_node); + + ControlFlowNode *match_cf_node = alloc_node<ControlFlowNode>(); + match_cf_node->cf_type = ControlFlowNode::CF_MATCH; + match_cf_node->match = match_node; + + p_block->statements.push_back(match_cf_node); + + _end_statement(); + } break; case GDTokenizer::TK_PR_ASSERT: { tokenizer->advance(); @@ -2233,6 +3109,11 @@ void GDParser::_parse_class(ClassNode *p_class) { bool defaulting=false; while(true) { + if (tokenizer->get_token()==GDTokenizer::TK_NEWLINE) { + tokenizer->advance(); + continue; + } + if (tokenizer->get_token()==GDTokenizer::TK_PR_VAR) { tokenizer->advance(); //var before the identifier is allowed @@ -2285,6 +3166,10 @@ void GDParser::_parse_class(ClassNode *p_class) { default_values.push_back(on); } + while (tokenizer->get_token()==GDTokenizer::TK_NEWLINE) { + tokenizer->advance(); + } + if (tokenizer->get_token()==GDTokenizer::TK_COMMA) { tokenizer->advance(); continue; @@ -2326,6 +3211,7 @@ void GDParser::_parse_class(ClassNode *p_class) { if (tokenizer->get_token()!=GDTokenizer::TK_PARENTHESIS_CLOSE) { //has arguments + parenthesis ++; while(true) { Node *arg = _parse_and_reduce_expression(p_class,_static); @@ -2343,6 +3229,7 @@ void GDParser::_parse_class(ClassNode *p_class) { break; } + parenthesis --; } tokenizer->advance(); @@ -2406,6 +3293,10 @@ void GDParser::_parse_class(ClassNode *p_class) { if (tokenizer->get_token()==GDTokenizer::TK_PARENTHESIS_OPEN) { tokenizer->advance(); while(true) { + if (tokenizer->get_token()==GDTokenizer::TK_NEWLINE) { + tokenizer->advance(); + continue; + } if (tokenizer->get_token()==GDTokenizer::TK_PARENTHESIS_CLOSE) { @@ -2421,6 +3312,10 @@ void GDParser::_parse_class(ClassNode *p_class) { sig.arguments.push_back(tokenizer->get_token_identifier()); tokenizer->advance(); + while (tokenizer->get_token()==GDTokenizer::TK_NEWLINE) { + tokenizer->advance(); + } + if (tokenizer->get_token()==GDTokenizer::TK_COMMA) { tokenizer->advance(); } else if (tokenizer->get_token()!=GDTokenizer::TK_PARENTHESIS_CLOSE) { @@ -2454,17 +3349,41 @@ void GDParser::_parse_class(ClassNode *p_class) { current_export.type=type; current_export.usage|=PROPERTY_USAGE_SCRIPT_VARIABLE; tokenizer->advance(); + + String hint_prefix =""; + + if(type == Variant::ARRAY && tokenizer->get_token()==GDTokenizer::TK_COMMA) { + tokenizer->advance(); + + while(tokenizer->get_token()==GDTokenizer::TK_BUILT_IN_TYPE) { + type = tokenizer->get_token_type(); + + tokenizer->advance(); + + if(type == Variant::ARRAY) { + hint_prefix += itos(Variant::ARRAY)+":"; + if (tokenizer->get_token()==GDTokenizer::TK_COMMA) { + tokenizer->advance(); + } + } else { + hint_prefix += itos(type); + break; + } + } + } + if (tokenizer->get_token()==GDTokenizer::TK_COMMA) { // hint expected next! tokenizer->advance(); - switch(current_export.type) { + + switch(type) { case Variant::INT: { if (tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier()=="FLAGS") { - current_export.hint=PROPERTY_HINT_ALL_FLAGS; + //current_export.hint=PROPERTY_HINT_ALL_FLAGS; tokenizer->advance(); if (tokenizer->get_token()==GDTokenizer::TK_PARENTHESIS_CLOSE) { @@ -2813,13 +3732,20 @@ void GDParser::_parse_class(ClassNode *p_class) { return; } break; } - + + } + if(current_export.type == Variant::ARRAY && !hint_prefix.empty()) { + if(current_export.hint) { + hint_prefix += "/"+itos(current_export.hint); + } + current_export.hint_string=hint_prefix+":"+current_export.hint_string; + current_export.hint=PROPERTY_HINT_NONE; } } else if (tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER) { String identifier = tokenizer->get_token_identifier(); - if (!ObjectTypeDB::is_type(identifier,"Resource")) { + if (!ClassDB::is_parent_class(identifier,"Resource")) { current_export=PropertyInfo(); _set_error("Export hint not a type or resource."); @@ -3029,6 +3955,16 @@ void GDParser::_parse_class(ClassNode *p_class) { } member._export.type=cn->value.get_type(); member._export.usage|=PROPERTY_USAGE_SCRIPT_VARIABLE; + if (cn->value.get_type()==Variant::OBJECT) { + Object *obj = cn->value; + Resource *res = obj->cast_to<Resource>(); + if(res==NULL) { + _set_error("Exported constant not a type or resource."); + return; + } + member._export.hint=PROPERTY_HINT_RESOURCE_TYPE; + member._export.hint_string=res->get_class(); + } } } #ifdef TOOLS_ENABLED @@ -3157,7 +4093,124 @@ void GDParser::_parse_class(ClassNode *p_class) { } } break; + case GDTokenizer::TK_PR_ENUM: { + //mutiple constant declarations.. + int last_assign = -1; // Incremented by 1 right before the assingment. + String enum_name; + Dictionary enum_dict; + + tokenizer->advance(); + if (tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER) { + enum_name=tokenizer->get_token_identifier(); + tokenizer->advance(); + } + if (tokenizer->get_token()!=GDTokenizer::TK_CURLY_BRACKET_OPEN) { + _set_error("Expected '{' in enum declaration"); + return; + } + tokenizer->advance(); + + while(true) { + if(tokenizer->get_token()==GDTokenizer::TK_NEWLINE) { + + tokenizer->advance(); // Ignore newlines + } else if (tokenizer->get_token()==GDTokenizer::TK_CURLY_BRACKET_CLOSE) { + + tokenizer->advance(); + break; // End of enum + } else if (tokenizer->get_token()!=GDTokenizer::TK_IDENTIFIER) { + + if(tokenizer->get_token()==GDTokenizer::TK_EOF) { + _set_error("Unexpected end of file."); + } else { + _set_error(String("Unexpected ") + GDTokenizer::get_token_name(tokenizer->get_token()) + ", expected identifier"); + } + + return; + } else { // tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER + ClassNode::Constant constant; + + constant.identifier=tokenizer->get_token_identifier(); + + tokenizer->advance(); + + if (tokenizer->get_token()==GDTokenizer::TK_OP_ASSIGN) { + tokenizer->advance(); + + Node *subexpr=NULL; + + subexpr = _parse_and_reduce_expression(p_class,true,true); + if (!subexpr) { + if (_recover_from_completion()) { + break; + } + return; + } + + if (subexpr->type!=Node::TYPE_CONSTANT) { + _set_error("Expected constant expression"); + } + + const ConstantNode *subexpr_const = static_cast<const ConstantNode*>(subexpr); + + if(subexpr_const->value.get_type() != Variant::INT) { + _set_error("Expected an int value for enum"); + } + + last_assign = subexpr_const->value; + + constant.expression=subexpr; + + } else { + last_assign = last_assign + 1; + ConstantNode *cn = alloc_node<ConstantNode>(); + cn->value = last_assign; + constant.expression = cn; + } + + if(tokenizer->get_token()==GDTokenizer::TK_COMMA) { + tokenizer->advance(); + } + + if(enum_name != "") { + const ConstantNode *cn = static_cast<const ConstantNode*>(constant.expression); + enum_dict[constant.identifier] = cn->value; + } + + p_class->constant_expressions.push_back(constant); + } + + } + + if(enum_name != "") { + ClassNode::Constant enum_constant; + enum_constant.identifier=enum_name; + ConstantNode *cn = alloc_node<ConstantNode>(); + cn->value = enum_dict; + enum_constant.expression=cn; + p_class->constant_expressions.push_back(enum_constant); + } + + if (!_end_statement()) { + _set_error("Expected end of statement (enum)"); + return; + } + + + + + } break; + + case GDTokenizer::TK_CONSTANT: { + if(tokenizer->get_token_constant().get_type() == Variant::STRING) { + tokenizer->advance(); + // Ignore + } else { + _set_error(String()+"Unexpected constant of type: "+Variant::get_type_name(tokenizer->get_token_constant().get_type())); + return; + } + } break; default: { @@ -3376,6 +4429,11 @@ int GDParser::get_completion_argument_index() { return completion_argument; } +int GDParser::get_completion_identifier_is_function() { + + return completion_ident_is_call; +} + GDParser::GDParser() { head=NULL; diff --git a/modules/gdscript/gd_parser.h b/modules/gdscript/gd_parser.h index 9e6f6e6765..7968bf85df 100644 --- a/modules/gdscript/gd_parser.h +++ b/modules/gdscript/gd_parser.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -209,6 +209,7 @@ public: OP_INDEX_NAMED, //unary operators OP_NEG, + OP_POS, OP_NOT, OP_BIT_INVERT, OP_PREINC, @@ -247,6 +248,9 @@ public: OP_BIT_AND, OP_BIT_OR, OP_BIT_XOR, + //ternary operators + OP_TERNARY_IF, + OP_TERNARY_ELSE, }; Operator op; @@ -254,6 +258,44 @@ public: Vector<Node*> arguments; OperatorNode() { type=TYPE_OPERATOR; } }; + + + struct PatternNode : public Node { + + enum PatternType { + PT_CONSTANT, + PT_BIND, + PT_DICTIONARY, + PT_ARRAY, + PT_IGNORE_REST, + PT_WILDCARD + }; + + PatternType pt_type; + + Node *constant; + StringName bind; + Map<ConstantNode*, PatternNode*> dictionary; + Vector<PatternNode*> array; + + }; + + struct PatternBranchNode : public Node { + Vector<PatternNode*> patterns; + BlockNode *body; + }; + + struct MatchNode : public Node { + Node *val_to_match; + Vector<PatternBranchNode*> branches; + + struct CompiledPatternBranch { + Node *compiled_pattern; + BlockNode *body; + }; + + Vector<CompiledPatternBranch> compiled_pattern_branches; + }; struct ControlFlowNode : public Node { enum CFType { @@ -263,13 +305,16 @@ public: CF_SWITCH, CF_BREAK, CF_CONTINUE, - CF_RETURN + CF_RETURN, + CF_MATCH }; CFType cf_type; Vector<Node*> arguments; BlockNode *body; BlockNode *body_else; + + MatchNode *match; ControlFlowNode *_else; //used for if ControlFlowNode() { type=TYPE_CONTROL_FLOW; cf_type=CF_IF; body=NULL; body_else=NULL;} @@ -372,6 +417,7 @@ public: enum CompletionType { COMPLETION_NONE, COMPLETION_BUILT_IN_TYPE_CONSTANT, + COMPLETION_GET_NODE, COMPLETION_FUNCTION, COMPLETION_IDENTIFIER, COMPLETION_PARENT_FUNCTION, @@ -429,6 +475,7 @@ private: int completion_line; int completion_argument; bool completion_found; + bool completion_ident_is_call; PropertyInfo current_export; @@ -446,6 +493,15 @@ private: Node* _reduce_expression(Node *p_node,bool p_to_const=false); Node* _parse_and_reduce_expression(Node *p_parent,bool p_static,bool p_reduce_const=false,bool p_allow_assign=false); + + + + PatternNode *_parse_pattern(bool p_static); + void _parse_pattern_block(BlockNode *p_block, Vector<PatternBranchNode*> &p_branches, bool p_static); + void _transform_match_statment(BlockNode *p_block, MatchNode *p_match_statement); + void _generate_pattern(PatternNode *p_pattern, Node *p_node_to_match, Node *&p_resulting_node, Map<StringName, Node*> &p_bindings); + + void _parse_block(BlockNode *p_block,bool p_static); void _parse_extends(ClassNode *p_class); void _parse_class(ClassNode *p_class); @@ -475,7 +531,7 @@ public: BlockNode *get_completion_block(); FunctionNode *get_completion_function(); int get_completion_argument_index(); - + int get_completion_identifier_is_function(); void clear(); GDParser(); diff --git a/modules/gdscript/gd_script.cpp b/modules/gdscript/gd_script.cpp index b97a0fcbb6..d4646aa36d 100644 --- a/modules/gdscript/gd_script.cpp +++ b/modules/gdscript/gd_script.cpp @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -27,7 +27,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "gd_script.h" -#include "globals.h" +#include "global_config.h" #include "global_constants.h" #include "gd_compiler.h" #include "os/file_access.h" @@ -50,7 +50,7 @@ GDNativeClass::GDNativeClass(const StringName& p_name) { bool GDNativeClass::_get(const StringName& p_name,Variant &r_ret) const { bool ok; - int v = ObjectTypeDB::get_integer_constant(name, p_name, &ok); + int v = ClassDB::get_integer_constant(name, p_name, &ok); if (ok) { r_ret=v; @@ -63,7 +63,7 @@ bool GDNativeClass::_get(const StringName& p_name,Variant &r_ret) const { void GDNativeClass::_bind_methods() { - ObjectTypeDB::bind_method(_MD("new"),&GDNativeClass::_new); + ClassDB::bind_method(D_METHOD("new"),&GDNativeClass::_new); } @@ -86,7 +86,7 @@ Variant GDNativeClass::_new() { Object *GDNativeClass::instance() { - return ObjectTypeDB::instance(name); + return ClassDB::instance(name); } @@ -111,14 +111,29 @@ GDInstance* GDScript::_create_instance(const Variant** p_args,int p_argcount,Obj /* STEP 2, INITIALIZE AND CONSRTUCT */ +#ifndef NO_THREADS + GDScriptLanguage::singleton->lock->lock(); +#endif + instances.insert(instance->owner); +#ifndef NO_THREADS + GDScriptLanguage::singleton->lock->unlock(); +#endif + initializer->call(instance,p_args,p_argcount,r_error); if (r_error.error!=Variant::CallError::CALL_OK) { instance->script=Ref<GDScript>(); instance->owner->set_script_instance(NULL); +#ifndef NO_THREADS + GDScriptLanguage::singleton->lock->lock(); +#endif instances.erase(p_owner); +#ifndef NO_THREADS + GDScriptLanguage::singleton->lock->unlock(); +#endif + ERR_FAIL_COND_V(r_error.error!=Variant::CallError::CALL_OK, NULL); //error constructing } @@ -145,6 +160,8 @@ Variant GDScript::_new(const Variant** p_args,int p_argcount,Variant::CallError& _baseptr=_baseptr->_base; } + ERR_FAIL_COND_V(_baseptr->native.is_null(), Variant()); + if (_baseptr->native.ptr()) { owner=_baseptr->native->instance(); } else { @@ -341,9 +358,11 @@ bool GDScript::get_property_default_value(const StringName& p_property, Variant #ifdef TOOLS_ENABLED - //for (const Map<StringName,Variant>::Element *I=member_default_values.front();I;I=I->next()) { - // print_line("\t"+String(String(I->key())+":"+String(I->get()))); - //} + /* + for (const Map<StringName,Variant>::Element *I=member_default_values.front();I;I=I->next()) { + print_line("\t"+String(String(I->key())+":"+String(I->get()))); + } + */ const Map<StringName,Variant>::Element *E=member_default_values_cache.find(p_property); if (E) { r_value=E->get(); @@ -388,12 +407,12 @@ ScriptInstance* GDScript::instance_create(Object *p_this) { top=top->_base; if (top->native.is_valid()) { - if (!ObjectTypeDB::is_type(p_this->get_type_name(),top->native->get_name())) { + if (!ClassDB::is_parent_class(p_this->get_class_name(),top->native->get_name())) { if (ScriptDebugger::get_singleton()) { - GDScriptLanguage::get_singleton()->debug_break_parse(get_path(),0,"Script inherits from native type '"+String(top->native->get_name())+"', so it can't be instanced in object of type: '"+p_this->get_type()+"'"); + GDScriptLanguage::get_singleton()->debug_break_parse(get_path(),0,"Script inherits from native type '"+String(top->native->get_name())+"', so it can't be instanced in object of type: '"+p_this->get_class()+"'"); } - ERR_EXPLAIN("Script inherits from native type '"+String(top->native->get_name())+"', so it can't be instanced in object of type: '"+p_this->get_type()+"'"); + ERR_EXPLAIN("Script inherits from native type '"+String(top->native->get_name())+"', so it can't be instanced in object of type: '"+p_this->get_class()+"'"); ERR_FAIL_V(NULL); } @@ -405,7 +424,16 @@ ScriptInstance* GDScript::instance_create(Object *p_this) { } bool GDScript::instance_has(const Object *p_this) const { - return instances.has((Object*)p_this); +#ifndef NO_THREADS + GDScriptLanguage::singleton->lock->lock(); +#endif + bool hasit = instances.has((Object*)p_this); + +#ifndef NO_THREADS + GDScriptLanguage::singleton->lock->unlock(); +#endif + + return hasit; } bool GDScript::has_source_code() const { @@ -513,7 +541,7 @@ bool GDScript::_update_exports() { } } - members_cache.clear();; + members_cache.clear(); member_default_values_cache.clear(); for(int i=0;i<c->variables.size();i++) { @@ -596,8 +624,16 @@ void GDScript::_set_subclass_path(Ref<GDScript>& p_sc,const String& p_path) { Error GDScript::reload(bool p_keep_state) { +#ifndef NO_THREADS + GDScriptLanguage::singleton->lock->lock(); +#endif + bool has_instances = instances.size(); + +#ifndef NO_THREADS + GDScriptLanguage::singleton->lock->unlock(); +#endif - ERR_FAIL_COND_V(!p_keep_state && instances.size(),ERR_ALREADY_IN_USE); + ERR_FAIL_COND_V(!p_keep_state && has_instances,ERR_ALREADY_IN_USE); String basedir=path; @@ -751,9 +787,9 @@ void GDScript::_get_property_list(List<PropertyInfo> *p_properties) const { void GDScript::_bind_methods() { - ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"new",&GDScript::_new,MethodInfo(Variant::OBJECT,"new")); + ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT,"new",&GDScript::_new,MethodInfo(Variant::OBJECT,"new")); - ObjectTypeDB::bind_method(_MD("get_as_byte_code"),&GDScript::get_as_byte_code); + ClassDB::bind_method(D_METHOD("get_as_byte_code"),&GDScript::get_as_byte_code); } @@ -830,7 +866,7 @@ Error GDScript::load_byte_code(const String& p_path) { Error GDScript::load_source_code(const String& p_path) { - DVector<uint8_t> sourcef; + PoolVector<uint8_t> sourcef; Error err; FileAccess *f=FileAccess::open(p_path,FileAccess::READ,&err); if (err) { @@ -840,7 +876,7 @@ Error GDScript::load_source_code(const String& p_path) { int len = f->get_len(); sourcef.resize(len+1); - DVector<uint8_t>::Write w = sourcef.write(); + PoolVector<uint8_t>::Write w = sourcef.write(); int r = f->get_buffer(w.ptr(),len); f->close(); memdelete(f); @@ -1423,7 +1459,15 @@ GDInstance::GDInstance() { GDInstance::~GDInstance() { if (script.is_valid() && owner) { - script->instances.erase(owner); +#ifndef NO_THREADS + GDScriptLanguage::singleton->lock->lock(); +#endif + + script->instances.erase(owner); +#ifndef NO_THREADS + GDScriptLanguage::singleton->lock->unlock(); +#endif + } } @@ -1477,7 +1521,7 @@ void GDScriptLanguage::init() { //populate native classes List<StringName> class_list; - ObjectTypeDB::get_type_list(&class_list); + ClassDB::get_class_list(&class_list); for(List<StringName>::Element *E=class_list.front();E;E=E->next()) { StringName n = E->get(); @@ -1493,9 +1537,9 @@ void GDScriptLanguage::init() { //populate singletons - List<Globals::Singleton> singletons; - Globals::get_singleton()->get_singletons(&singletons); - for(List<Globals::Singleton>::Element *E=singletons.front();E;E=E->next()) { + List<GlobalConfig::Singleton> singletons; + GlobalConfig::get_singleton()->get_singletons(&singletons); + for(List<GlobalConfig::Singleton>::Element *E=singletons.front();E;E=E->next()) { _add_global(E->get().name,E->get().ptr); } @@ -1820,7 +1864,7 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script>& p_script,bool p_sof void GDScriptLanguage::frame() { - // print_line("calls: "+itos(calls)); + //print_line("calls: "+itos(calls)); calls=0; #ifdef DEBUG_ENABLED @@ -1894,6 +1938,7 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const { "for", "pass", "return", + "match", "while", "remote", "sync", @@ -1940,7 +1985,7 @@ GDScriptLanguage::GDScriptLanguage() { script_frame_time=0; _debug_call_stack_pos=0; - int dmcs=GLOBAL_DEF("debug/script_max_call_stack",1024); + int dmcs=GLOBAL_DEF("debug/script/max_call_stack",1024); if (ScriptDebugger::get_singleton()) { //debugging enabled! @@ -2026,7 +2071,7 @@ bool ResourceFormatLoaderGDScript::handles_type(const String& p_type) const { String ResourceFormatLoaderGDScript::get_resource_type(const String &p_path) const { - String el = p_path.extension().to_lower(); + String el = p_path.get_extension().to_lower(); if (el=="gd" || el=="gdc" || el=="gde") return "GDScript"; return ""; diff --git a/modules/gdscript/gd_script.h b/modules/gdscript/gd_script.h index 0c3e1eb614..4d3baa5bc0 100644 --- a/modules/gdscript/gd_script.h +++ b/modules/gdscript/gd_script.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -35,7 +35,7 @@ #include "gd_function.h" class GDNativeClass : public Reference { - OBJ_TYPE(GDNativeClass,Reference); + GDCLASS(GDNativeClass,Reference); StringName name; protected: @@ -55,7 +55,7 @@ public: class GDScript : public Script { - OBJ_TYPE(GDScript,Script); + GDCLASS(GDScript,Script); bool tool; bool valid; @@ -65,6 +65,7 @@ class GDScript : public Script { StringName setter; StringName getter; ScriptInstance::RPCMode rpc_mode; + }; friend class GDInstance; @@ -86,8 +87,11 @@ friend class GDScriptLanguage; Map<StringName,Ref<GDScript> > subclasses; Map<StringName,Vector<StringName> > _signals; + #ifdef TOOLS_ENABLED + Map<StringName,int> member_lines; + Map<StringName,Variant> member_default_values; List<PropertyInfo> members_cache; @@ -135,7 +139,7 @@ protected: void _get_property_list(List<PropertyInfo> *p_properties) const; Variant call(const StringName& p_method,const Variant** p_args,int p_argcount,Variant::CallError &r_error); -// void call_multilevel(const StringName& p_method,const Variant** p_args,int p_argcount); + //void call_multilevel(const StringName& p_method,const Variant** p_args,int p_argcount); static void _bind_methods(); public: @@ -193,6 +197,16 @@ public: virtual ScriptLanguage *get_language() const; + virtual int get_member_line(const StringName& p_member) const { +#ifdef TOOLS_ENABLED + if (member_lines.has(p_member)) + return member_lines[p_member]; + else +#endif + return -1; + + } + GDScript(); ~GDScript(); }; @@ -280,11 +294,13 @@ class GDScriptLanguage : public ScriptLanguage { void _add_global(const StringName& p_name,const Variant& p_value); +friend class GDInstance; Mutex *lock; + friend class GDScript; SelfList<GDScript>::List script_list; @@ -392,8 +408,11 @@ public: virtual Script *create_script() const; virtual bool has_named_classes() const; virtual int find_function(const String& p_function,const String& p_code) const; - virtual String make_function(const String& p_class,const String& p_name,const StringArray& p_args) const; + virtual String make_function(const String& p_class,const String& p_name,const PoolStringArray& p_args) const; virtual Error complete_code(const String& p_code, const String& p_base_path, Object*p_owner,List<String>* r_options,String& r_call_hint); +#ifdef TOOLS_ENABLED + virtual Error lookup_code(const String& p_code, const String& p_symbol, const String& p_base_path, Object*p_owner, LookupResult& r_result); +#endif virtual void auto_indent_code(String& p_code,int p_from_line,int p_to_line) const; virtual void add_global_constant(const StringName& p_variable,const Variant& p_value); diff --git a/modules/gdscript/gd_tokenizer.cpp b/modules/gdscript/gd_tokenizer.cpp index 47e740b227..477a1f1ac8 100644 --- a/modules/gdscript/gd_tokenizer.cpp +++ b/modules/gdscript/gd_tokenizer.cpp @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -85,6 +85,7 @@ const char* GDTokenizer::token_names[TK_MAX]={ "continue", "pass", "return", +"match", "func", "class", "extends", @@ -95,6 +96,7 @@ const char* GDTokenizer::token_names[TK_MAX]={ "setget", "const", "var", +"enum", "preload", "assert", "yield", @@ -117,6 +119,7 @@ const char* GDTokenizer::token_names[TK_MAX]={ "':'", "'\\n'", "PI", +"_", "Error", "EOF", "Cursor"}; @@ -281,7 +284,7 @@ void GDTokenizerText::_advance() { case '\n': { line++; INCPOS(1); - column=0; + column=1; int i=0; while(GETCHAR(i)==' ' || GETCHAR(i)=='\t') { i++; @@ -302,7 +305,7 @@ void GDTokenizerText::_advance() { } } INCPOS(1); - column=0; + column=1; line++; int i=0; while(GETCHAR(i)==' ' || GETCHAR(i)=='\t') { @@ -334,7 +337,7 @@ void GDTokenizerText::_advance() { break; } else if (_code[pos]=='\n') { new_line++; - new_col=0; + new_col=1; } else { new_col++; } @@ -357,7 +360,7 @@ void GDTokenizerText::_advance() { } } INCPOS(1); - column=0; + column=1; line++; continue; @@ -459,6 +462,9 @@ void GDTokenizerText::_advance() { case ':': _make_token(TK_COLON); //for methods maybe but now useless. break; + case '$': + _make_token(TK_DOLLAR); //for the get_node() shortener + break; case '^': { if (GETCHAR(1)=='=') { _make_token(TK_OP_ASSIGN_BIT_XOR); @@ -509,9 +515,11 @@ void GDTokenizerText::_advance() { if (GETCHAR(1)=='=') { _make_token(TK_OP_ASSIGN_ADD); INCPOS(1); - //} else if (GETCHAR(1)=='+') { - // _make_token(TK_OP_PLUS_PLUS); - // INCPOS(1); + /* + } else if (GETCHAR(1)=='+') { + _make_token(TK_OP_PLUS_PLUS); + INCPOS(1); + */ } else { _make_token(TK_OP_ADD); } @@ -522,9 +530,11 @@ void GDTokenizerText::_advance() { if (GETCHAR(1)=='=') { _make_token(TK_OP_ASSIGN_SUB); INCPOS(1); - //} else if (GETCHAR(1)=='-') { - // _make_token(TK_OP_MINUS_MINUS); - // INCPOS(1); + /* + } else if (GETCHAR(1)=='-') { + _make_token(TK_OP_MINUS_MINUS); + INCPOS(1); + */ } else { _make_token(TK_OP_SUB); } @@ -653,7 +663,7 @@ void GDTokenizerText::_advance() { } else { if (CharType(GETCHAR(i))=='\n') { line++; - column=0; + column=1; } str+=CharType(GETCHAR(i)); @@ -727,14 +737,14 @@ void GDTokenizerText::_advance() { INCPOS(str.length()); if (hexa_found) { - int val = str.hex_to_int(); + int64_t val = str.hex_to_int64(); _make_constant(val); } else if (period_found || exponent_found) { - real_t val = str.to_double(); + double val = str.to_double(); //print_line("*%*%*%*% to convert: "+str+" result: "+rtos(val)); _make_constant(val); } else { - int val = str.to_int(); + int64_t val = str.to_int64(); _make_constant(val); } @@ -784,13 +794,12 @@ void GDTokenizerText::_advance() { {Variant::STRING,"String"}, {Variant::VECTOR2,"Vector2"}, {Variant::RECT2,"Rect2"}, - {Variant::MATRIX32,"Matrix32"}, + {Variant::TRANSFORM2D,"Transform2D"}, {Variant::VECTOR3,"Vector3"}, - {Variant::_AABB,"AABB"}, - {Variant::_AABB,"Rect3"}, + {Variant::RECT3,"Rect3"}, {Variant::PLANE,"Plane"}, {Variant::QUAT,"Quat"}, - {Variant::MATRIX3,"Matrix3"}, + {Variant::BASIS,"Basis"}, {Variant::TRANSFORM,"Transform"}, {Variant::COLOR,"Color"}, {Variant::IMAGE,"Image"}, @@ -800,13 +809,13 @@ void GDTokenizerText::_advance() { {Variant::NODE_PATH,"NodePath"}, {Variant::DICTIONARY,"Dictionary"}, {Variant::ARRAY,"Array"}, - {Variant::RAW_ARRAY,"RawArray"}, - {Variant::INT_ARRAY,"IntArray"}, - {Variant::REAL_ARRAY,"FloatArray"}, - {Variant::STRING_ARRAY,"StringArray"}, - {Variant::VECTOR2_ARRAY,"Vector2Array"}, - {Variant::VECTOR3_ARRAY,"Vector3Array"}, - {Variant::COLOR_ARRAY,"ColorArray"}, + {Variant::POOL_BYTE_ARRAY,"PoolByteArray"}, + {Variant::POOL_INT_ARRAY,"PoolIntArray"}, + {Variant::POOL_REAL_ARRAY,"PoolFloatArray"}, + {Variant::POOL_STRING_ARRAY,"PoolStringArray"}, + {Variant::POOL_VECTOR2_ARRAY,"PoolVector2Array"}, + {Variant::POOL_VECTOR3_ARRAY,"PoolVector3Array"}, + {Variant::POOL_COLOR_ARRAY,"PoolColorArray"}, {Variant::VARIANT_MAX,NULL}, }; @@ -874,6 +883,7 @@ void GDTokenizerText::_advance() { {TK_PR_SLAVE,"slave"}, {TK_PR_SYNC,"sync"}, {TK_PR_CONST,"const"}, + {TK_PR_ENUM,"enum"}, //controlflow {TK_CF_IF,"if"}, {TK_CF_ELIF,"elif"}, @@ -886,9 +896,11 @@ void GDTokenizerText::_advance() { {TK_CF_BREAK,"break"}, {TK_CF_CONTINUE,"continue"}, {TK_CF_RETURN,"return"}, + {TK_CF_MATCH, "match"}, {TK_CF_PASS,"pass"}, {TK_SELF,"self"}, {TK_CONST_PI,"PI"}, + {TK_WILDCARD,"_"}, {TK_ERROR,NULL} }; @@ -941,7 +953,7 @@ void GDTokenizerText::set_code(const String& p_code) { } code_pos=0; line=1; //it is stand-ar-ized that lines begin in 1 in code.. - column=0; + column=1; //the same holds for columns tk_rb_pos=0; error_flag=false; last_error=""; @@ -1055,7 +1067,7 @@ void GDTokenizerText::advance(int p_amount) { ////////////////////////////////////////////////////////////////////////////////////////////////////// -#define BYTECODE_VERSION 11 +#define BYTECODE_VERSION 12 Error GDTokenizerBuffer::set_code_buffer(const Vector<uint8_t> & p_buffer) { @@ -1157,7 +1169,7 @@ Vector<uint8_t> GDTokenizerBuffer::parse_code_string(const String& p_code) { Map<StringName,int> identifier_map; - HashMap<Variant,int,VariantHasher> constant_map; + HashMap<Variant,int,VariantHasher,VariantComparator> constant_map; Map<uint32_t,int> line_map; Vector<uint32_t> token_array; @@ -1330,7 +1342,7 @@ StringName GDTokenizerBuffer::get_token_identifier(int p_offset) const{ ERR_FAIL_INDEX_V(offset,tokens.size(),StringName()); uint32_t identifier = tokens[offset]>>TOKEN_BITS; - ERR_FAIL_INDEX_V(identifier,identifiers.size(),StringName()); + ERR_FAIL_INDEX_V(identifier,(uint32_t)identifiers.size(),StringName()); return identifiers[identifier]; } @@ -1389,7 +1401,7 @@ const Variant& GDTokenizerBuffer::get_token_constant(int p_offset) const{ int offset = token+p_offset; ERR_FAIL_INDEX_V(offset,tokens.size(),nil); uint32_t constant = tokens[offset]>>TOKEN_BITS; - ERR_FAIL_INDEX_V(constant,constants.size(),nil); + ERR_FAIL_INDEX_V(constant,(uint32_t)constants.size(),nil); return constants[constant]; } diff --git a/modules/gdscript/gd_tokenizer.h b/modules/gdscript/gd_tokenizer.h index 1815f82894..5d955ff1ae 100644 --- a/modules/gdscript/gd_tokenizer.h +++ b/modules/gdscript/gd_tokenizer.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -92,6 +92,7 @@ public: TK_CF_CONTINUE, TK_CF_PASS, TK_CF_RETURN, + TK_CF_MATCH, TK_PR_FUNCTION, TK_PR_CLASS, TK_PR_EXTENDS, @@ -102,6 +103,7 @@ public: TK_PR_SETGET, TK_PR_CONST, TK_PR_VAR, + TK_PR_ENUM, TK_PR_PRELOAD, TK_PR_ASSERT, TK_PR_YIELD, @@ -122,8 +124,10 @@ public: TK_PERIOD, TK_QUESTION_MARK, TK_COLON, + TK_DOLLAR, TK_NEWLINE, TK_CONST_PI, + TK_WILDCARD, TK_ERROR, TK_EOF, TK_CURSOR, //used for code completion diff --git a/modules/gdscript/register_types.cpp b/modules/gdscript/register_types.cpp index 95b18cae4d..db47ee43ce 100644 --- a/modules/gdscript/register_types.cpp +++ b/modules/gdscript/register_types.cpp @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -38,7 +38,7 @@ GDScriptLanguage *script_language_gd=NULL; ResourceFormatLoaderGDScript *resource_loader_gd=NULL; ResourceFormatSaverGDScript *resource_saver_gd=NULL; - +#if 0 #ifdef TOOLS_ENABLED #include "tools/editor/editor_import_export.h" @@ -48,7 +48,7 @@ ResourceFormatSaverGDScript *resource_saver_gd=NULL; class EditorExportGDScript : public EditorExportPlugin { - OBJ_TYPE(EditorExportGDScript,EditorExportPlugin); + GDCLASS(EditorExportGDScript,EditorExportPlugin); public: @@ -100,7 +100,7 @@ public: if (err==OK) { fae->store_buffer(file.ptr(),file.size()); - p_path=p_path.basename()+".gde"; + p_path=p_path.get_basename()+".gde"; } memdelete(fae); @@ -111,7 +111,7 @@ public: } else { - p_path=p_path.basename()+".gdc"; + p_path=p_path.get_basename()+".gdc"; return file; } } @@ -135,11 +135,11 @@ static void register_editor_plugin() { #endif - +#endif void register_gdscript_types() { - ObjectTypeDB::register_type<GDScript>(); - ObjectTypeDB::register_virtual_type<GDFunctionState>(); + ClassDB::register_class<GDScript>(); + ClassDB::register_virtual_class<GDFunctionState>(); script_language_gd=memnew( GDScriptLanguage ); //script_language_gd->init(); @@ -148,11 +148,12 @@ void register_gdscript_types() { ResourceLoader::add_resource_format_loader(resource_loader_gd); resource_saver_gd=memnew( ResourceFormatSaverGDScript ); ResourceSaver::add_resource_format_saver(resource_saver_gd); - +#if 0 #ifdef TOOLS_ENABLED EditorNode::add_init_callback(register_editor_plugin); #endif +#endif } void unregister_gdscript_types() { diff --git a/modules/gdscript/register_types.h b/modules/gdscript/register_types.h index aed11cd1d4..5778dfcadc 100644 --- a/modules/gdscript/register_types.h +++ b/modules/gdscript/register_types.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/modules/gridmap/SCsub b/modules/gridmap/SCsub index 211a043468..0882406761 100644 --- a/modules/gridmap/SCsub +++ b/modules/gridmap/SCsub @@ -1,3 +1,7 @@ +#!/usr/bin/env python + Import('env') -env.add_source_files(env.modules_sources,"*.cpp") +env.add_source_files(env.modules_sources, "*.cpp") + +Export('env') diff --git a/modules/gridmap/config.py b/modules/gridmap/config.py index ea7e83378a..5698a37295 100644 --- a/modules/gridmap/config.py +++ b/modules/gridmap/config.py @@ -1,11 +1,8 @@ def can_build(platform): - return True + return True def configure(env): - pass - - - + pass diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp index 6e73244b57..d4fb174bfe 100644 --- a/modules/gridmap/grid_map.cpp +++ b/modules/gridmap/grid_map.cpp @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -31,7 +31,7 @@ #include "scene/resources/surface_tool.h" #include "message_queue.h" #include "scene/3d/light.h" -#include "scene/3d/baked_light_instance.h" + #include "io/marshalls.h" #include "scene/scene_string_names.h" #include "os/os.h" @@ -41,31 +41,27 @@ bool GridMap::_set(const StringName& p_name, const Variant& p_value) { String name=p_name; - if (name=="theme/theme") { + if (name=="theme") { set_theme(p_value); - } else if (name=="cell/size") { + } else if (name=="cell_size") { set_cell_size(p_value); - } else if (name=="cell/octant_size") { + } else if (name=="cell_octant_size") { set_octant_size(p_value); - } else if (name=="cell/center_x") { + } else if (name=="cell_center_x") { set_center_x(p_value); - } else if (name=="cell/center_y") { + } else if (name=="cell_center_y") { set_center_y(p_value); - } else if (name=="cell/center_z") { + } else if (name=="cell_center_z") { set_center_z(p_value); - } else if (name=="cell/scale") { + } else if (name=="cell_scale") { set_cell_scale(p_value); - } else if (name=="lighting/bake") { - set_use_baked_light(p_value); - } else if (name=="theme/bake") { - set_bake(p_value); /* } else if (name=="cells") { - DVector<int> cells = p_value; + PoolVector<int> cells = p_value; int amount=cells.size(); - DVector<int>::Read r = cells.read(); + PoolVector<int>::Read r = cells.read(); ERR_FAIL_COND_V(amount&1,false); // not even - cell_map.clear();; + cell_map.clear(); for(int i=0;i<amount/3;i++) { @@ -81,16 +77,13 @@ bool GridMap::_set(const StringName& p_name, const Variant& p_value) { Dictionary d = p_value; - Dictionary baked; - if (d.has("baked")) - baked=d["baked"]; if (d.has("cells")) { - DVector<int> cells = d["cells"]; + PoolVector<int> cells = d["cells"]; int amount=cells.size(); - DVector<int>::Read r = cells.read(); + PoolVector<int>::Read r = cells.read(); ERR_FAIL_COND_V(amount%3,false); // not even - cell_map.clear();; + cell_map.clear(); for(int i=0;i<amount/3;i++) { IndexKey ik; @@ -101,33 +94,7 @@ bool GridMap::_set(const StringName& p_name, const Variant& p_value) { } } - baked_lock=baked.size()!=0; _recreate_octant_data(); - baked_lock=false; - if (!baked.empty()) { - List<Variant> kl; - baked.get_key_list(&kl); - for (List<Variant>::Element *E=kl.front();E;E=E->next()) { - - Plane ikv = E->get(); - Ref<Mesh> b=baked[ikv]; - ERR_CONTINUE(!b.is_valid()); - OctantKey ok; - ok.x=ikv.normal.x; - ok.y=ikv.normal.y; - ok.z=ikv.normal.z; - ok.area=ikv.d; - - ERR_CONTINUE(!octant_map.has(ok)); - - Octant &g = *octant_map[ok]; - - g.baked=b; - g.bake_instance=VS::get_singleton()->instance_create();; - VS::get_singleton()->instance_set_base(g.bake_instance,g.baked->get_rid()); - VS::get_singleton()->instance_geometry_set_baked_light(g.bake_instance,baked_light_instance?baked_light_instance->get_baked_light_instance():RID()); - } - } } else if (name.begins_with("areas/")) { @@ -161,32 +128,28 @@ bool GridMap::_get(const StringName& p_name,Variant &r_ret) const { String name=p_name; - if (name=="theme/theme") { + if (name=="theme") { r_ret= get_theme(); - } else if (name=="cell/size") { + } else if (name=="cell_size") { r_ret= get_cell_size(); - } else if (name=="cell/octant_size") { + } else if (name=="cell_octant_size") { r_ret= get_octant_size(); - } else if (name=="cell/center_x") { + } else if (name=="cell_center_x") { r_ret= get_center_x(); - } else if (name=="cell/center_y") { + } else if (name=="cell_center_y") { r_ret= get_center_y(); - } else if (name=="cell/center_z") { + } else if (name=="cell_center_z") { r_ret= get_center_z(); - } else if (name=="cell/scale") { + } else if (name=="cell_scale") { r_ret= cell_scale; - } else if (name=="lighting/bake") { - r_ret=is_using_baked_light(); - } else if (name=="theme/bake") { - r_ret= bake; } else if (name=="data") { Dictionary d; - DVector<int> cells; + PoolVector<int> cells; cells.resize(cell_map.size()*3); { - DVector<int>::Write w = cells.write(); + PoolVector<int>::Write w = cells.write(); int i=0; for (Map<IndexKey,Cell>::Element *E=cell_map.front();E;E=E->next(),i++) { @@ -197,23 +160,8 @@ bool GridMap::_get(const StringName& p_name,Variant &r_ret) const { d["cells"]=cells; - Dictionary baked; - for(Map<OctantKey,Octant*>::Element *E=octant_map.front();E;E=E->next()) { - - Octant &g=*E->get(); - - if (g.baked.is_valid()) { - - baked[Plane(E->key().x,E->key().y,E->key().z,E->key().area)]=g.baked; - } - } - - if (baked.size()) { - d["baked"]=baked; - } - r_ret= d; } else if (name.begins_with("areas/")) { int which = name.get_slicec('/',1).to_int(); @@ -237,22 +185,21 @@ bool GridMap::_get(const StringName& p_name,Variant &r_ret) const { void GridMap::_get_property_list( List<PropertyInfo> *p_list) const { - p_list->push_back( PropertyInfo( Variant::OBJECT, "theme/theme", PROPERTY_HINT_RESOURCE_TYPE, "MeshLibrary")); - p_list->push_back( PropertyInfo( Variant::BOOL, "theme/bake")); - p_list->push_back( PropertyInfo( Variant::BOOL, "lighting/bake")); - p_list->push_back( PropertyInfo( Variant::REAL, "cell/size",PROPERTY_HINT_RANGE,"0.01,16384,0.01") ); - p_list->push_back( PropertyInfo( Variant::INT, "cell/octant_size",PROPERTY_HINT_RANGE,"1,1024,1") ); - p_list->push_back( PropertyInfo( Variant::BOOL, "cell/center_x") ); - p_list->push_back( PropertyInfo( Variant::BOOL, "cell/center_y") ); - p_list->push_back( PropertyInfo( Variant::BOOL, "cell/center_z") ); - p_list->push_back( PropertyInfo( Variant::REAL, "cell/scale") ); + p_list->push_back( PropertyInfo( Variant::OBJECT, "theme", PROPERTY_HINT_RESOURCE_TYPE, "MeshLibrary")); + p_list->push_back( PropertyInfo( Variant::NIL, "Cell", PROPERTY_HINT_NONE,"cell_",PROPERTY_USAGE_GROUP)); + p_list->push_back( PropertyInfo( Variant::REAL, "cell_size",PROPERTY_HINT_RANGE,"0.01,16384,0.01") ); + p_list->push_back( PropertyInfo( Variant::INT, "cell_octant_size",PROPERTY_HINT_RANGE,"1,1024,1") ); + p_list->push_back( PropertyInfo( Variant::BOOL, "cell_center_x") ); + p_list->push_back( PropertyInfo( Variant::BOOL, "cell_center_y") ); + p_list->push_back( PropertyInfo( Variant::BOOL, "cell_center_z") ); + p_list->push_back( PropertyInfo( Variant::REAL, "cell_scale") ); p_list->push_back( PropertyInfo( Variant::DICTIONARY, "data", PROPERTY_HINT_NONE,"",PROPERTY_USAGE_STORAGE) ); for(const Map<int,Area*>::Element *E=area_map.front();E;E=E->next()) { String base="areas/"+itos(E->key())+"/"; - p_list->push_back( PropertyInfo( Variant::_AABB, base+"bounds", PROPERTY_HINT_NONE,"",PROPERTY_USAGE_STORAGE) ); + p_list->push_back( PropertyInfo( Variant::RECT3, base+"bounds", PROPERTY_HINT_NONE,"",PROPERTY_USAGE_STORAGE) ); p_list->push_back( PropertyInfo( Variant::STRING, base+"name", PROPERTY_HINT_NONE,"",PROPERTY_USAGE_STORAGE) ); p_list->push_back( PropertyInfo( Variant::REAL, base+"disable_distance", PROPERTY_HINT_NONE,"",PROPERTY_USAGE_STORAGE) ); p_list->push_back( PropertyInfo( Variant::COLOR, base+"disable_color", PROPERTY_HINT_NONE,"",PROPERTY_USAGE_STORAGE) ); @@ -380,17 +327,6 @@ void GridMap::set_cell_item(int p_x,int p_y,int p_z, int p_item,int p_rot){ g.items.erase(prev_item); } - - if (g.items.empty() || !baked_lock) { - //unbake just in case - if (g.baked.is_valid()) { - VS::get_singleton()->free(g.bake_instance); - g.bake_instance=RID(); - g.baked=Ref<Mesh>(); - } - - - } if (g.items.empty()) { PhysicsServer::get_singleton()->free(g.static_body); @@ -454,24 +390,12 @@ void GridMap::set_cell_item(int p_x,int p_y,int p_z, int p_item,int p_rot){ ii.navmesh=theme->get_item_navmesh(p_item); } ii.multimesh = Ref<MultiMesh>( memnew( MultiMesh ) ); + ii.multimesh->set_color_format(MultiMesh::COLOR_NONE); + ii.multimesh->set_transform_format(MultiMesh::TRANSFORM_3D); ii.multimesh->set_mesh(ii.mesh); ii.multimesh_instance = VS::get_singleton()->instance_create(); VS::get_singleton()->instance_set_base(ii.multimesh_instance,ii.multimesh->get_rid()); - VS::get_singleton()->instance_geometry_set_baked_light(ii.multimesh_instance,baked_light_instance?baked_light_instance->get_baked_light_instance():RID()); - if (!baked_lock) { - - //unbake just in case - if (g.bake_instance.is_valid()) - VS::get_singleton()->free(g.bake_instance); - g.baked=Ref<Mesh>(); - if (is_inside_world()) { - VS::get_singleton()->instance_set_scenario(ii.multimesh_instance,get_world()->get_scenario()); - if (ok.area) { - VS::get_singleton()->instance_set_room( ii.multimesh_instance,area_map[ok.area]->instance); - } - } - } g.items[p_item]=ii; } @@ -585,27 +509,14 @@ void GridMap::_octant_enter_world(const OctantKey &p_key) { VS::get_singleton()->instance_set_room(g.collision_debug_instance,area_map[p_key.area]->instance); } } - if (g.baked.is_valid()) { + for(Map<int,Octant::ItemInstances>::Element *E=g.items.front();E;E=E->next()) { - Transform xf = get_global_transform(); - xf.translate(_octant_get_offset(p_key)); + VS::get_singleton()->instance_set_scenario(E->get().multimesh_instance,get_world()->get_scenario()); + VS::get_singleton()->instance_set_transform(E->get().multimesh_instance,get_global_transform()); + //print_line("INSTANCEPOS: "+get_global_transform()); - VS::get_singleton()->instance_set_transform(g.bake_instance,xf); - VS::get_singleton()->instance_set_scenario(g.bake_instance,get_world()->get_scenario()); if (area_map.has(p_key.area)) { - VS::get_singleton()->instance_set_room(g.bake_instance,area_map[p_key.area]->instance); - - } - } else { - for(Map<int,Octant::ItemInstances>::Element *E=g.items.front();E;E=E->next()) { - - VS::get_singleton()->instance_set_scenario(E->get().multimesh_instance,get_world()->get_scenario()); - VS::get_singleton()->instance_set_transform(E->get().multimesh_instance,get_global_transform()); - //print_line("INSTANCEPOS: "+get_global_transform()); - - if (area_map.has(p_key.area)) { - VS::get_singleton()->instance_set_room(E->get().multimesh_instance,area_map[p_key.area]->instance); - } + VS::get_singleton()->instance_set_room(E->get().multimesh_instance,area_map[p_key.area]->instance); } } } @@ -621,17 +532,10 @@ void GridMap::_octant_transform(const OctantKey &p_key) { VS::get_singleton()->instance_set_transform(g.collision_debug_instance,get_global_transform()); } - if (g.baked.is_valid()) { - - Transform xf = get_global_transform(); - xf.origin+=_octant_get_offset(p_key); - VS::get_singleton()->instance_set_transform(g.bake_instance,xf); - } else { - for(Map<int,Octant::ItemInstances>::Element *E=g.items.front();E;E=E->next()) { + for(Map<int,Octant::ItemInstances>::Element *E=g.items.front();E;E=E->next()) { - VS::get_singleton()->instance_set_transform(E->get().multimesh_instance,get_global_transform()); - //print_line("UPDATEPOS: "+get_global_transform()); - } + VS::get_singleton()->instance_set_transform(E->get().multimesh_instance,get_global_transform()); + //print_line("UPDATEPOS: "+get_global_transform()); } } @@ -665,7 +569,7 @@ void GridMap::_octant_update(const OctantKey &p_key) { VS::get_singleton()->mesh_clear(g.collision_debug); } - DVector<Vector3> col_debug; + PoolVector<Vector3> col_debug; /* * foreach item in this octant, @@ -678,8 +582,8 @@ void GridMap::_octant_update(const OctantKey &p_key) { ii.multimesh->set_instance_count(ii.cells.size()); - AABB aabb; - AABB mesh_aabb = ii.mesh.is_null()?AABB():ii.mesh->get_aabb(); + Rect3 aabb; + Rect3 mesh_aabb = ii.mesh.is_null()?Rect3():ii.mesh->get_aabb(); Vector3 ofs(cell_size*0.5*int(center_x),cell_size*0.5*int(center_y),cell_size*0.5*int(center_z)); @@ -711,7 +615,7 @@ void GridMap::_octant_update(const OctantKey &p_key) { ii.multimesh->set_instance_transform(idx,xform); //ii.multimesh->set_instance_transform(idx,Transform() ); - ii.multimesh->set_instance_color(idx,Color(1,1,1,1)); + //ii.multimesh->set_instance_color(idx,Color(1,1,1,1)); //print_line("MMINST: "+xform); @@ -731,7 +635,7 @@ void GridMap::_octant_update(const OctantKey &p_key) { ii.shape->add_vertices_to_array(col_debug,xform); } - // print_line("PHIS x: "+xform); + //print_line("PHIS x: "+xform); } // add the item's navmesh at given xform to GridMap's Navigation ancestor @@ -748,7 +652,7 @@ void GridMap::_octant_update(const OctantKey &p_key) { idx++; } - ii.multimesh->set_aabb(aabb); + //ii.multimesh->set_aabb(aabb); } @@ -760,7 +664,7 @@ void GridMap::_octant_update(const OctantKey &p_key) { arr.resize(VS::ARRAY_MAX); arr[VS::ARRAY_VERTEX]=col_debug; - VS::get_singleton()->mesh_add_surface(g.collision_debug,VS::PRIMITIVE_LINES,arr); + VS::get_singleton()->mesh_add_surface_from_arrays(g.collision_debug,VS::PRIMITIVE_LINES,arr); SceneTree *st=SceneTree::get_singleton(); if (st) { VS::get_singleton()->mesh_surface_set_material( g.collision_debug, 0,st->get_debug_collision_material()->get_rid() ); @@ -780,13 +684,6 @@ void GridMap::_octant_exit_world(const OctantKey &p_key) { PhysicsServer::get_singleton()->body_set_space(g.static_body,RID()); - if (g.baked.is_valid()) { - - VS::get_singleton()->instance_set_room(g.bake_instance,RID()); - VS::get_singleton()->instance_set_scenario(g.bake_instance,RID()); - - } - if (g.collision_debug_instance.is_valid()) { VS::get_singleton()->instance_set_room(g.collision_debug_instance,RID()); @@ -796,200 +693,12 @@ void GridMap::_octant_exit_world(const OctantKey &p_key) { for(Map<int,Octant::ItemInstances>::Element *E=g.items.front();E;E=E->next()) { VS::get_singleton()->instance_set_scenario(E->get().multimesh_instance,RID()); - // VS::get_singleton()->instance_set_transform(E->get().multimesh_instance,get_global_transform()); + //VS::get_singleton()->instance_set_transform(E->get().multimesh_instance,get_global_transform()); VS::get_singleton()->instance_set_room(E->get().multimesh_instance,RID()); } } -void GridMap::_octant_clear_baked(const OctantKey &p_key) { - - - ERR_FAIL_COND(!octant_map.has(p_key)); - Octant&g = *octant_map[p_key]; - - if (!g.baked.is_valid()) - return; - - VS::get_singleton()->free(g.bake_instance); - g.bake_instance=RID(); - g.baked=Ref<Mesh>(); - - if (is_inside_tree()) - _octant_enter_world(p_key); - g.dirty=true; - _queue_dirty_map(); -} - -void GridMap::_octant_bake(const OctantKey &p_key, const Ref<TriangleMesh>& p_tmesh,const Vector<BakeLight> &p_lights,List<Vector3> *p_prebake) { - - - ERR_FAIL_COND(!octant_map.has(p_key)); - Octant&g = *octant_map[p_key]; - - Ref<TriangleMesh> tm=p_tmesh; - if (!p_prebake && is_inside_world()) - _octant_exit_world(p_key); - - Map< Ref<Material>, Ref<SurfaceTool> > surfaces; - Vector3 ofs(cell_size*0.5*int(center_x),cell_size*0.5*int(center_y),cell_size*0.5*int(center_z)); - Vector3 octant_ofs=_octant_get_offset(p_key); - - for(Map<int,Octant::ItemInstances>::Element *E=g.items.front();E;E=E->next()) { - - Octant::ItemInstances &ii=E->get(); - - if (ii.mesh.is_null()) - continue; - - for(Set<IndexKey>::Element *F=ii.cells.front();F;F=F->next()) { - - IndexKey ik=F->get(); - Map<IndexKey,Cell>::Element *C=cell_map.find(ik); - ERR_CONTINUE(!C); - Vector3 cellpos = Vector3(ik.x,ik.y,ik.z ); - - Transform xform; - xform.basis.set_orthogonal_index(C->get().rot); - xform.set_origin( cellpos*cell_size+ofs); - if (!p_prebake) - xform.origin-=octant_ofs; - - - for(int i=0;i<ii.mesh->get_surface_count();i++) { - - if (p_prebake) { - - if (ii.mesh->surface_get_primitive_type(i)!=Mesh::PRIMITIVE_TRIANGLES) - continue; - Array a = ii.mesh->surface_get_arrays(i); - DVector<Vector3> av=a[VS::ARRAY_VERTEX]; - int avs = av.size(); - DVector<Vector3>::Read vr = av.read(); - - DVector<int> ai=a[VS::ARRAY_INDEX]; - int ais=ai.size(); - if (ais) { - - DVector<int>::Read ir=ai.read(); - for(int j=0;j<ais;j++) { - - p_prebake->push_back(xform.xform(vr[ir[j]])); - //print_line("V SET: "+xform.xform(vr[ir[j]])); - } - - } else { - - for(int j=0;j<avs;j++) { - - p_prebake->push_back(xform.xform(vr[j])); - } - } - - } else { - - Ref<Material> m = ii.mesh->surface_get_material(i); - - Map< Ref<Material>, Ref<SurfaceTool> >::Element *S=surfaces.find(m); - - if (!S) { - - S=surfaces.insert(m,Ref<SurfaceTool>( memnew( SurfaceTool ))); - } - - Ref<SurfaceTool> st = S->get(); - List<SurfaceTool::Vertex>::Element *V=st->get_vertex_array().back(); - st->append_from(ii.mesh,i,xform); - st->set_material(m); - - - if (tm.is_valid()) { - - if (V) - V=V->next(); - else - V=st->get_vertex_array().front();; - int lc = p_lights.size(); - const BakeLight* bl = p_lights.ptr(); - float ofs = cell_size*0.02; - - - for(;V;V=V->next()) { - - SurfaceTool::Vertex &v=V->get(); - - Vector3 vertex = v.vertex + octant_ofs; - //print_line("V GET: "+vertex); - Vector3 normal = tm->get_area_normal( AABB( Vector3(-ofs,-ofs,-ofs)+vertex,Vector3(ofs,ofs,ofs)*2.0)); - if (normal==Vector3()) { - print_line("couldn't find for vertex: "+vertex); - } - ERR_CONTINUE( normal== Vector3()); - - float max_l=1.0; - float max_dist=1.0; - - if (lc) { - - for(int j=0;j<lc;j++) { - const BakeLight &l=bl[j]; - switch(l.type) { - case VS::LIGHT_DIRECTIONAL: { - - Vector3 ray_from=vertex + normal *ofs; - Vector3 ray_to=l.dir*5000; - Vector3 n; - Vector3 p; - if (tm->intersect_segment(ray_from,ray_to,p,n)) { - - float dist = 1.0-l.param[VS::LIGHT_PARAM_SHADOW_DARKENING]; - if (dist<=max_dist) { - max_dist=dist; - max_l=1.0-dist; - } - } - } break; - } - - } - } - - v.color=Color(max_l,max_l,max_l,1.0); - - } - - st->add_to_format(VS::ARRAY_FORMAT_COLOR); - if (m.is_valid()) { - Ref<FixedMaterial> fm = m; - if (fm.is_valid()) - fm->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY,true); - } - } - } - } - } - } - - if (p_prebake) - return; - - g.baked = Ref<Mesh>( memnew( Mesh )); - - for(Map< Ref<Material>, Ref<SurfaceTool> >::Element *E=surfaces.front();E;E=E->next()) { - - Ref<SurfaceTool> st = E->get(); - st->commit(g.baked); - } - - g.bake_instance = VS::get_singleton()->instance_create(); - VS::get_singleton()->instance_set_base(g.bake_instance,g.baked->get_rid()); - - if (is_inside_world()) - _octant_enter_world(p_key); - - g.dirty=true; - _queue_dirty_map(); -} void GridMap::_notification(int p_what) { @@ -1001,8 +710,8 @@ void GridMap::_notification(int p_what) { _update_area_instances(); for(Map<OctantKey,Octant*>::Element *E=octant_map.front();E;E=E->next()) { -// IndexKey ik; -// ik.key = E->key().indexkey; + //IndexKey ik; + //ik.key = E->key().indexkey; _octant_enter_world(E->key()); _octant_update(E->key()); } @@ -1011,10 +720,6 @@ void GridMap::_notification(int p_what) { last_transform=get_global_transform(); - if (use_baked_light) { - - _find_baked_light(); - } } break; case NOTIFICATION_TRANSFORM_CHANGED: { @@ -1036,15 +741,6 @@ void GridMap::_notification(int p_what) { _octant_exit_world(E->key()); } - if (use_baked_light) { - - if (baked_light_instance) { - baked_light_instance->disconnect(SceneStringNames::get_singleton()->baked_light_changed,this,SceneStringNames::get_singleton()->_baked_light_changed); - baked_light_instance=NULL; - } - _baked_light_changed(); - - } //_queue_dirty_map(MAP_DIRTY_INSTANCES|MAP_DIRTY_TRANSFORMS); //_update_dirty_map_callback(); @@ -1122,9 +818,6 @@ void GridMap::_clear_internal(bool p_keep_areas) { VS::get_singleton()->free(F->get().multimesh_instance); } - //unbake just in case - if (E->get()->bake_instance.is_valid()) - VS::get_singleton()->free(E->get()->bake_instance); if (E->get()->collision_debug.is_valid()) VS::get_singleton()->free(E->get()->collision_debug); @@ -1185,60 +878,48 @@ void GridMap::_update_dirty_map_callback() { void GridMap::_bind_methods() { - ObjectTypeDB::bind_method(_MD("set_theme","theme:MeshLibrary"),&GridMap::set_theme); - ObjectTypeDB::bind_method(_MD("get_theme:MeshLibrary"),&GridMap::get_theme); - - ObjectTypeDB::bind_method(_MD("set_bake","enable"),&GridMap::set_bake); - ObjectTypeDB::bind_method(_MD("is_baking_enabled"),&GridMap::is_baking_enabled); - - ObjectTypeDB::bind_method(_MD("set_cell_size","size"),&GridMap::set_cell_size); - ObjectTypeDB::bind_method(_MD("get_cell_size"),&GridMap::get_cell_size); - - ObjectTypeDB::bind_method(_MD("set_octant_size","size"),&GridMap::set_octant_size); - ObjectTypeDB::bind_method(_MD("get_octant_size"),&GridMap::get_octant_size); + ClassDB::bind_method(D_METHOD("set_theme","theme:MeshLibrary"),&GridMap::set_theme); + ClassDB::bind_method(D_METHOD("get_theme:MeshLibrary"),&GridMap::get_theme); - ObjectTypeDB::bind_method(_MD("set_cell_item","x","y","z","item","orientation"),&GridMap::set_cell_item,DEFVAL(0)); - ObjectTypeDB::bind_method(_MD("get_cell_item","x","y","z"),&GridMap::get_cell_item); - ObjectTypeDB::bind_method(_MD("get_cell_item_orientation","x","y","z"),&GridMap::get_cell_item_orientation); + ClassDB::bind_method(D_METHOD("set_cell_size","size"),&GridMap::set_cell_size); + ClassDB::bind_method(D_METHOD("get_cell_size"),&GridMap::get_cell_size); -// ObjectTypeDB::bind_method(_MD("_recreate_octants"),&GridMap::_recreate_octants); - ObjectTypeDB::bind_method(_MD("_update_dirty_map_callback"),&GridMap::_update_dirty_map_callback); - ObjectTypeDB::bind_method(_MD("resource_changed","resource"),&GridMap::resource_changed); + ClassDB::bind_method(D_METHOD("set_octant_size","size"),&GridMap::set_octant_size); + ClassDB::bind_method(D_METHOD("get_octant_size"),&GridMap::get_octant_size); - ObjectTypeDB::bind_method(_MD("set_center_x","enable"),&GridMap::set_center_x); - ObjectTypeDB::bind_method(_MD("get_center_x"),&GridMap::get_center_x); - ObjectTypeDB::bind_method(_MD("set_center_y","enable"),&GridMap::set_center_y); - ObjectTypeDB::bind_method(_MD("get_center_y"),&GridMap::get_center_y); - ObjectTypeDB::bind_method(_MD("set_center_z","enable"),&GridMap::set_center_z); - ObjectTypeDB::bind_method(_MD("get_center_z"),&GridMap::get_center_z); + ClassDB::bind_method(D_METHOD("set_cell_item","x","y","z","item","orientation"),&GridMap::set_cell_item,DEFVAL(0)); + ClassDB::bind_method(D_METHOD("get_cell_item","x","y","z"),&GridMap::get_cell_item); + ClassDB::bind_method(D_METHOD("get_cell_item_orientation","x","y","z"),&GridMap::get_cell_item_orientation); - ObjectTypeDB::bind_method(_MD("set_clip","enabled","clipabove","floor","axis"),&GridMap::set_clip,DEFVAL(true),DEFVAL(0),DEFVAL(Vector3::AXIS_X)); + //ClassDB::bind_method(D_METHOD("_recreate_octants"),&GridMap::_recreate_octants); + ClassDB::bind_method(D_METHOD("_update_dirty_map_callback"),&GridMap::_update_dirty_map_callback); + ClassDB::bind_method(D_METHOD("resource_changed","resource"),&GridMap::resource_changed); - ObjectTypeDB::bind_method(_MD("create_area","id","area"),&GridMap::create_area); - ObjectTypeDB::bind_method(_MD("area_get_bounds","area","bounds"),&GridMap::area_get_bounds); - ObjectTypeDB::bind_method(_MD("area_set_exterior_portal","area","enable"),&GridMap::area_set_exterior_portal); - ObjectTypeDB::bind_method(_MD("area_set_name","area","name"),&GridMap::area_set_name); - ObjectTypeDB::bind_method(_MD("area_get_name","area"),&GridMap::area_get_name); - ObjectTypeDB::bind_method(_MD("area_is_exterior_portal","area"),&GridMap::area_is_exterior_portal); - ObjectTypeDB::bind_method(_MD("area_set_portal_disable_distance","area","distance"),&GridMap::area_set_portal_disable_distance); - ObjectTypeDB::bind_method(_MD("area_get_portal_disable_distance","area"),&GridMap::area_get_portal_disable_distance); - ObjectTypeDB::bind_method(_MD("area_set_portal_disable_color","area","color"),&GridMap::area_set_portal_disable_color); - ObjectTypeDB::bind_method(_MD("area_get_portal_disable_color","area"),&GridMap::area_get_portal_disable_color); - ObjectTypeDB::bind_method(_MD("erase_area","area"),&GridMap::erase_area); - ObjectTypeDB::bind_method(_MD("get_unused_area_id","area"),&GridMap::get_unused_area_id); - ObjectTypeDB::bind_method(_MD("bake_geometry"),&GridMap::bake_geometry); + ClassDB::bind_method(D_METHOD("set_center_x","enable"),&GridMap::set_center_x); + ClassDB::bind_method(D_METHOD("get_center_x"),&GridMap::get_center_x); + ClassDB::bind_method(D_METHOD("set_center_y","enable"),&GridMap::set_center_y); + ClassDB::bind_method(D_METHOD("get_center_y"),&GridMap::get_center_y); + ClassDB::bind_method(D_METHOD("set_center_z","enable"),&GridMap::set_center_z); + ClassDB::bind_method(D_METHOD("get_center_z"),&GridMap::get_center_z); - ObjectTypeDB::bind_method(_MD("_baked_light_changed"),&GridMap::_baked_light_changed); - ObjectTypeDB::bind_method(_MD("set_use_baked_light","use"),&GridMap::set_use_baked_light); - ObjectTypeDB::bind_method(_MD("is_using_baked_light","use"),&GridMap::is_using_baked_light); + ClassDB::bind_method(D_METHOD("set_clip","enabled","clipabove","floor","axis"),&GridMap::set_clip,DEFVAL(true),DEFVAL(0),DEFVAL(Vector3::AXIS_X)); - ObjectTypeDB::bind_method(_MD("_get_baked_light_meshes"),&GridMap::_get_baked_light_meshes); + ClassDB::bind_method(D_METHOD("create_area","id","area"),&GridMap::create_area); + ClassDB::bind_method(D_METHOD("area_get_bounds","area","bounds"),&GridMap::area_get_bounds); + ClassDB::bind_method(D_METHOD("area_set_exterior_portal","area","enable"),&GridMap::area_set_exterior_portal); + ClassDB::bind_method(D_METHOD("area_set_name","area","name"),&GridMap::area_set_name); + ClassDB::bind_method(D_METHOD("area_get_name","area"),&GridMap::area_get_name); + ClassDB::bind_method(D_METHOD("area_is_exterior_portal","area"),&GridMap::area_is_exterior_portal); + ClassDB::bind_method(D_METHOD("area_set_portal_disable_distance","area","distance"),&GridMap::area_set_portal_disable_distance); + ClassDB::bind_method(D_METHOD("area_get_portal_disable_distance","area"),&GridMap::area_get_portal_disable_distance); + ClassDB::bind_method(D_METHOD("area_set_portal_disable_color","area","color"),&GridMap::area_set_portal_disable_color); + ClassDB::bind_method(D_METHOD("area_get_portal_disable_color","area"),&GridMap::area_get_portal_disable_color); + ClassDB::bind_method(D_METHOD("erase_area","area"),&GridMap::erase_area); + ClassDB::bind_method(D_METHOD("get_unused_area_id","area"),&GridMap::get_unused_area_id); + ClassDB::bind_method(D_METHOD("clear"),&GridMap::clear); - - ObjectTypeDB::set_method_flags("GridMap","bake_geometry",METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR); - - ObjectTypeDB::bind_method(_MD("clear"),&GridMap::clear); + ClassDB::bind_method(D_METHOD("get_meshes"),&GridMap::get_meshes); BIND_CONSTANT( INVALID_CELL_ITEM ); @@ -1435,7 +1116,7 @@ void GridMap::_update_area_instances() { } -Error GridMap::create_area(int p_id,const AABB& p_bounds) { +Error GridMap::create_area(int p_id,const Rect3& p_bounds) { ERR_FAIL_COND_V(area_map.has(p_id),ERR_ALREADY_EXISTS); ERR_EXPLAIN("ID 0 is taken as global area, start from 1"); @@ -1484,12 +1165,12 @@ Error GridMap::create_area(int p_id,const AABB& p_bounds) { return OK; } -AABB GridMap::area_get_bounds(int p_area) const { +Rect3 GridMap::area_get_bounds(int p_area) const { - ERR_FAIL_COND_V(!area_map.has(p_area),AABB()); + ERR_FAIL_COND_V(!area_map.has(p_area),Rect3()); const Area *a = area_map[p_area]; - AABB aabb; + Rect3 aabb; aabb.pos=Vector3(a->from.x,a->from.y,a->from.z); aabb.size=Vector3(a->to.x,a->to.y,a->to.z)-aabb.pos; @@ -1622,23 +1303,6 @@ int GridMap::get_unused_area_id() const { return area_map.back()->key()+1; } - -void GridMap::set_bake(bool p_bake) { - - bake=p_bake; - if (bake==false) { - for(Map<OctantKey,Octant*>::Element *E=octant_map.front();E;E=E->next()) { - - _octant_clear_baked(E->key()); - } - } -} - -bool GridMap::is_baking_enabled() const { - - return bake; -} - void GridMap::set_cell_scale(float p_scale) { cell_scale=p_scale; @@ -1652,98 +1316,8 @@ float GridMap::get_cell_scale() const{ -void GridMap::bake_geometry() { - - //used to compute vertex occlusion - Ref<TriangleMesh> tmesh; - Vector<BakeLight> lights; - - if (true) { - - List<Vector3> vertices; - - for(Map<OctantKey,Octant*>::Element *E=octant_map.front();E;E=E->next()) { - _octant_bake(E->key(),tmesh,lights,&vertices); - - } - - DVector<Vector3> vv; - vv.fill_with(vertices); - //print_line("TOTAL VERTICES: "+itos(vv.size())); - tmesh = Ref<TriangleMesh>( memnew( TriangleMesh )); - tmesh->create(vv); - - - for(int i=0;i<get_child_count();i++) { - - if (get_child(i)->cast_to<Light>()) { - Light *l = get_child(i)->cast_to<Light>(); - BakeLight bl; - for(int i=0;i<Light::PARAM_MAX;i++) { - bl.param[i]=l->get_parameter(Light::Parameter(i)); - } - Transform t=l->get_global_transform(); - bl.pos=t.origin; - bl.dir=t.basis.get_axis(2); - bl.type=l->get_light_type(); - lights.push_back(bl); - - } - } - } - - int idx=0; - for(Map<OctantKey,Octant*>::Element *E=octant_map.front();E;E=E->next()) { - if (E->get()->baked.is_valid()) - _octant_clear_baked(E->key()); - - _octant_bake(E->key(),tmesh,lights); - print_line("baking "+itos(idx)+"/"+itos(octant_map.size())); - idx++; - } - -} - -void GridMap::_baked_light_changed() { - -// if (!baked_light_instance) -// VS::get_singleton()->instance_geometry_set_baked_light(get_instance(),RID()); -// else -// VS::get_singleton()->instance_geometry_set_baked_light(get_instance(),baked_light_instance->get_baked_light_instance()); - for(Map<OctantKey,Octant*>::Element *E=octant_map.front();E;E=E->next()) { - - for(Map<int,Octant::ItemInstances>::Element *F=E->get()->items.front();F;F=F->next()) { - - VS::get_singleton()->instance_geometry_set_baked_light(F->get().multimesh_instance,baked_light_instance?baked_light_instance->get_baked_light_instance():RID()); - } - - } - -} - -void GridMap::_find_baked_light() { - - Node *n=get_parent(); - while(n) { - - BakedLightInstance *bl=n->cast_to<BakedLightInstance>(); - if (bl) { - - baked_light_instance=bl; - baked_light_instance->connect(SceneStringNames::get_singleton()->baked_light_changed,this,SceneStringNames::get_singleton()->_baked_light_changed); - _baked_light_changed(); - return; - } - - n=n->get_parent(); - } - - _baked_light_changed(); -} - - -Array GridMap::_get_baked_light_meshes() { +Array GridMap::get_meshes() { if (theme.is_null()) return Array(); @@ -1781,31 +1355,6 @@ Array GridMap::_get_baked_light_meshes() { return meshes; } -void GridMap::set_use_baked_light(bool p_use) { - - if (use_baked_light==p_use) - return; - - use_baked_light=p_use; - - if (is_inside_world()) { - if (!p_use) { - if (baked_light_instance) { - baked_light_instance->disconnect(SceneStringNames::get_singleton()->baked_light_changed,this,SceneStringNames::get_singleton()->_baked_light_changed); - baked_light_instance=NULL; - } - _baked_light_changed(); - } else { - _find_baked_light(); - } - } - -} - -bool GridMap::is_using_baked_light() const{ - - return use_baked_light; -} @@ -1823,14 +1372,11 @@ GridMap::GridMap() { clip_floor=0; clip_axis=Vector3::AXIS_Z; clip_above=true; - baked_lock=false; - bake=false; cell_scale=1.0; - baked_light_instance=NULL; - use_baked_light=false; navigation = NULL; + set_notify_transform(true); } diff --git a/modules/gridmap/grid_map.h b/modules/gridmap/grid_map.h index 0116ea094f..5d4133383b 100644 --- a/modules/gridmap/grid_map.h +++ b/modules/gridmap/grid_map.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -44,7 +44,7 @@ class BakedLightInstance; class GridMap : public Spatial { - OBJ_TYPE( GridMap, Spatial ); + GDCLASS( GridMap, Spatial ); enum { MAP_DIRTY_TRANSFORMS=1, @@ -103,8 +103,6 @@ class GridMap : public Spatial { Ref<NavigationMesh> navmesh; }; - Ref<Mesh> baked; - RID bake_instance; RID collision_debug; RID collision_debug_instance; @@ -140,14 +138,12 @@ class GridMap : public Spatial { float cell_size; int octant_size; bool center_x,center_y,center_z; - bool bake; float cell_scale; Navigation *navigation; bool clip; bool clip_above; int clip_floor; - bool baked_lock; Vector3::Axis clip_axis; @@ -205,9 +201,7 @@ class GridMap : public Spatial { void _octant_exit_world(const OctantKey &p_key); void _octant_update(const OctantKey &p_key); void _octant_transform(const OctantKey &p_key); - void _octant_clear_baked(const OctantKey &p_key); void _octant_clear_navmesh(const GridMap::OctantKey&); - void _octant_bake(const OctantKey &p_key,const Ref<TriangleMesh>& p_tmesh=RES(),const Vector<BakeLight> &p_lights=Vector<BakeLight>(),List<Vector3> *r_prebake=NULL); bool awaiting_update; void _queue_dirty_map(); @@ -221,14 +215,6 @@ class GridMap : public Spatial { void _clear_internal(bool p_keep_areas=false); - BakedLightInstance *baked_light_instance; - bool use_baked_light; - void _find_baked_light(); - void _baked_light_changed(); - - - Array _get_baked_light_meshes(); - protected: bool _set(const StringName& p_name, const Variant& p_value); @@ -268,8 +254,8 @@ public: void set_clip(bool p_enabled, bool p_clip_above=true, int p_floor=0, Vector3::Axis p_axis=Vector3::AXIS_X); - Error create_area(int p_id,const AABB& p_area); - AABB area_get_bounds(int p_area) const; + Error create_area(int p_id,const Rect3& p_area); + Rect3 area_get_bounds(int p_area) const; void area_set_exterior_portal(int p_area,bool p_enable); void area_set_name(int p_area,const String& p_name); String area_get_name(int p_area) const; @@ -285,13 +271,11 @@ public: void set_cell_scale(float p_scale); float get_cell_scale() const; - void set_bake(bool p_bake); - bool is_baking_enabled() const; - void bake_geometry(); - void set_use_baked_light(bool p_use); - bool is_using_baked_light() const; + Array get_meshes(); + + void clear(); GridMap(); diff --git a/modules/gridmap/grid_map_editor_plugin.cpp b/modules/gridmap/grid_map_editor_plugin.cpp index 9bdad6713d..2630360058 100644 --- a/modules/gridmap/grid_map_editor_plugin.cpp +++ b/modules/gridmap/grid_map_editor_plugin.cpp @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -99,70 +99,70 @@ void GridMapEditor::_menu_option(int p_option) { } break; case MENU_OPTION_CURSOR_ROTATE_Y: { - Matrix3 r; + Basis r; if (input_action==INPUT_DUPLICATE) { r.set_orthogonal_index(selection.duplicate_rot); - r.rotate(Vector3(0,1,0),Math_PI/2.0); + r.rotate(Vector3(0,1,0),-Math_PI/2.0); selection.duplicate_rot=r.get_orthogonal_index(); _update_duplicate_indicator(); break; } r.set_orthogonal_index(cursor_rot); - r.rotate(Vector3(0,1,0),Math_PI/2.0); + r.rotate(Vector3(0,1,0),-Math_PI/2.0); cursor_rot=r.get_orthogonal_index(); _update_cursor_transform(); } break; case MENU_OPTION_CURSOR_ROTATE_X: { - Matrix3 r; + Basis r; if (input_action==INPUT_DUPLICATE) { r.set_orthogonal_index(selection.duplicate_rot); - r.rotate(Vector3(1,0,0),Math_PI/2.0); + r.rotate(Vector3(1,0,0),-Math_PI/2.0); selection.duplicate_rot=r.get_orthogonal_index(); _update_duplicate_indicator(); break; } r.set_orthogonal_index(cursor_rot); - r.rotate(Vector3(1,0,0),Math_PI/2.0); + r.rotate(Vector3(1,0,0),-Math_PI/2.0); cursor_rot=r.get_orthogonal_index(); _update_cursor_transform(); } break; case MENU_OPTION_CURSOR_ROTATE_Z: { - Matrix3 r; + Basis r; if (input_action==INPUT_DUPLICATE) { r.set_orthogonal_index(selection.duplicate_rot); - r.rotate(Vector3(0,0,1),Math_PI/2.0); + r.rotate(Vector3(0,0,1),-Math_PI/2.0); selection.duplicate_rot=r.get_orthogonal_index(); _update_duplicate_indicator(); break; } r.set_orthogonal_index(cursor_rot); - r.rotate(Vector3(0,0,1),Math_PI/2.0); + r.rotate(Vector3(0,0,1),-Math_PI/2.0); cursor_rot=r.get_orthogonal_index(); _update_cursor_transform(); } break; case MENU_OPTION_CURSOR_BACK_ROTATE_Y: { - Matrix3 r; + Basis r; r.set_orthogonal_index(cursor_rot); - r.rotate(Vector3(0,1,0),-Math_PI/2.0); + r.rotate(Vector3(0,1,0),Math_PI/2.0); cursor_rot=r.get_orthogonal_index(); _update_cursor_transform(); } break; case MENU_OPTION_CURSOR_BACK_ROTATE_X: { - Matrix3 r; + Basis r; r.set_orthogonal_index(cursor_rot); - r.rotate(Vector3(1,0,0),-Math_PI/2.0); + r.rotate(Vector3(1,0,0),Math_PI/2.0); cursor_rot=r.get_orthogonal_index(); _update_cursor_transform(); } break; case MENU_OPTION_CURSOR_BACK_ROTATE_Z: { - Matrix3 r; + Basis r; r.set_orthogonal_index(cursor_rot); - r.rotate(Vector3(0,0,1),-Math_PI/2.0); + r.rotate(Vector3(0,0,1),Math_PI/2.0); cursor_rot=r.get_orthogonal_index(); _update_cursor_transform(); } break; @@ -191,7 +191,7 @@ void GridMapEditor::_menu_option(int p_option) { if (!selection.active) break; int area = node->get_unused_area_id(); - Error err = node->create_area(area,AABB(selection.begin,selection.end-selection.begin+Vector3(1,1,1))); + Error err = node->create_area(area,Rect3(selection.begin,selection.end-selection.begin+Vector3(1,1,1))); if (err!=OK) { @@ -249,7 +249,7 @@ void GridMapEditor::_update_cursor_transform() { if (cursor_instance.is_valid()) { VisualServer::get_singleton()->instance_set_transform(cursor_instance,cursor_transform); - VisualServer::get_singleton()->instance_geometry_set_flag(cursor_instance,VS::INSTANCE_FLAG_VISIBLE,cursor_visible); + VisualServer::get_singleton()->instance_set_visible(cursor_instance,cursor_visible); } } @@ -318,7 +318,7 @@ bool GridMapEditor::do_input_action(Camera* p_camera,const Point2& p_point,bool p.d=edit_floor[edit_axis]*node->get_cell_size(); Vector3 inters; - if (!p.intersects_segment(from, from + normal * settings_pick_distance->get_val(), &inters)) + if (!p.intersects_segment(from, from + normal * settings_pick_distance->get_value(), &inters)) return false; @@ -358,7 +358,7 @@ bool GridMapEditor::do_input_action(Camera* p_camera,const Point2& p_point,bool } last_mouseover=Vector3(cell[0],cell[1],cell[2]); - VS::get_singleton()->instance_set_transform(grid_instance[edit_axis],Transform(Matrix3(),grid_ofs)); + VS::get_singleton()->instance_set_transform(grid_instance[edit_axis],Transform(Basis(),grid_ofs)); if (cursor_instance.is_valid()) { @@ -459,7 +459,7 @@ void GridMapEditor::_update_duplicate_indicator() { Transform xf; xf.scale(Vector3(1,1,1)*(Vector3(1,1,1)+(selection.end-selection.begin))*node->get_cell_size()); xf.origin=(selection.begin+(selection.current-selection.click))*node->get_cell_size(); - Matrix3 rot; + Basis rot; rot.set_orthogonal_index(selection.duplicate_rot); xf.basis = rot * xf.basis; @@ -481,7 +481,7 @@ void GridMapEditor::_duplicate_paste() { List< __Item > items; - Matrix3 rot; + Basis rot; rot.set_orthogonal_index(selection.duplicate_rot); for(int i=selection.begin.x;i<=selection.end.x;i++) { @@ -498,7 +498,7 @@ void GridMapEditor::_duplicate_paste() { Vector3 rel=Vector3(i,j,k)-selection.begin; rel = rot.xform(rel); - Matrix3 orm; + Basis orm; orm.set_orthogonal_index(orientation); orm = rot * orm; @@ -548,12 +548,12 @@ bool GridMapEditor::forward_spatial_input_event(Camera* p_camera,const InputEven if (p_event.mouse_button.button_index==BUTTON_WHEEL_UP && (p_event.mouse_button.mod.command || p_event.mouse_button.mod.shift)) { if (p_event.mouse_button.pressed) - floor->set_val( floor->get_val() +1); + floor->set_value( floor->get_value() +1); return true; //eaten } else if (p_event.mouse_button.button_index==BUTTON_WHEEL_DOWN && (p_event.mouse_button.mod.command || p_event.mouse_button.mod.shift)) { if (p_event.mouse_button.pressed) - floor->set_val( floor->get_val() -1); + floor->set_value( floor->get_value() -1); return true; } @@ -664,7 +664,7 @@ bool GridMapEditor::forward_spatial_input_event(Camera* p_camera,const InputEven for(List<int>::Element *E=areas.front();E;E=E->next()) { int area = E->get(); - AABB aabb = node->area_get_bounds(area); + Rect3 aabb = node->area_get_bounds(area); aabb.pos*=node->get_cell_size(); aabb.size*=node->get_cell_size(); @@ -731,7 +731,7 @@ void GridMapEditor::update_pallete() { theme_pallete->set_icon_mode(ItemList::ICON_MODE_LEFT); } - float min_size = EDITOR_DEF("grid_map/preview_size",64); + float min_size = EDITOR_DEF("editors/grid_map/preview_size",64); theme_pallete->set_fixed_icon_size(Size2(min_size, min_size)); theme_pallete->set_fixed_column_width(min_size*3/2); theme_pallete->set_max_text_lines(2); @@ -852,11 +852,11 @@ void GridMapEditor::edit(GridMap *p_gridmap) { if (!node) { set_process(false); for(int i=0;i<3;i++) { - VisualServer::get_singleton()->instance_geometry_set_flag(grid_instance[i],VS::INSTANCE_FLAG_VISIBLE,false); + VisualServer::get_singleton()->instance_set_visible(grid_instance[i],false); } - VisualServer::get_singleton()->instance_geometry_set_flag(cursor_instance, VS::INSTANCE_FLAG_VISIBLE,false); + VisualServer::get_singleton()->instance_set_visible(cursor_instance,false); _clear_areas(); @@ -884,13 +884,11 @@ void GridMapEditor::edit(GridMap *p_gridmap) { { //update grids - indicator_mat = VisualServer::get_singleton()->fixed_material_create(); - VisualServer::get_singleton()->material_set_flag( indicator_mat, VisualServer::MATERIAL_FLAG_UNSHADED, true ); - VisualServer::get_singleton()->material_set_flag( indicator_mat, VisualServer::MATERIAL_FLAG_ONTOP, false ); - - VisualServer::get_singleton()->fixed_material_set_param(indicator_mat,VisualServer::FIXED_MATERIAL_PARAM_DIFFUSE,Color(0.8,0.5,0.1)); - VisualServer::get_singleton()->fixed_material_set_flag( indicator_mat, VisualServer::FIXED_MATERIAL_FLAG_USE_ALPHA, true ); - VisualServer::get_singleton()->fixed_material_set_flag( indicator_mat, VisualServer::FIXED_MATERIAL_FLAG_USE_COLOR_ARRAY, true ); + indicator_mat.instance(); + indicator_mat->set_flag(FixedSpatialMaterial::FLAG_UNSHADED,true); + indicator_mat->set_flag(FixedSpatialMaterial::FLAG_SRGB_VERTEX_COLOR,true); + indicator_mat->set_flag(FixedSpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR,true); + indicator_mat->set_albedo(Color(0.8,0.5,0.1)); Vector<Vector3> grid_points[3]; @@ -903,7 +901,7 @@ void GridMapEditor::edit(GridMap *p_gridmap) { Vector3 axis; axis[i]=1; Vector3 axis_n1; - axis_n1[(i+1)%3]=cell_size[(i+1)%3];; + axis_n1[(i+1)%3]=cell_size[(i+1)%3]; Vector3 axis_n2; axis_n2[(i+2)%3]=cell_size[(i+2)%3]; @@ -937,8 +935,8 @@ void GridMapEditor::edit(GridMap *p_gridmap) { d.resize(VS::ARRAY_MAX); d[VS::ARRAY_VERTEX]=grid_points[i]; d[VS::ARRAY_COLOR]=grid_colors[i]; - VisualServer::get_singleton()->mesh_add_surface(grid[i],VisualServer::PRIMITIVE_LINES,d); - VisualServer::get_singleton()->mesh_surface_set_material(grid[i],0,indicator_mat); + VisualServer::get_singleton()->mesh_add_surface_from_arrays(grid[i],VisualServer::PRIMITIVE_LINES,d); + VisualServer::get_singleton()->mesh_surface_set_material(grid[i],0,indicator_mat->get_rid()); } @@ -972,16 +970,16 @@ void GridMapEditor::update_grid() { grid_ofs[edit_axis]=edit_floor[edit_axis]*node->get_cell_size(); edit_grid_xform.origin=grid_ofs; - edit_grid_xform.basis=Matrix3(); + edit_grid_xform.basis=Basis(); for(int i=0;i<3;i++) { - VisualServer::get_singleton()->instance_geometry_set_flag(grid_instance[i],VS::INSTANCE_FLAG_VISIBLE,i==edit_axis); + VisualServer::get_singleton()->instance_set_visible(grid_instance[i],i==edit_axis); } updating=true; - floor->set_val(edit_floor[edit_axis]); + floor->set_value(edit_floor[edit_axis]); updating=false; } @@ -1103,7 +1101,7 @@ void GridMapEditor::_update_areas_display() { if (!node) { return; } - +#if 0 _clear_areas(); List<int> areas; node->get_area_list(&areas); @@ -1118,6 +1116,8 @@ void GridMapEditor::_update_areas_display() { color=Color(1,1,1,0.2); else color.set_hsv(Math::fmod(area*0.37,1),Math::fmod(area*0.75,1),1.0,0.2); + + RID material = VisualServer::get_singleton()->fixed_material_create(); VisualServer::get_singleton()->fixed_material_set_param( material, VS::FIXED_MATERIAL_PARAM_DIFFUSE,color ); VisualServer::get_singleton()->fixed_material_set_param( material, VS::FIXED_MATERIAL_PARAM_EMISSION,0.5 ); @@ -1126,7 +1126,7 @@ void GridMapEditor::_update_areas_display() { RID mesh = VisualServer::get_singleton()->mesh_create(); - DVector<Plane> planes; + PoolVector<Plane> planes; for(int i=0;i<3;i++) { Vector3 axis; @@ -1142,14 +1142,14 @@ void GridMapEditor::_update_areas_display() { ad.mesh=mesh; ad.instance = VisualServer::get_singleton()->instance_create2(mesh,node->get_world()->get_scenario()); Transform xform; - AABB aabb = node->area_get_bounds(area); + Rect3 aabb = node->area_get_bounds(area); xform.origin=aabb.pos * node->get_cell_size(); xform.basis.scale(aabb.size * node->get_cell_size()); VisualServer::get_singleton()->instance_set_transform(ad.instance,global_xf * xform); this->areas.push_back(ad); } - +#endif } void GridMapEditor::_edit_mode_changed(int p_what) { @@ -1181,15 +1181,15 @@ void GridMapEditor::_floor_changed(float p_value) { void GridMapEditor::_bind_methods() { - ObjectTypeDB::bind_method("_menu_option",&GridMapEditor::_menu_option); - ObjectTypeDB::bind_method("_configure",&GridMapEditor::_configure); - ObjectTypeDB::bind_method("_item_selected_cbk",&GridMapEditor::_item_selected_cbk); - ObjectTypeDB::bind_method("_edit_mode_changed",&GridMapEditor::_edit_mode_changed); - ObjectTypeDB::bind_method("_area_renamed",&GridMapEditor::_area_renamed); - ObjectTypeDB::bind_method("_area_selected",&GridMapEditor::_area_selected); - ObjectTypeDB::bind_method("_floor_changed",&GridMapEditor::_floor_changed); + ClassDB::bind_method("_menu_option",&GridMapEditor::_menu_option); + ClassDB::bind_method("_configure",&GridMapEditor::_configure); + ClassDB::bind_method("_item_selected_cbk",&GridMapEditor::_item_selected_cbk); + ClassDB::bind_method("_edit_mode_changed",&GridMapEditor::_edit_mode_changed); + ClassDB::bind_method("_area_renamed",&GridMapEditor::_area_renamed); + ClassDB::bind_method("_area_selected",&GridMapEditor::_area_selected); + ClassDB::bind_method("_floor_changed",&GridMapEditor::_floor_changed); - ObjectTypeDB::bind_method(_MD("_set_display_mode","mode"), &GridMapEditor::_set_display_mode); + ClassDB::bind_method(D_METHOD("_set_display_mode","mode"), &GridMapEditor::_set_display_mode); } @@ -1201,7 +1201,7 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) { editor=p_editor; undo_redo=p_editor->get_undo_redo(); - int mw = EDITOR_DEF("grid_map/palette_min_width",230); + int mw = EDITOR_DEF("editors/grid_map/palette_min_width",230); Control *ec = memnew( Control); ec->set_custom_minimum_size(Size2(mw,0)); add_child(ec); @@ -1257,17 +1257,16 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) { settings_vbc = memnew(VBoxContainer); settings_vbc->set_custom_minimum_size(Size2(200, 0)); settings_dialog->add_child(settings_vbc); - settings_dialog->set_child_rect(settings_vbc); settings_pick_distance = memnew(SpinBox); settings_pick_distance->set_max(10000.0f); settings_pick_distance->set_min(500.0f); settings_pick_distance->set_step(1.0f); - settings_pick_distance->set_val(EDITOR_DEF("grid_map/pick_distance", 5000.0)); + settings_pick_distance->set_value(EDITOR_DEF("editors/grid_map/pick_distance", 5000.0)); settings_vbc->add_margin_child("Pick Distance:", settings_pick_distance); clip_mode=CLIP_DISABLED; - options->get_popup()->connect("item_pressed", this,"_menu_option"); + options->get_popup()->connect("id_pressed", this,"_menu_option"); HBoxContainer *hb = memnew( HBoxContainer ); add_child(hb); @@ -1275,8 +1274,8 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) { edit_mode = memnew(OptionButton); edit_mode->set_area_as_parent_rect(); - edit_mode->set_anchor_and_margin(MARGIN_BOTTOM,ANCHOR_BEGIN,24);; - edit_mode->set_anchor_and_margin(MARGIN_RIGHT,ANCHOR_END,14);; + edit_mode->set_anchor_and_margin(MARGIN_BOTTOM,ANCHOR_BEGIN,24); + edit_mode->set_anchor_and_margin(MARGIN_RIGHT,ANCHOR_END,14); edit_mode->add_item("Tiles"); edit_mode->add_item("Areas"); hb->add_child(edit_mode); @@ -1296,6 +1295,8 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) { hb->add_child(mode_list); mode_list->connect("pressed", this, "_set_display_mode", varray(DISPLAY_LIST)); + EDITOR_DEF("editors/grid_map/preview_size",64); + display_mode = DISPLAY_THUMBNAIL; selected_area=-1; @@ -1341,8 +1342,8 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) { //selection mesh create - DVector<Vector3> lines; - DVector<Vector3> triangles; + PoolVector<Vector3> lines; + PoolVector<Vector3> triangles; for (int i=0;i<6;i++) { @@ -1376,7 +1377,7 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) { for(int i=0;i<12;i++) { - AABB base(Vector3(0,0,0),Vector3(1,1,1)); + Rect3 base(Vector3(0,0,0),Vector3(1,1,1)); Vector3 a,b; base.get_edge(i,a,b); lines.push_back(a); @@ -1386,52 +1387,36 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) { Array d; d.resize(VS::ARRAY_MAX); - inner_mat = VisualServer::get_singleton()->fixed_material_create(); - VisualServer::get_singleton()->fixed_material_set_param(inner_mat,VS::FIXED_MATERIAL_PARAM_DIFFUSE,Color(0.7,0.7,1.0,0.3)); - VisualServer::get_singleton()->material_set_flag(inner_mat,VS::MATERIAL_FLAG_ONTOP,true); - VisualServer::get_singleton()->material_set_flag(inner_mat,VS::MATERIAL_FLAG_UNSHADED,true); - VisualServer::get_singleton()->fixed_material_set_flag( inner_mat, VisualServer::FIXED_MATERIAL_FLAG_USE_ALPHA, true ); + inner_mat.instance(); + inner_mat->set_albedo(Color(0.7,0.7,1.0,0.3)); + inner_mat->set_flag(FixedSpatialMaterial::FLAG_ONTOP,true); + inner_mat->set_flag(FixedSpatialMaterial::FLAG_UNSHADED,true); + inner_mat->set_feature(FixedSpatialMaterial::FEATURE_TRANSPARENT,true); d[VS::ARRAY_VERTEX]=triangles; - VisualServer::get_singleton()->mesh_add_surface(selection_mesh,VS::PRIMITIVE_TRIANGLES,d); - VisualServer::get_singleton()->mesh_surface_set_material(selection_mesh,0,inner_mat); + VisualServer::get_singleton()->mesh_add_surface_from_arrays(selection_mesh,VS::PRIMITIVE_TRIANGLES,d); + VisualServer::get_singleton()->mesh_surface_set_material(selection_mesh,0,inner_mat->get_rid()); - outer_mat = VisualServer::get_singleton()->fixed_material_create(); - VisualServer::get_singleton()->fixed_material_set_param(outer_mat,VS::FIXED_MATERIAL_PARAM_DIFFUSE,Color(0.7,0.7,1.0,0.8)); - VisualServer::get_singleton()->material_set_line_width(outer_mat,3.0); - VisualServer::get_singleton()->material_set_flag(outer_mat,VS::MATERIAL_FLAG_ONTOP,true); - VisualServer::get_singleton()->material_set_flag(outer_mat,VS::MATERIAL_FLAG_UNSHADED,true); - VisualServer::get_singleton()->fixed_material_set_flag( outer_mat, VisualServer::FIXED_MATERIAL_FLAG_USE_ALPHA, true ); + outer_mat.instance(); + outer_mat->set_albedo(Color(0.7,0.7,1.0,0.3)); + outer_mat->set_flag(FixedSpatialMaterial::FLAG_ONTOP,true); + outer_mat->set_flag(FixedSpatialMaterial::FLAG_UNSHADED,true); + outer_mat->set_line_width(3.0); + outer_mat->set_feature(FixedSpatialMaterial::FEATURE_TRANSPARENT,true); d[VS::ARRAY_VERTEX]=lines; - VisualServer::get_singleton()->mesh_add_surface(selection_mesh,VS::PRIMITIVE_LINES,d); - VisualServer::get_singleton()->mesh_surface_set_material(selection_mesh,1,outer_mat); - - - inner_mat_dup = VisualServer::get_singleton()->fixed_material_create(); - VisualServer::get_singleton()->fixed_material_set_param(inner_mat_dup,VS::FIXED_MATERIAL_PARAM_DIFFUSE,Color(1.0,0.7,0.7,0.3)); - VisualServer::get_singleton()->material_set_flag(inner_mat_dup,VS::MATERIAL_FLAG_ONTOP,true); - VisualServer::get_singleton()->material_set_flag(inner_mat_dup,VS::MATERIAL_FLAG_UNSHADED,true); - VisualServer::get_singleton()->fixed_material_set_flag( inner_mat_dup, VisualServer::FIXED_MATERIAL_FLAG_USE_ALPHA, true ); - + VisualServer::get_singleton()->mesh_add_surface_from_arrays(selection_mesh,VS::PRIMITIVE_LINES,d); + VisualServer::get_singleton()->mesh_surface_set_material(selection_mesh,1,outer_mat->get_rid()); d[VS::ARRAY_VERTEX]=triangles; - VisualServer::get_singleton()->mesh_add_surface(duplicate_mesh,VS::PRIMITIVE_TRIANGLES,d); - VisualServer::get_singleton()->mesh_surface_set_material(duplicate_mesh,0,inner_mat_dup); - - outer_mat_dup = VisualServer::get_singleton()->fixed_material_create(); - VisualServer::get_singleton()->fixed_material_set_param(outer_mat_dup,VS::FIXED_MATERIAL_PARAM_DIFFUSE,Color(1.0,0.7,0.7,0.8)); - VisualServer::get_singleton()->material_set_line_width(outer_mat_dup,3.0); - VisualServer::get_singleton()->material_set_flag(outer_mat_dup,VS::MATERIAL_FLAG_ONTOP,true); - VisualServer::get_singleton()->material_set_flag(outer_mat_dup,VS::MATERIAL_FLAG_UNSHADED,true); - VisualServer::get_singleton()->fixed_material_set_flag( outer_mat_dup, VisualServer::FIXED_MATERIAL_FLAG_USE_ALPHA, true ); - + VisualServer::get_singleton()->mesh_add_surface_from_arrays(duplicate_mesh,VS::PRIMITIVE_TRIANGLES,d); + VisualServer::get_singleton()->mesh_surface_set_material(duplicate_mesh,0,inner_mat->get_rid()); d[VS::ARRAY_VERTEX]=lines; - VisualServer::get_singleton()->mesh_add_surface(duplicate_mesh,VS::PRIMITIVE_LINES,d); - VisualServer::get_singleton()->mesh_surface_set_material(duplicate_mesh,1,outer_mat_dup); + VisualServer::get_singleton()->mesh_add_surface_from_arrays(duplicate_mesh,VS::PRIMITIVE_LINES,d); + VisualServer::get_singleton()->mesh_surface_set_material(duplicate_mesh,1,outer_mat->get_rid()); } @@ -1451,14 +1436,10 @@ GridMapEditor::~GridMapEditor() { VisualServer::get_singleton()->free(grid[i]); if (grid_instance[i].is_valid()) VisualServer::get_singleton()->free(grid_instance[i]); - if (cursor_instance) + if (cursor_instance.is_valid()) VisualServer::get_singleton()->free(cursor_instance); } - VisualServer::get_singleton()->free(inner_mat); - VisualServer::get_singleton()->free(outer_mat); - VisualServer::get_singleton()->free(inner_mat_dup); - VisualServer::get_singleton()->free(outer_mat_dup); VisualServer::get_singleton()->free(selection_mesh); if (selection_instance.is_valid()) @@ -1480,7 +1461,7 @@ void GridMapEditorPlugin::edit(Object *p_object) { bool GridMapEditorPlugin::handles(Object *p_object) const { - return p_object->is_type("GridMap"); + return p_object->is_class("GridMap"); } void GridMapEditorPlugin::make_visible(bool p_visible) { diff --git a/modules/gridmap/grid_map_editor_plugin.h b/modules/gridmap/grid_map_editor_plugin.h index 535c51bcbf..66ec5dc4bc 100644 --- a/modules/gridmap/grid_map_editor_plugin.h +++ b/modules/gridmap/grid_map_editor_plugin.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -40,7 +40,7 @@ class SpatialEditorPlugin; class GridMapEditor : public VBoxContainer { - OBJ_TYPE(GridMapEditor, VBoxContainer ); + GDCLASS(GridMapEditor, VBoxContainer ); enum { @@ -112,12 +112,9 @@ class GridMapEditor : public VBoxContainer { RID duplicate_mesh; RID duplicate_instance; - RID indicator_mat; - - RID inner_mat; - RID outer_mat; - RID inner_mat_dup; - RID outer_mat_dup; + Ref<FixedSpatialMaterial> indicator_mat; + Ref<FixedSpatialMaterial> inner_mat; + Ref<FixedSpatialMaterial> outer_mat; bool updating; @@ -238,7 +235,7 @@ public: class GridMapEditorPlugin : public EditorPlugin { - OBJ_TYPE( GridMapEditorPlugin, EditorPlugin ); + GDCLASS( GridMapEditorPlugin, EditorPlugin ); GridMapEditor *gridmap_editor; EditorNode *editor; diff --git a/modules/gridmap/register_types.cpp b/modules/gridmap/register_types.cpp index 9dcc04b22a..9cd70a0f9b 100644 --- a/modules/gridmap/register_types.cpp +++ b/modules/gridmap/register_types.cpp @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,7 +28,7 @@ /*************************************************************************/ #include "register_types.h" #ifndef _3D_DISABLED -#include "object_type_db.h" +#include "class_db.h" #include "grid_map.h" #include "grid_map_editor_plugin.h" #endif @@ -36,7 +36,7 @@ void register_gridmap_types() { #ifndef _3D_DISABLED - ObjectTypeDB::register_type<GridMap>(); + ClassDB::register_class<GridMap>(); #ifdef TOOLS_ENABLED EditorPlugins::add_by_type<GridMapEditorPlugin>(); #endif diff --git a/modules/gridmap/register_types.h b/modules/gridmap/register_types.h index 7b5c10f9e5..cc7c13961a 100644 --- a/modules/gridmap/register_types.h +++ b/modules/gridmap/register_types.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/modules/ik/SCsub b/modules/ik/SCsub deleted file mode 100644 index 211a043468..0000000000 --- a/modules/ik/SCsub +++ /dev/null @@ -1,3 +0,0 @@ -Import('env') - -env.add_source_files(env.modules_sources,"*.cpp") diff --git a/modules/ik/ik.cpp b/modules/ik/ik.cpp deleted file mode 100644 index 35b3ba7e83..0000000000 --- a/modules/ik/ik.cpp +++ /dev/null @@ -1,326 +0,0 @@ -/*************************************************************************/ -/* ik.cpp */ -/* Copyright (c) 2016 Sergey Lapin <slapinid@gmail.com> */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* http://www.godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "ik.h" - -bool InverseKinematics::_get(const StringName& p_name,Variant &r_ret) const -{ - - if (String(p_name)=="ik_bone") { - - r_ret=get_bone_name(); - return true; - } - - return false; -} - -bool InverseKinematics::_set(const StringName& p_name, const Variant& p_value) -{ - - if (String(p_name)=="ik_bone") { - - set_bone_name(p_value); - changed = true; - return true; - } - - return false; -} - -void InverseKinematics::_get_property_list( List<PropertyInfo>* p_list ) const -{ - - Skeleton *parent=NULL; - if(get_parent()) - parent=get_parent()->cast_to<Skeleton>(); - - if (parent) { - - String names; - for(int i=0;i<parent->get_bone_count();i++) { - if(i>0) - names+=","; - names+=parent->get_bone_name(i); - } - - p_list->push_back(PropertyInfo(Variant::STRING,"ik_bone",PROPERTY_HINT_ENUM,names)); - } else { - - p_list->push_back(PropertyInfo(Variant::STRING,"ik_bone")); - - } - -} - -void InverseKinematics::_check_bind() -{ - - if (get_parent() && get_parent()->cast_to<Skeleton>()) { - Skeleton *sk = get_parent()->cast_to<Skeleton>(); - int idx = sk->find_bone(ik_bone); - if (idx!=-1) { - ik_bone_no = idx; - bound=true; - } - skel = sk; - } -} - -void InverseKinematics::_check_unbind() -{ - - if (bound) { - - if (get_parent() && get_parent()->cast_to<Skeleton>()) { - Skeleton *sk = get_parent()->cast_to<Skeleton>(); - int idx = sk->find_bone(ik_bone); - if (idx!=-1) - ik_bone_no = idx; - else - ik_bone_no = 0; - skel = sk; - - } - bound=false; - } -} - - -void InverseKinematics::set_bone_name(const String& p_name) -{ - - if (is_inside_tree()) - _check_unbind(); - - ik_bone=p_name; - - if (is_inside_tree()) - _check_bind(); - changed = true; -} - -String InverseKinematics::get_bone_name() const -{ - - return ik_bone; -} - -void InverseKinematics::set_iterations(int itn) -{ - - if (is_inside_tree()) - _check_unbind(); - - iterations=itn; - - if (is_inside_tree()) - _check_bind(); - changed = true; -} - -int InverseKinematics::get_iterations() const -{ - - return iterations; -} - -void InverseKinematics::set_chain_size(int cs) -{ - if (is_inside_tree()) - _check_unbind(); - - chain_size=cs; - chain.clear(); - if (bound) - update_parameters(); - - if (is_inside_tree()) - _check_bind(); - changed = true; -} - -int InverseKinematics::get_chain_size() const -{ - - return chain_size; -} - -void InverseKinematics::set_precision(float p) -{ - - if (is_inside_tree()) - _check_unbind(); - - precision=p; - - if (is_inside_tree()) - _check_bind(); - changed = true; -} - -float InverseKinematics::get_precision() const -{ - - return precision; -} - -void InverseKinematics::set_speed(float p) -{ - - if (is_inside_tree()) - _check_unbind(); - - speed=p; - - if (is_inside_tree()) - _check_bind(); - changed = true; -} - -float InverseKinematics::get_speed() const -{ - - return speed; -} - -void InverseKinematics::update_parameters() -{ - tail_bone = -1; - for (int i = 0; i < skel->get_bone_count(); i++) - if (skel->get_bone_parent(i) == ik_bone_no) - tail_bone = i; - int cur_bone = ik_bone_no; - int its = chain_size; - while (its > 0 && cur_bone >= 0) { - chain.push_back(cur_bone); - cur_bone = skel->get_bone_parent(cur_bone); - its--; - } -} - -void InverseKinematics::_notification(int p_what) -{ - - switch(p_what) { - - case NOTIFICATION_ENTER_TREE: { - - _check_bind(); - if (bound) { - update_parameters(); - changed = false; - set_process(true); - } - } break; - case NOTIFICATION_PROCESS: { - - Spatial *sksp = skel->cast_to<Spatial>(); - if (!bound) - break; - if (!sksp) - break; - if (changed) { - update_parameters(); - changed = false; - } - Vector3 to = get_translation(); - for (int hump = 0; hump < iterations; hump++) { - int depth = 0; - float olderr = 1000.0; - float psign = 1.0; - bool reached = false; - - for (List<int>::Element *b = chain.front(); b; b = b->next()) { - int cur_bone = b->get(); - Vector3 d = skel->get_bone_global_pose(tail_bone).origin; - Vector3 rg = to; - float err = d.distance_squared_to(rg); - if (err < precision) { - if (!reached && err < precision) - reached = true; - break; - } else - if (reached) - reached = false; - if (err > olderr) - psign = -psign; - Transform mod = skel->get_bone_global_pose(cur_bone); - Quat q1 = Quat(mod.basis).normalized(); - Transform mod2 = mod.looking_at(to, Vector3(0.0, 1.0, 0.0)); - Quat q2 = Quat(mod2.basis).normalized(); - if (psign < 0.0) - q2 = q2.inverse(); - Quat q = q1.slerp(q2, speed / (1.0 + 500.0 * depth)).normalized(); - Transform fin = Transform(q); - fin.origin = mod.origin; - skel->set_bone_global_pose(cur_bone, fin); - depth++; - } - if (reached) - break; - - } - - } break; - case NOTIFICATION_EXIT_TREE: { - set_process(false); - - _check_unbind(); - } break; - } -} -void InverseKinematics::_bind_methods() { - ObjectTypeDB::bind_method(_MD("set_bone_name","ik_bone"),&InverseKinematics::set_bone_name); - ObjectTypeDB::bind_method(_MD("get_bone_name"),&InverseKinematics::get_bone_name); - ObjectTypeDB::bind_method(_MD("set_iterations","iterations"),&InverseKinematics::set_iterations); - ObjectTypeDB::bind_method(_MD("get_iterations"),&InverseKinematics::get_iterations); - ObjectTypeDB::bind_method(_MD("set_chain_size","chain_size"),&InverseKinematics::set_chain_size); - ObjectTypeDB::bind_method(_MD("get_chain_size"),&InverseKinematics::get_chain_size); - ObjectTypeDB::bind_method(_MD("set_precision","precision"),&InverseKinematics::set_precision); - ObjectTypeDB::bind_method(_MD("get_precision"),&InverseKinematics::get_precision); - ObjectTypeDB::bind_method(_MD("set_speed","speed"),&InverseKinematics::set_speed); - ObjectTypeDB::bind_method(_MD("get_speed"),&InverseKinematics::get_speed); - ADD_PROPERTY(PropertyInfo(Variant::INT, "iterations"), _SCS("set_iterations"), _SCS("get_iterations")); - ADD_PROPERTY(PropertyInfo(Variant::INT, "chain_size"), _SCS("set_chain_size"), _SCS("get_chain_size")); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "precision"), _SCS("set_precision"), _SCS("get_precision")); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "speed"), _SCS("set_speed"), _SCS("get_speed")); -} - -InverseKinematics::InverseKinematics() -{ - bound=false; - chain_size = 2; - iterations = 100; - precision = 0.001; - speed = 0.2; - -} - diff --git a/modules/jpg/SCsub b/modules/jpg/SCsub new file mode 100644 index 0000000000..e72dc6a1ca --- /dev/null +++ b/modules/jpg/SCsub @@ -0,0 +1,20 @@ +#!/usr/bin/env python + +Import('env') +Import('env_modules') + +env_jpg = env_modules.Clone() + +# Thirdparty source files +# Not unbundled for now as they are not commonly available as shared library +thirdparty_dir = "#thirdparty/jpeg-compressor/" +thirdparty_sources = [ + "jpgd.cpp", +] +thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] + +env_jpg.add_source_files(env.modules_sources, thirdparty_sources) +env_jpg.Append(CPPPATH=[thirdparty_dir]) + +# Godot's own source files +env_jpg.add_source_files(env.modules_sources, "*.cpp") diff --git a/modules/jpg/config.py b/modules/jpg/config.py new file mode 100644 index 0000000000..fb920482f5 --- /dev/null +++ b/modules/jpg/config.py @@ -0,0 +1,7 @@ + +def can_build(platform): + return True + + +def configure(env): + pass diff --git a/modules/jpg/image_loader_jpegd.cpp b/modules/jpg/image_loader_jpegd.cpp new file mode 100644 index 0000000000..1152d42e1b --- /dev/null +++ b/modules/jpg/image_loader_jpegd.cpp @@ -0,0 +1,144 @@ +/*************************************************************************/ +/* image_loader_jpegd.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#include "image_loader_jpegd.h" + +#include "print_string.h" +#include "os/os.h" + +#include <jpgd.h> +#include <string.h> + + +Error jpeg_load_image_from_buffer(Image *p_image,const uint8_t* p_buffer, int p_buffer_len) { + + jpgd::jpeg_decoder_mem_stream mem_stream(p_buffer,p_buffer_len); + + jpgd::jpeg_decoder decoder(&mem_stream); + + if (decoder.get_error_code() != jpgd::JPGD_SUCCESS) { + return ERR_CANT_OPEN; + } + + const int image_width = decoder.get_width(); + const int image_height = decoder.get_height(); + int comps = decoder.get_num_components(); + if (comps==3) + comps=4; //weird + + if (decoder.begin_decoding() != jpgd::JPGD_SUCCESS) + return ERR_FILE_CORRUPT; + + const int dst_bpl = image_width * comps; + + PoolVector<uint8_t> data; + + data.resize(dst_bpl * image_height); + + PoolVector<uint8_t>::Write dw = data.write(); + + jpgd::uint8 *pImage_data = (jpgd::uint8*)dw.ptr(); + + for (int y = 0; y < image_height; y++) + { + const jpgd::uint8* pScan_line; + jpgd::uint scan_line_len; + if (decoder.decode((const void**)&pScan_line, &scan_line_len) != jpgd::JPGD_SUCCESS) + { + return ERR_FILE_CORRUPT; + } + + jpgd::uint8 *pDst = pImage_data + y * dst_bpl; + memcpy(pDst, pScan_line, dst_bpl); + + + } + + + //all good + + Image::Format fmt; + if (comps==1) + fmt=Image::FORMAT_L8; + else + fmt=Image::FORMAT_RGBA8; + + dw = PoolVector<uint8_t>::Write(); + p_image->create(image_width,image_height,0,fmt,data); + + return OK; + +} + + +Error ImageLoaderJPG::load_image(Image *p_image,FileAccess *f) { + + + PoolVector<uint8_t> src_image; + int src_image_len = f->get_len(); + ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT); + src_image.resize(src_image_len); + + PoolVector<uint8_t>::Write w = src_image.write(); + + f->get_buffer(&w[0],src_image_len); + + f->close(); + + + Error err = jpeg_load_image_from_buffer(p_image,w.ptr(),src_image_len); + + w = PoolVector<uint8_t>::Write(); + + return err; + +} + +void ImageLoaderJPG::get_recognized_extensions(List<String> *p_extensions) const { + + p_extensions->push_back("jpg"); + p_extensions->push_back("jpeg"); +} + + +static Image _jpegd_mem_loader_func(const uint8_t* p_png,int p_size) { + + Image img; + Error err = jpeg_load_image_from_buffer(&img,p_png,p_size); + if (err) + ERR_PRINT("Couldn't initialize ImageLoaderJPG with the given resource."); + + return img; +} + +ImageLoaderJPG::ImageLoaderJPG() { + + Image::_jpg_mem_loader_func=_jpegd_mem_loader_func; +} + + diff --git a/modules/ik/ik.h b/modules/jpg/image_loader_jpegd.h index b57d69b026..aeb219aa5d 100644 --- a/modules/ik/ik.h +++ b/modules/jpg/image_loader_jpegd.h @@ -1,12 +1,11 @@ /*************************************************************************/ -/* ik.h */ -/* Copyright (c) 2016 Sergey Lapin <slapinid@gmail.com> */ +/* image_loader_jpegd.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -27,48 +26,24 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef IK_H -#define IK_H +#ifndef IMAGE_LOADER_JPG_H +#define IMAGE_LOADER_JPG_H -#include "scene/3d/skeleton.h" -class InverseKinematics : public Spatial { - OBJ_TYPE(InverseKinematics, Spatial); - bool bound; - String ik_bone; - int ik_bone_no; - int tail_bone; - int chain_size; - Skeleton *skel; - List<int> chain; - void _check_bind(); - void _check_unbind(); - int iterations; - float precision; - float speed; - bool changed; +#include "io/image_loader.h" + +/** + @author Juan Linietsky <reduzio@gmail.com> +*/ +class ImageLoaderJPG : public ImageFormatLoader { -protected: - bool _set(const StringName& p_name, const Variant& p_value); - bool _get(const StringName& p_name,Variant &r_ret) const; - void _get_property_list( List<PropertyInfo> *p_list) const; - void _notification(int p_what); - static void _bind_methods(); - void update_parameters(); public: - Skeleton *get_skeleton(); - void set_bone_name(const String& p_name); - String get_bone_name() const; - void set_iterations(int itn); - int get_iterations() const; - void set_chain_size(int cs); - int get_chain_size() const; - void set_precision(float p); - float get_precision() const; - void set_speed(float p); - float get_speed() const; - InverseKinematics(); + + virtual Error load_image(Image *p_image,FileAccess *f); + virtual void get_recognized_extensions(List<String> *p_extensions) const; + ImageLoaderJPG(); }; -#endif + +#endif diff --git a/modules/jpg/register_types.cpp b/modules/jpg/register_types.cpp new file mode 100644 index 0000000000..bcd467f5fc --- /dev/null +++ b/modules/jpg/register_types.cpp @@ -0,0 +1,44 @@ +/*************************************************************************/ +/* register_types.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#include "register_types.h" + +#include "image_loader_jpegd.h" + +static ImageLoaderJPG *image_loader_jpg = NULL; + +void register_jpg_types() { + + image_loader_jpg = memnew( ImageLoaderJPG ); + ImageLoader::add_image_format_loader(image_loader_jpg); +} + +void unregister_jpg_types() { + + memdelete( image_loader_jpg ); +} diff --git a/modules/jpg/register_types.h b/modules/jpg/register_types.h new file mode 100644 index 0000000000..62132bf461 --- /dev/null +++ b/modules/jpg/register_types.h @@ -0,0 +1,30 @@ +/*************************************************************************/ +/* register_types.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +void register_jpg_types(); +void unregister_jpg_types(); diff --git a/modules/ogg/SCsub b/modules/ogg/SCsub new file mode 100644 index 0000000000..5eabaf6f2b --- /dev/null +++ b/modules/ogg/SCsub @@ -0,0 +1,21 @@ +#!/usr/bin/env python + +Import('env') +Import('env_modules') + +env_ogg = env_modules.Clone() + +# Thirdparty source files +if (env['builtin_libogg'] != 'no'): + thirdparty_dir = "#thirdparty/libogg/" + thirdparty_sources = [ + "bitwise.c", + "framing.c", + ] + thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] + + env_ogg.add_source_files(env.modules_sources, thirdparty_sources) + env_ogg.Append(CPPPATH=[thirdparty_dir]) + +# Godot source files +env_ogg.add_source_files(env.modules_sources, "*.cpp") diff --git a/modules/ogg/config.py b/modules/ogg/config.py new file mode 100644 index 0000000000..ef5daca05c --- /dev/null +++ b/modules/ogg/config.py @@ -0,0 +1,8 @@ + +def can_build(platform): +# return True + return False + + +def configure(env): + pass diff --git a/modules/ogg/register_types.cpp b/modules/ogg/register_types.cpp new file mode 100644 index 0000000000..ed796ec092 --- /dev/null +++ b/modules/ogg/register_types.cpp @@ -0,0 +1,35 @@ +/*************************************************************************/ +/* register_types.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#include "register_types.h" + +// Dummy module as libogg is needed by other modules (vorbis, theora, opus, ...) + +void register_ogg_types() {} + +void unregister_ogg_types() {} diff --git a/modules/ogg/register_types.h b/modules/ogg/register_types.h new file mode 100644 index 0000000000..cc67b4d2f0 --- /dev/null +++ b/modules/ogg/register_types.h @@ -0,0 +1,30 @@ +/*************************************************************************/ +/* register_types.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +void register_ogg_types(); +void unregister_ogg_types(); diff --git a/modules/openssl/SCsub b/modules/openssl/SCsub new file mode 100644 index 0000000000..0e811ce8c9 --- /dev/null +++ b/modules/openssl/SCsub @@ -0,0 +1,687 @@ +#!/usr/bin/env python + +Import('env') +Import('env_modules') + +env_openssl = env_modules.Clone() + +# Thirdparty source files +if (env['builtin_openssl'] != 'no'): + thirdparty_dir = "#thirdparty/openssl/" + + thirdparty_sources = [ + "ssl/t1_lib.c", + "ssl/t1_ext.c", + "ssl/s3_srvr.c", + "ssl/t1_enc.c", + "ssl/t1_meth.c", + "ssl/s23_clnt.c", + "ssl/ssl_asn1.c", + "ssl/tls_srp.c", + "ssl/kssl.c", + "ssl/d1_both.c", + "ssl/t1_clnt.c", + "ssl/bio_ssl.c", + "ssl/d1_srtp.c", + "ssl/t1_reneg.c", + "ssl/ssl_cert.c", + "ssl/s3_lib.c", + "ssl/d1_srvr.c", + "ssl/s23_meth.c", + "ssl/ssl_stat.c", + "ssl/ssl_err.c", + "ssl/ssl_algs.c", + "ssl/s3_cbc.c", + "ssl/d1_clnt.c", + "ssl/s3_pkt.c", + "ssl/d1_meth.c", + "ssl/s3_both.c", + "ssl/s2_enc.c", + "ssl/s3_meth.c", + "ssl/s3_enc.c", + "ssl/s23_pkt.c", + "ssl/s2_pkt.c", + "ssl/d1_pkt.c", + "ssl/ssl_rsa.c", + "ssl/s23_srvr.c", + "ssl/s2_meth.c", + "ssl/s3_clnt.c", + "ssl/s23_lib.c", + "ssl/t1_srvr.c", + "ssl/ssl_lib.c", + "ssl/ssl_txt.c", + "ssl/s2_srvr.c", + "ssl/ssl_sess.c", + "ssl/s2_clnt.c", + "ssl/d1_lib.c", + "ssl/s2_lib.c", + "ssl/ssl_err2.c", + "ssl/ssl_ciph.c", + "crypto/dsa/dsa_lib.c", + "crypto/dsa/dsa_pmeth.c", + "crypto/dsa/dsa_ossl.c", + "crypto/dsa/dsa_gen.c", + "crypto/dsa/dsa_asn1.c", + "crypto/dsa/dsa_prn.c", + "crypto/dsa/dsa_sign.c", + "crypto/dsa/dsa_key.c", + "crypto/dsa/dsa_vrf.c", + "crypto/dsa/dsa_err.c", + "crypto/dsa/dsa_ameth.c", + "crypto/dsa/dsa_depr.c", + "crypto/x509/x509_lu.c", + "crypto/x509/x509cset.c", + "crypto/x509/x509_set.c", + "crypto/x509/x509_d2.c", + "crypto/x509/x509_txt.c", + "crypto/x509/x509rset.c", + "crypto/x509/by_dir.c", + "crypto/x509/x509_vpm.c", + "crypto/x509/x509_vfy.c", + "crypto/x509/x509_trs.c", + "crypto/x509/by_file.c", + "crypto/x509/x509_obj.c", + "crypto/x509/x509spki.c", + "crypto/x509/x509_v3.c", + "crypto/x509/x509_req.c", + "crypto/x509/x509_att.c", + "crypto/x509/x_all.c", + "crypto/x509/x509_ext.c", + "crypto/x509/x509type.c", + "crypto/x509/x509_def.c", + "crypto/x509/x509_err.c", + "crypto/x509/x509name.c", + "crypto/x509/x509_r2x.c", + "crypto/x509/x509_cmp.c", + "crypto/asn1/x_pkey.c", + "crypto/asn1/a_gentm.c", + "crypto/asn1/x_sig.c", + "crypto/asn1/t_req.c", + "crypto/asn1/t_pkey.c", + "crypto/asn1/p8_pkey.c", + "crypto/asn1/a_i2d_fp.c", + "crypto/asn1/x_val.c", + "crypto/asn1/f_string.c", + "crypto/asn1/p5_pbe.c", + "crypto/asn1/bio_ndef.c", + "crypto/asn1/a_bool.c", + "crypto/asn1/asn1_gen.c", + "crypto/asn1/x_algor.c", + "crypto/asn1/bio_asn1.c", + "crypto/asn1/asn_mime.c", + "crypto/asn1/t_x509.c", + "crypto/asn1/a_strex.c", + "crypto/asn1/x_nx509.c", + "crypto/asn1/asn1_err.c", + "crypto/asn1/x_crl.c", + "crypto/asn1/a_print.c", + "crypto/asn1/a_type.c", + "crypto/asn1/tasn_new.c", + "crypto/asn1/n_pkey.c", + "crypto/asn1/x_bignum.c", + "crypto/asn1/asn_pack.c", + "crypto/asn1/evp_asn1.c", + "crypto/asn1/t_bitst.c", + "crypto/asn1/x_req.c", + "crypto/asn1/a_time.c", + "crypto/asn1/x_name.c", + "crypto/asn1/x_pubkey.c", + "crypto/asn1/tasn_typ.c", + "crypto/asn1/asn_moid.c", + "crypto/asn1/a_utctm.c", + "crypto/asn1/asn1_lib.c", + "crypto/asn1/x_x509a.c", + "crypto/asn1/a_set.c", + "crypto/asn1/t_crl.c", + "crypto/asn1/p5_pbev2.c", + "crypto/asn1/tasn_enc.c", + "crypto/asn1/a_mbstr.c", + "crypto/asn1/tasn_dec.c", + "crypto/asn1/x_x509.c", + "crypto/asn1/a_octet.c", + "crypto/asn1/x_long.c", + "crypto/asn1/a_bytes.c", + "crypto/asn1/t_x509a.c", + "crypto/asn1/a_enum.c", + "crypto/asn1/a_int.c", + "crypto/asn1/tasn_prn.c", + "crypto/asn1/i2d_pr.c", + "crypto/asn1/a_utf8.c", + "crypto/asn1/t_spki.c", + "crypto/asn1/a_digest.c", + "crypto/asn1/a_dup.c", + "crypto/asn1/i2d_pu.c", + "crypto/asn1/a_verify.c", + "crypto/asn1/f_enum.c", + "crypto/asn1/a_sign.c", + "crypto/asn1/d2i_pr.c", + "crypto/asn1/asn1_par.c", + "crypto/asn1/x_spki.c", + "crypto/asn1/a_d2i_fp.c", + "crypto/asn1/f_int.c", + "crypto/asn1/x_exten.c", + "crypto/asn1/tasn_utl.c", + "crypto/asn1/nsseq.c", + "crypto/asn1/a_bitstr.c", + "crypto/asn1/x_info.c", + "crypto/asn1/a_strnid.c", + "crypto/asn1/a_object.c", + "crypto/asn1/tasn_fre.c", + "crypto/asn1/d2i_pu.c", + "crypto/asn1/ameth_lib.c", + "crypto/asn1/x_attrib.c", + "crypto/evp/m_sha.c", + "crypto/evp/e_camellia.c", + "crypto/evp/e_aes.c", + "crypto/evp/bio_b64.c", + "crypto/evp/m_sigver.c", + "crypto/evp/m_wp.c", + "crypto/evp/m_sha1.c", + "crypto/evp/p_seal.c", + "crypto/evp/c_alld.c", + "crypto/evp/p5_crpt.c", + "crypto/evp/e_rc4.c", + "crypto/evp/m_ecdsa.c", + "crypto/evp/bio_enc.c", + "crypto/evp/e_des3.c", + "crypto/evp/m_null.c", + "crypto/evp/bio_ok.c", + "crypto/evp/pmeth_gn.c", + "crypto/evp/e_rc5.c", + "crypto/evp/e_rc2.c", + "crypto/evp/p_dec.c", + "crypto/evp/p_verify.c", + "crypto/evp/e_rc4_hmac_md5.c", + "crypto/evp/pmeth_lib.c", + "crypto/evp/m_ripemd.c", + "crypto/evp/m_md5.c", + "crypto/evp/e_bf.c", + "crypto/evp/p_enc.c", + "crypto/evp/m_dss.c", + "crypto/evp/bio_md.c", + "crypto/evp/evp_pbe.c", + "crypto/evp/e_seed.c", + "crypto/evp/e_cast.c", + "crypto/evp/p_open.c", + "crypto/evp/p5_crpt2.c", + "crypto/evp/m_dss1.c", + "crypto/evp/names.c", + "crypto/evp/evp_acnf.c", + "crypto/evp/e_des.c", + "crypto/evp/evp_cnf.c", + "crypto/evp/evp_lib.c", + "crypto/evp/digest.c", + "crypto/evp/evp_err.c", + "crypto/evp/evp_enc.c", + "crypto/evp/e_old.c", + "crypto/evp/c_all.c", + "crypto/evp/m_md2.c", + "crypto/evp/e_xcbc_d.c", + "crypto/evp/pmeth_fn.c", + "crypto/evp/p_lib.c", + "crypto/evp/evp_key.c", + "crypto/evp/encode.c", + "crypto/evp/e_aes_cbc_hmac_sha1.c", + "crypto/evp/e_aes_cbc_hmac_sha256.c", + "crypto/evp/m_mdc2.c", + "crypto/evp/e_null.c", + "crypto/evp/p_sign.c", + "crypto/evp/e_idea.c", + "crypto/evp/c_allc.c", + "crypto/evp/evp_pkey.c", + "crypto/evp/m_md4.c", + "crypto/ex_data.c", + "crypto/pkcs12/p12_p8e.c", + "crypto/pkcs12/p12_crt.c", + "crypto/pkcs12/p12_utl.c", + "crypto/pkcs12/p12_attr.c", + "crypto/pkcs12/p12_npas.c", + "crypto/pkcs12/p12_decr.c", + "crypto/pkcs12/p12_init.c", + "crypto/pkcs12/p12_kiss.c", + "crypto/pkcs12/p12_add.c", + "crypto/pkcs12/p12_p8d.c", + "crypto/pkcs12/p12_mutl.c", + "crypto/pkcs12/p12_crpt.c", + "crypto/pkcs12/pk12err.c", + "crypto/pkcs12/p12_asn.c", + "crypto/pkcs12/p12_key.c", + "crypto/ecdh/ech_key.c", + "crypto/ecdh/ech_ossl.c", + "crypto/ecdh/ech_lib.c", + "crypto/ecdh/ech_err.c", + "crypto/ecdh/ech_kdf.c", + "crypto/o_str.c", + "crypto/conf/conf_api.c", + "crypto/conf/conf_err.c", + "crypto/conf/conf_def.c", + "crypto/conf/conf_lib.c", + "crypto/conf/conf_mall.c", + "crypto/conf/conf_sap.c", + "crypto/conf/conf_mod.c", + "crypto/ebcdic.c", + "crypto/ecdsa/ecs_lib.c", + "crypto/ecdsa/ecs_asn1.c", + "crypto/ecdsa/ecs_ossl.c", + "crypto/ecdsa/ecs_vrf.c", + "crypto/ecdsa/ecs_sign.c", + "crypto/ecdsa/ecs_err.c", + "crypto/dso/dso_win32.c", + "crypto/dso/dso_lib.c", + "crypto/dso/dso_dlfcn.c", + "crypto/dso/dso_dl.c", + "crypto/dso/dso_beos.c", + "crypto/dso/dso_null.c", + "crypto/dso/dso_vms.c", + "crypto/dso/dso_err.c", + "crypto/dso/dso_openssl.c", + "crypto/cryptlib.c", + "crypto/md5/md5_one.c", + "crypto/md5/md5_dgst.c", + "crypto/pkcs7/pkcs7err.c", + "crypto/pkcs7/pk7_smime.c", + "crypto/pkcs7/bio_pk7.c", + "crypto/pkcs7/pk7_mime.c", + "crypto/pkcs7/pk7_lib.c", + "crypto/pkcs7/pk7_asn1.c", + "crypto/pkcs7/pk7_doit.c", + "crypto/pkcs7/pk7_attr.c", + "crypto/md4/md4_one.c", + "crypto/md4/md4_dgst.c", + "crypto/o_dir.c", + "crypto/buffer/buf_err.c", + "crypto/buffer/buf_str.c", + "crypto/buffer/buffer.c", + "crypto/cms/cms_lib.c", + "crypto/cms/cms_io.c", + "crypto/cms/cms_err.c", + "crypto/cms/cms_dd.c", + "crypto/cms/cms_smime.c", + "crypto/cms/cms_att.c", + "crypto/cms/cms_pwri.c", + "crypto/cms/cms_cd.c", + "crypto/cms/cms_sd.c", + "crypto/cms/cms_asn1.c", + "crypto/cms/cms_env.c", + "crypto/cms/cms_enc.c", + "crypto/cms/cms_ess.c", + "crypto/cms/cms_kari.c", + "crypto/mem_dbg.c", + "crypto/uid.c", + "crypto/stack/stack.c", + "crypto/ec/ec_ameth.c", + "crypto/ec/ec_err.c", + "crypto/ec/ec_lib.c", + "crypto/ec/ec_curve.c", + "crypto/ec/ec_oct.c", + "crypto/ec/ec_asn1.c", + "crypto/ec/ecp_oct.c", + "crypto/ec/ec_print.c", + "crypto/ec/ec2_smpl.c", + "crypto/ec/ecp_nistp224.c", + "crypto/ec/ec2_oct.c", + "crypto/ec/eck_prn.c", + "crypto/ec/ec_key.c", + "crypto/ec/ecp_nist.c", + "crypto/ec/ec_check.c", + "crypto/ec/ecp_smpl.c", + "crypto/ec/ec2_mult.c", + "crypto/ec/ecp_mont.c", + "crypto/ec/ecp_nistp521.c", + "crypto/ec/ec_mult.c", + "crypto/ec/ecp_nistputil.c", + "crypto/ec/ec_pmeth.c", + "crypto/ec/ec_cvt.c", + "crypto/ec/ecp_nistp256.c", + "crypto/krb5/krb5_asn.c", + "crypto/hmac/hmac.c", + "crypto/hmac/hm_ameth.c", + "crypto/hmac/hm_pmeth.c", + "crypto/comp/c_rle.c", + "crypto/comp/c_zlib.c", + "crypto/comp/comp_lib.c", + "crypto/comp/comp_err.c", + "crypto/des/fcrypt.c", + "crypto/des/str2key.c", + "crypto/des/cbc_cksm.c", + "crypto/des/des_enc.c", + "crypto/des/ofb_enc.c", + "crypto/des/read2pwd.c", + "crypto/des/ecb3_enc.c", + "crypto/des/rand_key.c", + "crypto/des/cfb64ede.c", + "crypto/des/rpc_enc.c", + "crypto/des/ofb64ede.c", + "crypto/des/qud_cksm.c", + "crypto/des/enc_writ.c", + "crypto/des/set_key.c", + "crypto/des/xcbc_enc.c", + "crypto/des/fcrypt_b.c", + "crypto/des/ede_cbcm_enc.c", + "crypto/des/des_old2.c", + "crypto/des/cfb_enc.c", + "crypto/des/ecb_enc.c", + "crypto/des/enc_read.c", + "crypto/des/des_old.c", + "crypto/des/ofb64enc.c", + "crypto/des/pcbc_enc.c", + "crypto/des/cbc_enc.c", + "crypto/des/cfb64enc.c", + "crypto/lhash/lh_stats.c", + "crypto/lhash/lhash.c", + "crypto/x509v3/v3_genn.c", + "crypto/x509v3/pcy_cache.c", + "crypto/x509v3/v3_sxnet.c", + "crypto/x509v3/v3_scts.c", + "crypto/x509v3/v3err.c", + "crypto/x509v3/v3_conf.c", + "crypto/x509v3/v3_utl.c", + "crypto/x509v3/v3_akeya.c", + "crypto/x509v3/v3_lib.c", + "crypto/x509v3/pcy_lib.c", + "crypto/x509v3/v3_cpols.c", + "crypto/x509v3/v3_ia5.c", + "crypto/x509v3/v3_bitst.c", + "crypto/x509v3/v3_skey.c", + "crypto/x509v3/v3_info.c", + "crypto/x509v3/v3_asid.c", + "crypto/x509v3/pcy_tree.c", + "crypto/x509v3/v3_pcons.c", + "crypto/x509v3/v3_bcons.c", + "crypto/x509v3/v3_pku.c", + "crypto/x509v3/v3_ocsp.c", + "crypto/x509v3/pcy_map.c", + "crypto/x509v3/v3_ncons.c", + "crypto/x509v3/v3_purp.c", + "crypto/x509v3/v3_enum.c", + "crypto/x509v3/v3_pmaps.c", + "crypto/x509v3/pcy_node.c", + "crypto/x509v3/v3_pcia.c", + "crypto/x509v3/v3_crld.c", + "crypto/x509v3/v3_pci.c", + "crypto/x509v3/v3_akey.c", + "crypto/x509v3/v3_addr.c", + "crypto/x509v3/v3_int.c", + "crypto/x509v3/v3_alt.c", + "crypto/x509v3/v3_extku.c", + "crypto/x509v3/v3_prn.c", + "crypto/x509v3/pcy_data.c", + "crypto/aes/aes_ofb.c", + "crypto/aes/aes_ctr.c", + "crypto/aes/aes_ecb.c", + "crypto/aes/aes_cfb.c", + "crypto/aes/aes_wrap.c", + "crypto/aes/aes_ige.c", + "crypto/aes/aes_misc.c", + "crypto/pqueue/pqueue.c", + "crypto/sha/sha_one.c", + "crypto/sha/sha_dgst.c", + "crypto/sha/sha512.c", + "crypto/sha/sha1_one.c", + "crypto/sha/sha1dgst.c", + "crypto/sha/sha256.c", + "crypto/whrlpool/wp_dgst.c", + "crypto/objects/obj_xref.c", + "crypto/objects/o_names.c", + "crypto/objects/obj_err.c", + "crypto/objects/obj_dat.c", + "crypto/objects/obj_lib.c", + "crypto/mem.c", + "crypto/fips_ers.c", + "crypto/o_fips.c", + "crypto/engine/eng_rdrand.c", + "crypto/engine/eng_err.c", + "crypto/engine/tb_ecdsa.c", + "crypto/engine/tb_rsa.c", + "crypto/engine/tb_cipher.c", + "crypto/engine/tb_dsa.c", + "crypto/engine/eng_lib.c", + "crypto/engine/tb_asnmth.c", + "crypto/engine/tb_ecdh.c", + "crypto/engine/tb_dh.c", + "crypto/engine/tb_store.c", + "crypto/engine/eng_init.c", + "crypto/engine/eng_cnf.c", + "crypto/engine/eng_all.c", + "crypto/engine/tb_digest.c", + "crypto/engine/tb_pkmeth.c", + "crypto/engine/eng_table.c", + "crypto/engine/eng_ctrl.c", + "crypto/engine/eng_list.c", + "crypto/engine/eng_cryptodev.c", + "crypto/engine/eng_pkey.c", + "crypto/engine/tb_rand.c", + "crypto/engine/eng_openssl.c", + "crypto/engine/eng_fat.c", + "crypto/engine/eng_dyn.c", + "crypto/ts/ts_rsp_verify.c", + "crypto/ts/ts_req_print.c", + "crypto/ts/ts_verify_ctx.c", + "crypto/ts/ts_req_utils.c", + "crypto/ts/ts_err.c", + "crypto/ts/ts_rsp_print.c", + "crypto/ts/ts_rsp_utils.c", + "crypto/ts/ts_lib.c", + "crypto/ts/ts_conf.c", + "crypto/ts/ts_asn1.c", + "crypto/ts/ts_rsp_sign.c", + "crypto/ocsp/ocsp_ext.c", + "crypto/ocsp/ocsp_cl.c", + "crypto/ocsp/ocsp_ht.c", + "crypto/ocsp/ocsp_lib.c", + "crypto/ocsp/ocsp_srv.c", + "crypto/ocsp/ocsp_vfy.c", + "crypto/ocsp/ocsp_err.c", + "crypto/ocsp/ocsp_prn.c", + "crypto/ocsp/ocsp_asn.c", + "crypto/bf/bf_cfb64.c", + "crypto/bf/bf_ecb.c", + "crypto/bf/bf_enc.c", + "crypto/bf/bf_skey.c", + "crypto/bf/bf_ofb64.c", + "crypto/idea/i_skey.c", + "crypto/idea/i_ofb64.c", + "crypto/idea/i_cbc.c", + "crypto/idea/i_ecb.c", + "crypto/idea/i_cfb64.c", + "crypto/cmac/cm_ameth.c", + "crypto/cmac/cmac.c", + "crypto/cmac/cm_pmeth.c", + "crypto/dh/dh_lib.c", + "crypto/dh/dh_key.c", + "crypto/dh/dh_asn1.c", + "crypto/dh/dh_depr.c", + "crypto/dh/dh_pmeth.c", + "crypto/dh/dh_prn.c", + "crypto/dh/dh_gen.c", + "crypto/dh/dh_ameth.c", + "crypto/dh/dh_check.c", + "crypto/dh/dh_err.c", + "crypto/dh/dh_kdf.c", + "crypto/dh/dh_rfc5114.c", + "crypto/modes/ccm128.c", + "crypto/modes/ofb128.c", + "crypto/modes/cts128.c", + "crypto/modes/ctr128.c", + "crypto/modes/gcm128.c", + "crypto/modes/cbc128.c", + "crypto/modes/cfb128.c", + "crypto/modes/xts128.c", + "crypto/modes/wrap128.c", + "crypto/camellia/cmll_cfb.c", + "crypto/camellia/cmll_ecb.c", + "crypto/camellia/cmll_utl.c", + "crypto/camellia/cmll_misc.c", + "crypto/camellia/cmll_ofb.c", + "crypto/camellia/cmll_ctr.c", + "crypto/seed/seed_ecb.c", + "crypto/seed/seed_cbc.c", + "crypto/seed/seed.c", + "crypto/seed/seed_ofb.c", + "crypto/seed/seed_cfb.c", + "crypto/txt_db/txt_db.c", + "crypto/cpt_err.c", + "crypto/pem/pem_pk8.c", + "crypto/pem/pem_lib.c", + "crypto/pem/pem_sign.c", + "crypto/pem/pem_all.c", + "crypto/pem/pem_info.c", + "crypto/pem/pem_pkey.c", + "crypto/pem/pem_seal.c", + "crypto/pem/pem_err.c", + "crypto/pem/pem_xaux.c", + "crypto/pem/pvkfmt.c", + "crypto/pem/pem_x509.c", + "crypto/pem/pem_oth.c", + "crypto/rand/rand_lib.c", + "crypto/rand/randfile.c", + "crypto/rand/rand_os2.c", + "crypto/rand/rand_unix.c", + "crypto/rand/rand_nw.c", + "crypto/rand/md_rand.c", + "crypto/rand/rand_err.c", + "crypto/rand/rand_win.c", + "crypto/rand/rand_egd.c", + "crypto/cversion.c", + "crypto/cast/c_ecb.c", + "crypto/cast/c_skey.c", + "crypto/cast/c_ofb64.c", + "crypto/cast/c_enc.c", + "crypto/cast/c_cfb64.c", + "crypto/o_time.c", + "crypto/mdc2/mdc2dgst.c", + "crypto/mdc2/mdc2_one.c", + "crypto/rc4/rc4_utl.c", + "crypto/ui/ui_compat.c", + "crypto/ui/ui_util.c", + "crypto/ui/ui_lib.c", + "crypto/ui/ui_err.c", + "crypto/ui/ui_openssl.c", + "crypto/bio/bf_buff.c", + "crypto/bio/bss_null.c", + "crypto/bio/bss_acpt.c", + "crypto/bio/bss_conn.c", + "crypto/bio/bss_fd.c", + "crypto/bio/bf_null.c", + "crypto/bio/bio_err.c", + "crypto/bio/bss_sock.c", + "crypto/bio/bss_mem.c", + "crypto/bio/b_dump.c", + "crypto/bio/b_print.c", + "crypto/bio/b_sock.c", + "crypto/bio/bss_dgram.c", + "crypto/bio/bf_nbio.c", + "crypto/bio/bio_lib.c", + "crypto/bio/bss_file.c", + "crypto/bio/bss_bio.c", + "crypto/bio/bss_log.c", + "crypto/bio/bio_cb.c", + "crypto/o_init.c", + "crypto/rc2/rc2_skey.c", + "crypto/rc2/rc2_cbc.c", + "crypto/rc2/rc2cfb64.c", + "crypto/rc2/rc2_ecb.c", + "crypto/rc2/rc2ofb64.c", + "crypto/bn/bn_x931p.c", + "crypto/bn/bn_blind.c", + "crypto/bn/bn_gf2m.c", + "crypto/bn/bn_const.c", + "crypto/bn/bn_sqr.c", + "crypto/bn/bn_nist.c", + "crypto/bn/bn_rand.c", + "crypto/bn/bn_err.c", + "crypto/bn/bn_div.c", + "crypto/bn/bn_kron.c", + "crypto/bn/bn_ctx.c", + "crypto/bn/bn_shift.c", + "crypto/bn/bn_mod.c", + "crypto/bn/bn_exp2.c", + "crypto/bn/bn_word.c", + "crypto/bn/bn_add.c", + "crypto/bn/bn_exp.c", + "crypto/bn/bn_mont.c", + "crypto/bn/bn_print.c", + "crypto/bn/bn_mul.c", + "crypto/bn/bn_prime.c", + "crypto/bn/bn_depr.c", + "crypto/bn/bn_gcd.c", + "crypto/bn/bn_mpi.c", + "crypto/bn/bn_sqrt.c", + "crypto/bn/bn_recp.c", + "crypto/bn/bn_lib.c", + "crypto/ripemd/rmd_dgst.c", + "crypto/ripemd/rmd_one.c", + "crypto/rsa/rsa_x931.c", + "crypto/rsa/rsa_depr.c", + "crypto/rsa/rsa_saos.c", + "crypto/rsa/rsa_crpt.c", + "crypto/rsa/rsa_pss.c", + "crypto/rsa/rsa_oaep.c", + "crypto/rsa/rsa_null.c", + "crypto/rsa/rsa_gen.c", + "crypto/rsa/rsa_prn.c", + "crypto/rsa/rsa_pmeth.c", + "crypto/rsa/rsa_asn1.c", + "crypto/rsa/rsa_ssl.c", + "crypto/rsa/rsa_ameth.c", + "crypto/rsa/rsa_pk1.c", + "crypto/rsa/rsa_err.c", + "crypto/rsa/rsa_lib.c", + "crypto/rsa/rsa_none.c", + "crypto/rsa/rsa_chk.c", + "crypto/rsa/rsa_eay.c", + "crypto/rsa/rsa_sign.c", + "crypto/srp/srp_lib.c", + "crypto/srp/srp_vfy.c", + "crypto/err/err.c", + "crypto/err/err_prn.c", + "crypto/err/err_all.c", + "crypto/mem_clr.c", + "crypto/rc4/rc4_skey.c", + "crypto/rc4/rc4_enc.c", + "crypto/camellia/camellia.c", + "crypto/camellia/cmll_cbc.c", + #"crypto/aes/aes_x86core.c", + "crypto/aes/aes_core.c", + "crypto/aes/aes_cbc.c", + "crypto/whrlpool/wp_block.c", + "crypto/bn/bn_asm.c", + ] + + if "platform" in env and env["platform"] == "uwp": + thirdparty_sources += ['uwp.cpp'] + + thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] + + env_openssl.add_source_files(env.modules_sources, thirdparty_sources) + + # FIXME: Clone the environment to make a env_openssl and not pollute the modules env + thirdparty_include_paths = [ + "", + "crypto", + "crypto/asn1", + "crypto/evp", + "crypto/modes", + "openssl", + ] + env_openssl.Append(CPPPATH=[thirdparty_dir + "/" + dir for dir in thirdparty_include_paths]) + + env_openssl.Append(CPPFLAGS=["-DOPENSSL_NO_ASM", "-DOPENSSL_THREADS", "-DL_ENDIAN"]) + + # Workaround for compilation error with GCC/Clang when -Werror is too greedy (GH-4517) + import os + import methods + if not (os.name == "nt" and os.getenv("VCINSTALLDIR")): # not Windows and not MSVC + env_openssl.Append(CFLAGS=["-Wno-error=implicit-function-declaration"]) + + +# Module sources +env_openssl.add_source_files(env.modules_sources, "*.cpp") +env_openssl.add_source_files(env.modules_sources, "*.c") + +# platform/uwp need to know openssl is available, pass to main env +if "platform" in env and env["platform"] == "uwp": + env.Append(CPPPATH=[thirdparty_dir]) + env.Append(CPPFLAGS=['-DOPENSSL_ENABLED']) + +Export('env') diff --git a/modules/openssl/config.py b/modules/openssl/config.py new file mode 100644 index 0000000000..fb920482f5 --- /dev/null +++ b/modules/openssl/config.py @@ -0,0 +1,7 @@ + +def can_build(platform): + return True + + +def configure(env): + pass diff --git a/modules/openssl/curl_hostcheck.c b/modules/openssl/curl_hostcheck.c new file mode 100644 index 0000000000..feef232619 --- /dev/null +++ b/modules/openssl/curl_hostcheck.c @@ -0,0 +1,217 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* This file is an amalgamation of hostcheck.c and most of rawstr.c + from cURL. The contents of the COPYING file mentioned above are: + +COPYRIGHT AND PERMISSION NOTICE + +Copyright (c) 1996 - 2013, Daniel Stenberg, <daniel@haxx.se>. + +All rights reserved. + +Permission to use, copy, modify, and distribute this software for any purpose +with or without fee is hereby granted, provided that the above copyright +notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN +NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE +OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of a copyright holder shall not +be used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization of the copyright holder. +*/ + +#include "curl_hostcheck.h" +#include <string.h> + +/* Portable, consistent toupper (remember EBCDIC). Do not use toupper() because + its behavior is altered by the current locale. */ +static char Curl_raw_toupper(char in) +{ + switch (in) { + case 'a': + return 'A'; + case 'b': + return 'B'; + case 'c': + return 'C'; + case 'd': + return 'D'; + case 'e': + return 'E'; + case 'f': + return 'F'; + case 'g': + return 'G'; + case 'h': + return 'H'; + case 'i': + return 'I'; + case 'j': + return 'J'; + case 'k': + return 'K'; + case 'l': + return 'L'; + case 'm': + return 'M'; + case 'n': + return 'N'; + case 'o': + return 'O'; + case 'p': + return 'P'; + case 'q': + return 'Q'; + case 'r': + return 'R'; + case 's': + return 'S'; + case 't': + return 'T'; + case 'u': + return 'U'; + case 'v': + return 'V'; + case 'w': + return 'W'; + case 'x': + return 'X'; + case 'y': + return 'Y'; + case 'z': + return 'Z'; + } + return in; +} + +/* + * Curl_raw_equal() is for doing "raw" case insensitive strings. This is meant + * to be locale independent and only compare strings we know are safe for + * this. See http://daniel.haxx.se/blog/2008/10/15/strcasecmp-in-turkish/ for + * some further explanation to why this function is necessary. + * + * The function is capable of comparing a-z case insensitively even for + * non-ascii. + */ + +static int Curl_raw_equal(const char *first, const char *second) +{ + while(*first && *second) { + if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second)) + /* get out of the loop as soon as they don't match */ + break; + first++; + second++; + } + /* we do the comparison here (possibly again), just to make sure that if the + loop above is skipped because one of the strings reached zero, we must not + return this as a successful match */ + return (Curl_raw_toupper(*first) == Curl_raw_toupper(*second)); +} + +static int Curl_raw_nequal(const char *first, const char *second, size_t max) +{ + while(*first && *second && max) { + if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second)) { + break; + } + max--; + first++; + second++; + } + if(0 == max) + return 1; /* they are equal this far */ + + return Curl_raw_toupper(*first) == Curl_raw_toupper(*second); +} + +/* + * Match a hostname against a wildcard pattern. + * E.g. + * "foo.host.com" matches "*.host.com". + * + * We use the matching rule described in RFC6125, section 6.4.3. + * http://tools.ietf.org/html/rfc6125#section-6.4.3 + */ + +static int hostmatch(const char *hostname, const char *pattern) +{ + const char *pattern_label_end, *pattern_wildcard, *hostname_label_end; + int wildcard_enabled; + size_t prefixlen, suffixlen; + pattern_wildcard = strchr(pattern, '*'); + if(pattern_wildcard == NULL) + return Curl_raw_equal(pattern, hostname) ? + CURL_HOST_MATCH : CURL_HOST_NOMATCH; + + /* We require at least 2 dots in pattern to avoid too wide wildcard + match. */ + wildcard_enabled = 1; + pattern_label_end = strchr(pattern, '.'); + if(pattern_label_end == NULL || strchr(pattern_label_end+1, '.') == NULL || + pattern_wildcard > pattern_label_end || + Curl_raw_nequal(pattern, "xn--", 4)) { + wildcard_enabled = 0; + } + if(!wildcard_enabled) + return Curl_raw_equal(pattern, hostname) ? + CURL_HOST_MATCH : CURL_HOST_NOMATCH; + + hostname_label_end = strchr(hostname, '.'); + if(hostname_label_end == NULL || + !Curl_raw_equal(pattern_label_end, hostname_label_end)) + return CURL_HOST_NOMATCH; + + /* The wildcard must match at least one character, so the left-most + label of the hostname is at least as large as the left-most label + of the pattern. */ + if(hostname_label_end - hostname < pattern_label_end - pattern) + return CURL_HOST_NOMATCH; + + prefixlen = pattern_wildcard - pattern; + suffixlen = pattern_label_end - (pattern_wildcard+1); + return Curl_raw_nequal(pattern, hostname, prefixlen) && + Curl_raw_nequal(pattern_wildcard+1, hostname_label_end - suffixlen, + suffixlen) ? + CURL_HOST_MATCH : CURL_HOST_NOMATCH; +} + +int Tool_Curl_cert_hostcheck(const char *match_pattern, const char *hostname) +{ + if(!match_pattern || !*match_pattern || + !hostname || !*hostname) /* sanity check */ + return 0; + + if(Curl_raw_equal(hostname, match_pattern)) /* trivial case */ + return 1; + + if(hostmatch(hostname,match_pattern) == CURL_HOST_MATCH) + return 1; + return 0; +} diff --git a/modules/openssl/curl_hostcheck.h b/modules/openssl/curl_hostcheck.h new file mode 100644 index 0000000000..1b7fbe81e3 --- /dev/null +++ b/modules/openssl/curl_hostcheck.h @@ -0,0 +1,39 @@ +#ifndef HEADER_TOOL_CURL_HOSTCHECK_H +#define HEADER_TOOL_CURL_HOSTCHECK_H + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#define CURL_HOST_NOMATCH 0 +#define CURL_HOST_MATCH 1 +int Tool_Curl_cert_hostcheck(const char *match_pattern, const char *hostname); + +#ifdef __cplusplus +} +#endif + +#endif /* HEADER_CURL_HOSTCHECK_H */ + diff --git a/modules/openssl/register_types.cpp b/modules/openssl/register_types.cpp new file mode 100644 index 0000000000..6cc9fa3669 --- /dev/null +++ b/modules/openssl/register_types.cpp @@ -0,0 +1,42 @@ +/*************************************************************************/ +/* register_types.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#include "register_types.h" + +#include "stream_peer_openssl.h" + +void register_openssl_types() { + + ClassDB::register_class<StreamPeerOpenSSL>(); + StreamPeerOpenSSL::initialize_ssl(); +} + +void unregister_openssl_types() { + + StreamPeerOpenSSL::finalize_ssl(); +} diff --git a/modules/openssl/register_types.h b/modules/openssl/register_types.h new file mode 100644 index 0000000000..3bcee59bfd --- /dev/null +++ b/modules/openssl/register_types.h @@ -0,0 +1,30 @@ +/*************************************************************************/ +/* register_types.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +void register_openssl_types(); +void unregister_openssl_types(); diff --git a/modules/openssl/stream_peer_openssl.cpp b/modules/openssl/stream_peer_openssl.cpp new file mode 100644 index 0000000000..43a1f610d8 --- /dev/null +++ b/modules/openssl/stream_peer_openssl.cpp @@ -0,0 +1,646 @@ +/*************************************************************************/ +/* stream_peer_openssl.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#include "stream_peer_openssl.h" +//hostname matching code from curl + + +//#include <openssl/applink.c> // To prevent crashing (see the OpenSSL FAQ) + +bool StreamPeerOpenSSL::_match_host_name(const char *name, const char *hostname) { + + return Tool_Curl_cert_hostcheck(name,hostname)==CURL_HOST_MATCH; + //print_line("MATCH: "+String(name)+" vs "+String(hostname)); + //return true; +} + +Error StreamPeerOpenSSL::_match_common_name(const char *hostname, const X509 *server_cert) { + + int common_name_loc = -1; + X509_NAME_ENTRY *common_name_entry = NULL; + ASN1_STRING *common_name_asn1 = NULL; + char *common_name_str = NULL; + + // Find the position of the CN field in the Subject field of the certificate + common_name_loc = X509_NAME_get_index_by_NID(X509_get_subject_name((X509 *) server_cert), NID_commonName, -1); + + ERR_FAIL_COND_V(common_name_loc < 0, ERR_INVALID_PARAMETER ); + + // Extract the CN field + common_name_entry = X509_NAME_get_entry(X509_get_subject_name((X509 *) server_cert), common_name_loc); + + ERR_FAIL_COND_V(common_name_entry == NULL, ERR_INVALID_PARAMETER ); + + // Convert the CN field to a C string + common_name_asn1 = X509_NAME_ENTRY_get_data(common_name_entry); + + ERR_FAIL_COND_V(common_name_asn1 == NULL, ERR_INVALID_PARAMETER ); + + common_name_str = (char *) ASN1_STRING_data(common_name_asn1); + + // Make sure there isn't an embedded NUL character in the CN + bool malformed_certificate = (size_t)ASN1_STRING_length(common_name_asn1) != strlen(common_name_str); + + ERR_FAIL_COND_V(malformed_certificate, ERR_INVALID_PARAMETER ); + + + // Compare expected hostname with the CN + + + return _match_host_name(common_name_str,hostname)?OK:FAILED; + +} + + +/** +* Tries to find a match for hostname in the certificate's Subject Alternative Name extension. +* +*/ + +Error StreamPeerOpenSSL::_match_subject_alternative_name(const char *hostname, const X509 *server_cert) { + + Error result = FAILED; + int i; + int san_names_nb = -1; + STACK_OF(GENERAL_NAME) *san_names = NULL; + + // Try to extract the names within the SAN extension from the certificate + san_names = (STACK_OF(GENERAL_NAME) *)X509_get_ext_d2i((X509 *) server_cert, NID_subject_alt_name, NULL, NULL); + if (san_names == NULL) { + return ERR_FILE_NOT_FOUND; + } + san_names_nb = sk_GENERAL_NAME_num(san_names); + + // Check each name within the extension + for (i=0; i<san_names_nb; i++) { + const GENERAL_NAME *current_name = sk_GENERAL_NAME_value(san_names, i); + + if (current_name->type == GEN_DNS) { + // Current name is a DNS name, let's check it + char *dns_name = (char *) ASN1_STRING_data(current_name->d.dNSName); + + // Make sure there isn't an embedded NUL character in the DNS name + if ((size_t)ASN1_STRING_length(current_name->d.dNSName) != strlen(dns_name)) { + result = ERR_INVALID_PARAMETER; + break; + } + else { // Compare expected hostname with the DNS name + if (_match_host_name(dns_name, hostname)) { + result = OK; + break; + } + } + } + } + sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free); + + return result; +} + +/* See http://archives.seul.org/libevent/users/Jan-2013/msg00039.html */ +int StreamPeerOpenSSL::_cert_verify_callback(X509_STORE_CTX *x509_ctx, void *arg) { + + /* This is the function that OpenSSL would call if we hadn't called + * SSL_CTX_set_cert_verify_callback(). Therefore, we are "wrapping" + * the default functionality, rather than replacing it. */ + + bool base_cert_valid = X509_verify_cert(x509_ctx); + if (!base_cert_valid) { + print_line("Cause: "+String(X509_verify_cert_error_string(X509_STORE_CTX_get_error(x509_ctx)))); + ERR_print_errors_fp(stdout); + } + X509 *server_cert = X509_STORE_CTX_get_current_cert(x509_ctx); + + ERR_FAIL_COND_V(!server_cert,0); + + char cert_str[256]; + X509_NAME_oneline(X509_get_subject_name (server_cert), + cert_str, sizeof (cert_str)); + + print_line("CERT STR: "+String(cert_str)); + print_line("VALID: "+itos(base_cert_valid)); + + if (!base_cert_valid) + return 0; + + StreamPeerOpenSSL *ssl = (StreamPeerOpenSSL *)arg; + + if (ssl->validate_hostname) { + + Error err = _match_subject_alternative_name(ssl->hostname.utf8().get_data(),server_cert); + + if (err==ERR_FILE_NOT_FOUND) { + + err = _match_common_name(ssl->hostname.utf8().get_data(),server_cert); + } + + if (err!=OK) { + + ssl->status=STATUS_ERROR_HOSTNAME_MISMATCH; + return 0; + } + } + + return 1; + +} + + + +int StreamPeerOpenSSL::_bio_create( BIO *b ) { + b->init = 1; + b->num = 0; + b->ptr = NULL; + b->flags = 0; + return 1; +} + +int StreamPeerOpenSSL::_bio_destroy( BIO *b ) +{ + if ( b == NULL ) + return 0; + + b->ptr = NULL; /* sb_tls_remove() will free it */ + b->init = 0; + b->flags = 0; + return 1; +} + +int StreamPeerOpenSSL::_bio_read( BIO *b, char *buf, int len ) { + + + if ( buf == NULL || len <= 0 ) return 0; + + StreamPeerOpenSSL *sp = (StreamPeerOpenSSL *)b->ptr; + + ERR_FAIL_COND_V( sp == NULL, 0); + + BIO_clear_retry_flags( b ); + if (sp->use_blocking) { + + Error err = sp->base->get_data((uint8_t*)buf,len); + if (err!=OK) { + return -1; + } + + return len; + } else { + + int got; + Error err = sp->base->get_partial_data((uint8_t*)buf,len,got); + if (err!=OK) { + return -1; + } + if (got==0) { + BIO_set_retry_read( b ); + } + return got; + } + + //unreachable + return 0; +} + +int StreamPeerOpenSSL::_bio_write( BIO *b, const char *buf, int len ) { + + if ( buf == NULL || len <= 0 ) return 0; + + StreamPeerOpenSSL *sp = (StreamPeerOpenSSL *)b->ptr; + + ERR_FAIL_COND_V( sp == NULL, 0); + + BIO_clear_retry_flags( b ); + if (sp->use_blocking) { + + Error err = sp->base->put_data((const uint8_t*)buf,len); + if (err!=OK) { + return -1; + } + + return len; + } else { + + int sent; + Error err = sp->base->put_partial_data((const uint8_t*)buf,len,sent); + if (err!=OK) { + return -1; + } + if (sent==0) { + BIO_set_retry_write( b ); + } + return sent; + + } + + //unreachable + return 0; +} + +long StreamPeerOpenSSL::_bio_ctrl( BIO *b, int cmd, long num, void *ptr ) +{ + if ( cmd == BIO_CTRL_FLUSH ) { + /* The OpenSSL library needs this */ + return 1; + } + return 0; +} + +int StreamPeerOpenSSL::_bio_gets( BIO *b, char *buf, int len ) +{ + return -1; +} + +int StreamPeerOpenSSL::_bio_puts( BIO *b, const char *str ) +{ + return _bio_write( b, str, strlen( str ) ); +} + +BIO_METHOD StreamPeerOpenSSL::_bio_method = { + /* it's a source/sink BIO */ + ( 100 | 0x400 ), + "streampeer glue", + _bio_write, + _bio_read, + _bio_puts, + _bio_gets, + _bio_ctrl, + _bio_create, + _bio_destroy +}; + +Error StreamPeerOpenSSL::connect_to_stream(Ref<StreamPeer> p_base, bool p_validate_certs, const String& p_for_hostname) { + + if (connected) + disconnect_from_stream(); + + + hostname=p_for_hostname; + status=STATUS_DISCONNECTED; + + // Set up a SSL_CTX object, which will tell our BIO object how to do its work + ctx = SSL_CTX_new(SSLv23_client_method()); + base=p_base; + validate_certs=p_validate_certs; + validate_hostname=p_for_hostname!=""; + + + + + if (p_validate_certs) { + + + if (certs.size()) { + //yay for undocumented OpenSSL functions + + X509_STORE *store = SSL_CTX_get_cert_store(ctx); + for(int i=0;i<certs.size();i++) { + + X509_STORE_add_cert(store,certs[i]); + + } +#if 0 + const unsigned char *in=(const unsigned char *)certs.ptr(); + X509 *Cert = d2i_X509(NULL, &in, certs.size()-1); + if (!Cert) { + print_line(String(ERR_error_string(ERR_get_error(),NULL))); + } + ERR_FAIL_COND_V(!Cert,ERR_PARSE_ERROR); + + X509_STORE *store = SSL_CTX_get_cert_store(ctx); + X509_STORE_add_cert(store,Cert); + + //char *str = X509_NAME_oneline(X509_get_subject_name(Cert),0,0); + //printf ("subject: %s\n", str); /* [1] */ +#endif + } + + //used for testing + //int res = SSL_CTX_load_verify_locations(ctx,"/etc/ssl/certs/ca-certificates.crt",NULL); + //print_line("verify locations res: "+itos(res)); + + + /* Ask OpenSSL to verify the server certificate. Note that this + * does NOT include verifying that the hostname is correct. + * So, by itself, this means anyone with any legitimate + * CA-issued certificate for any website, can impersonate any + * other website in the world. This is not good. See "The + * Most Dangerous Code in the World" article at + * https://crypto.stanford.edu/~dabo/pubs/abstracts/ssl-client-bugs.html + */ + SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); + /* This is how we solve the problem mentioned in the previous + * comment. We "wrap" OpenSSL's validation routine in our + * own routine, which also validates the hostname by calling + * the code provided by iSECPartners. Note that even though + * the "Everything You've Always Wanted to Know About + * Certificate Validation With OpenSSL (But Were Afraid to + * Ask)" paper from iSECPartners says very explicitly not to + * call SSL_CTX_set_cert_verify_callback (at the bottom of + * page 2), what we're doing here is safe because our + * cert_verify_callback() calls X509_verify_cert(), which is + * OpenSSL's built-in routine which would have been called if + * we hadn't set the callback. Therefore, we're just + * "wrapping" OpenSSL's routine, not replacing it. */ + SSL_CTX_set_cert_verify_callback (ctx, _cert_verify_callback,this); + + //Let the verify_callback catch the verify_depth error so that we get an appropriate error in the logfile. (??) + SSL_CTX_set_verify_depth(ctx,max_cert_chain_depth + 1); + + } + + + + + + ssl = SSL_new( ctx ); + bio = BIO_new( &_bio_method ); + bio->ptr = this; + SSL_set_bio( ssl, bio, bio ); + + if (p_for_hostname!=String()) { + SSL_set_tlsext_host_name(ssl,p_for_hostname.utf8().get_data()); + } + + use_blocking=true; // let handshake use blocking + // Set the SSL to automatically retry on failure. + SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); + + // Same as before, try to connect. + int result = SSL_connect( ssl ); + + print_line("CONNECTION RESULT: "+itos(result)); + if (result<1) { + ERR_print_errors_fp(stdout); + _print_error(result); + } + + X509 * peer = SSL_get_peer_certificate(ssl); + + if (peer) { + bool cert_ok = SSL_get_verify_result(ssl) == X509_V_OK; + print_line("cert_ok: "+itos(cert_ok)); + + } else if (validate_certs){ + status=STATUS_ERROR_NO_CERTIFICATE; + } + + connected=true; + status=STATUS_CONNECTED; + + return OK; +} + +Error StreamPeerOpenSSL::accept_stream(Ref<StreamPeer> p_base) { + + + return ERR_UNAVAILABLE; +} + +void StreamPeerOpenSSL::_print_error(int err) { + + err = SSL_get_error(ssl,err); + switch(err) { + case SSL_ERROR_NONE: ERR_PRINT("NO ERROR: The TLS/SSL I/O operation completed"); break; + case SSL_ERROR_ZERO_RETURN: ERR_PRINT("The TLS/SSL connection has been closed."); + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + ERR_PRINT("The operation did not complete."); break; + case SSL_ERROR_WANT_CONNECT: + case SSL_ERROR_WANT_ACCEPT: + ERR_PRINT("The connect/accept operation did not complete"); break; + case SSL_ERROR_WANT_X509_LOOKUP: + ERR_PRINT("The operation did not complete because an application callback set by SSL_CTX_set_client_cert_cb() has asked to be called again."); break; + case SSL_ERROR_SYSCALL: + ERR_PRINT("Some I/O error occurred. The OpenSSL error queue may contain more information on the error."); break; + case SSL_ERROR_SSL: + ERR_PRINT("A failure in the SSL library occurred, usually a protocol error."); break; + + } +} + +Error StreamPeerOpenSSL::put_data(const uint8_t* p_data,int p_bytes) { + + ERR_FAIL_COND_V(!connected,ERR_UNCONFIGURED); + + while(p_bytes>0) { + int ret = SSL_write(ssl,p_data,p_bytes); + if (ret<=0) { + _print_error(ret); + disconnect_from_stream(); + return ERR_CONNECTION_ERROR; + } + p_data+=ret; + p_bytes-=ret; + } + + return OK; + +} + +Error StreamPeerOpenSSL::put_partial_data(const uint8_t* p_data,int p_bytes, int &r_sent){ + + ERR_FAIL_COND_V(!connected,ERR_UNCONFIGURED); + if (p_bytes==0) + return OK; + + Error err = put_data(p_data,p_bytes); + if (err!=OK) + return err; + + r_sent=p_bytes; + return OK; + +} + +Error StreamPeerOpenSSL::get_data(uint8_t* p_buffer, int p_bytes){ + + ERR_FAIL_COND_V(!connected,ERR_UNCONFIGURED); + + while(p_bytes>0) { + + int ret = SSL_read(ssl,p_buffer,p_bytes); + if (ret<=0) { + _print_error(ret); + disconnect_from_stream(); + return ERR_CONNECTION_ERROR; + } + p_buffer+=ret; + p_bytes-=ret; + } + + return OK; +} + +Error StreamPeerOpenSSL::get_partial_data(uint8_t* p_buffer, int p_bytes,int &r_received){ + + ERR_FAIL_COND_V(!connected,ERR_UNCONFIGURED); + if (p_bytes==0) { + r_received=0; + return OK; + } + + Error err = get_data(p_buffer,p_bytes); + if (err!=OK) + return err; + r_received=p_bytes; + return OK; +} + +int StreamPeerOpenSSL::get_available_bytes() const { + + ERR_FAIL_COND_V(!connected,0); + + return SSL_pending(ssl); + +} +StreamPeerOpenSSL::StreamPeerOpenSSL() { + + ctx=NULL; + ssl=NULL; + bio=NULL; + connected=false; + use_blocking=true; //might be improved int the future, but for now it always blocks + max_cert_chain_depth=9; + flags=0; +} + +void StreamPeerOpenSSL::disconnect_from_stream() { + + if (!connected) + return; + SSL_shutdown( ssl ); + SSL_free( ssl ); + SSL_CTX_free(ctx); + base=Ref<StreamPeer>(); + connected=false; + validate_certs=false; + validate_hostname=false; + status=STATUS_DISCONNECTED; + + +} + +StreamPeerOpenSSL::Status StreamPeerOpenSSL::get_status() const { + + return status; +} + + +StreamPeerOpenSSL::~StreamPeerOpenSSL() { + disconnect_from_stream(); +} + +StreamPeerSSL* StreamPeerOpenSSL::_create_func() { + + return memnew( StreamPeerOpenSSL ); +} + + +Vector<X509*> StreamPeerOpenSSL::certs; + + +void StreamPeerOpenSSL::_load_certs(const PoolByteArray& p_array) { + + PoolByteArray::Read r = p_array.read(); + BIO* mem = BIO_new(BIO_s_mem()); + BIO_puts(mem,(const char*)r.ptr()); + while(true) { + X509*cert = PEM_read_bio_X509(mem, NULL, 0, NULL); + if (!cert) + break; + certs.push_back(cert); + } + BIO_free(mem); +} + +void StreamPeerOpenSSL::initialize_ssl() { + + available=true; + + load_certs_func=_load_certs; + + _create=_create_func; + CRYPTO_malloc_init(); // Initialize malloc, free, etc for OpenSSL's use + SSL_library_init(); // Initialize OpenSSL's SSL libraries + SSL_load_error_strings(); // Load SSL error strings + ERR_load_BIO_strings(); // Load BIO error strings + OpenSSL_add_all_algorithms(); // Load all available encryption algorithms + String certs_path =GLOBAL_DEF("network/ssl/certificates",""); + GlobalConfig::get_singleton()->set_custom_property_info("network/ssl/certificates",PropertyInfo(Variant::STRING,"network/ssl/certificates",PROPERTY_HINT_FILE,"*.crt")); + if (certs_path!="") { + + + + FileAccess *f=FileAccess::open(certs_path,FileAccess::READ); + if (f) { + PoolByteArray arr; + int flen = f->get_len(); + arr.resize(flen+1); + { + PoolByteArray::Write w = arr.write(); + f->get_buffer(w.ptr(),flen); + w[flen]=0; //end f string + } + + memdelete(f); + + _load_certs(arr); + print_line("Loaded certs from '"+certs_path+"': "+itos(certs.size())); + } + } + String config_path =GLOBAL_DEF("network/ssl/config",""); + GlobalConfig::get_singleton()->set_custom_property_info("network/ssl/config",PropertyInfo(Variant::STRING,"network/ssl/config",PROPERTY_HINT_FILE,"*.cnf")); + if (config_path!="") { + + Vector<uint8_t> data = FileAccess::get_file_as_array(config_path); + if (data.size()) { + data.push_back(0); + BIO* mem = BIO_new(BIO_s_mem()); + BIO_puts(mem,(const char*) data.ptr()); + + while(true) { + X509*cert = PEM_read_bio_X509(mem, NULL, 0, NULL); + if (!cert) + break; + certs.push_back(cert); + } + BIO_free(mem); + } + print_line("Loaded certs from '"+certs_path+"': "+itos(certs.size())); + + } + +} + +void StreamPeerOpenSSL::finalize_ssl(){ + + for(int i=0;i<certs.size();i++) { + X509_free(certs[i]); + } + certs.clear(); +} diff --git a/modules/openssl/stream_peer_openssl.h b/modules/openssl/stream_peer_openssl.h new file mode 100644 index 0000000000..84ae03fe07 --- /dev/null +++ b/modules/openssl/stream_peer_openssl.h @@ -0,0 +1,109 @@ +/*************************************************************************/ +/* stream_peer_openssl.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#ifndef STREAM_PEER_OPEN_SSL_H +#define STREAM_PEER_OPEN_SSL_H + +#include <stdio.h> // If you don't know what this is for stop reading now. +#include "io/stream_peer_ssl.h" +#include "global_config.h" +#include "os/file_access.h" +#include "curl_hostcheck.h" + +#include <openssl/bio.h> // BIO objects for I/O +#include <openssl/ssl.h> // SSL and SSL_CTX for SSL connections +#include <openssl/err.h> // Error reporting +#include <openssl/x509v3.h> + +class StreamPeerOpenSSL : public StreamPeerSSL { +private: + static int _bio_create( BIO *b ); + static int _bio_destroy( BIO *b ); + static int _bio_read( BIO *b, char *buf, int len ); + static int _bio_write( BIO *b, const char *buf, int len ); + static long _bio_ctrl( BIO *b, int cmd, long num, void *ptr ); + static int _bio_gets( BIO *b, char *buf, int len ); + static int _bio_puts( BIO *b, const char *str ); + + static BIO_METHOD _bio_method; + + static bool _match_host_name(const char *name, const char *hostname); + static Error _match_common_name(const char *hostname, const X509 *server_cert); + static Error _match_subject_alternative_name(const char *hostname, const X509 *server_cert); + + + static int _cert_verify_callback(X509_STORE_CTX *x509_ctx, void *arg); + + + Status status; + String hostname; + int max_cert_chain_depth; + SSL_CTX* ctx; + SSL* ssl; + BIO* bio; + bool connected; + int flags; + bool use_blocking; + bool validate_certs; + bool validate_hostname; + + Ref<StreamPeer> base; + + static StreamPeerSSL* _create_func(); + void _print_error(int err); + + static Vector<X509*> certs; + + static void _load_certs(const PoolByteArray& p_array); +protected: + static void _bind_methods(); +public: + + + virtual Error accept_stream(Ref<StreamPeer> p_base); + virtual Error connect_to_stream(Ref<StreamPeer> p_base,bool p_validate_certs=false,const String& p_for_hostname=String()); + virtual Status get_status() const; + + virtual void disconnect_from_stream(); + + virtual Error put_data(const uint8_t* p_data,int p_bytes); + virtual Error put_partial_data(const uint8_t* p_data,int p_bytes, int &r_sent); + + virtual Error get_data(uint8_t* p_buffer, int p_bytes); + virtual Error get_partial_data(uint8_t* p_buffer, int p_bytes,int &r_received); + + virtual int get_available_bytes() const; + + static void initialize_ssl(); + static void finalize_ssl(); + + StreamPeerOpenSSL(); + ~StreamPeerOpenSSL(); +}; + +#endif // STREAM_PEER_SSL_H diff --git a/modules/opus/SCsub b/modules/opus/SCsub new file mode 100644 index 0000000000..4d3053c7ec --- /dev/null +++ b/modules/opus/SCsub @@ -0,0 +1,216 @@ +#!/usr/bin/env python + +Import('env') +Import('env_modules') + +env_opus = env_modules.Clone() + +# Thirdparty source files +if (env['builtin_opus'] != 'no'): + thirdparty_dir = "#thirdparty/opus/" + + thirdparty_sources = [ + "silk/tables_other.c", + "silk/sum_sqr_shift.c", + "silk/PLC.c", + "silk/dec_API.c", + "silk/decode_pulses.c", + "silk/inner_prod_aligned.c", + "silk/init_encoder.c", + "silk/interpolate.c", + "silk/stereo_encode_pred.c", + "silk/decode_frame.c", + "silk/NLSF_del_dec_quant.c", + "silk/VAD.c", + "silk/resampler_private_AR2.c", + "silk/NLSF_unpack.c", + "silk/resampler_down2.c", + "silk/sort.c", + "silk/resampler_private_IIR_FIR.c", + "silk/resampler_down2_3.c", + "silk/resampler_private_up2_HQ.c", + "silk/tables_gain.c", + "silk/stereo_find_predictor.c", + "silk/stereo_quant_pred.c", + "silk/NLSF_stabilize.c", + "silk/ana_filt_bank_1.c", + "silk/check_control_input.c", + "silk/bwexpander.c", + "silk/A2NLSF.c", + "silk/LPC_inv_pred_gain.c", + "silk/log2lin.c", + "silk/process_NLSFs.c", + "silk/sigm_Q15.c", + "silk/VQ_WMat_EC.c", + "silk/quant_LTP_gains.c", + "silk/resampler_private_down_FIR.c", + "silk/NLSF_decode.c", + "silk/control_codec.c", + "silk/NLSF_VQ_weights_laroia.c", + "silk/decode_pitch.c", + "silk/stereo_decode_pred.c", + "silk/tables_pulses_per_block.c", + "silk/init_decoder.c", + "silk/table_LSF_cos.c", + "silk/decode_core.c", + "silk/code_signs.c", + "silk/enc_API.c", + "silk/tables_LTP.c", + "silk/pitch_est_tables.c", + "silk/biquad_alt.c", + "silk/encode_indices.c", + "silk/tables_NLSF_CB_WB.c", + "silk/debug.c", + "silk/decode_parameters.c", + "silk/tables_pitch_lag.c", + "silk/NLSF2A.c", + "silk/resampler.c", + "silk/decode_indices.c", + "silk/NLSF_VQ.c", + "silk/bwexpander_32.c", + "silk/tables_NLSF_CB_NB_MB.c", + "silk/encode_pulses.c", + "silk/NSQ_del_dec.c", + "silk/control_SNR.c", + "silk/shell_coder.c", + "silk/NLSF_encode.c", + "silk/stereo_MS_to_LR.c", + "silk/stereo_LR_to_MS.c", + "silk/HP_variable_cutoff.c", + "silk/LPC_analysis_filter.c", + "silk/CNG.c", + "silk/decoder_set_fs.c", + "silk/resampler_rom.c", + "silk/control_audio_bandwidth.c", + "silk/lin2log.c", + "silk/LP_variable_cutoff.c", + "silk/NSQ.c", + "silk/gain_quant.c", + "celt/laplace.c", + "celt/vq.c", + "celt/quant_bands.c", + "celt/kiss_fft.c", + "celt/entcode.c", + "celt/entenc.c", + "celt/celt_lpc.c", + "celt/pitch.c", + "celt/rate.c", + "celt/mathops.c", + #"celt/arm/armcpu.c", + #"celt/arm/celt_neon_intr.c", + #"celt/arm/celt_ne10_mdct.c", + #"celt/arm/celt_ne10_fft.c", + #"celt/arm/arm_celt_map.c", + "celt/celt_encoder.c", + "celt/celt.c", + "celt/bands.c", + "celt/cwrs.c", + "celt/entdec.c", + "celt/celt_decoder.c", + "celt/mdct.c", + "celt/modes.c", + "repacketizer.c", + "mlp_data.c", + "opus_multistream.c", + "opusfile.c", + "opus_encoder.c", + "analysis.c", + "mlp.c", + "info.c", + "stream.c", + "opus_decoder.c", + "internal.c", + "wincerts.c", + "opus.c", + "opus_multistream_encoder.c", + "http.c", + "opus_multistream_decoder.c" + ] + + opus_sources_silk = [] + + if("opus_fixed_point" in env and env.opus_fixed_point == "yes"): + env_opus.Append(CFLAGS=["-DFIXED_POINT"]) + opus_sources_silk = [ + "silk/fixed/schur64_FIX.c", + "silk/fixed/residual_energy16_FIX.c", + "silk/fixed/encode_frame_FIX.c", + "silk/fixed/regularize_correlations_FIX.c", + "silk/fixed/apply_sine_window_FIX.c", + "silk/fixed/solve_LS_FIX.c", + "silk/fixed/schur_FIX.c", + "silk/fixed/pitch_analysis_core_FIX.c", + "silk/fixed/noise_shape_analysis_FIX.c", + "silk/fixed/find_LTP_FIX.c", + "silk/fixed/vector_ops_FIX.c", + "silk/fixed/autocorr_FIX.c", + "silk/fixed/warped_autocorrelation_FIX.c", + "silk/fixed/find_pitch_lags_FIX.c", + "silk/fixed/k2a_Q16_FIX.c", + "silk/fixed/LTP_scale_ctrl_FIX.c", + "silk/fixed/corrMatrix_FIX.c", + "silk/fixed/prefilter_FIX.c", + "silk/fixed/find_LPC_FIX.c", + "silk/fixed/residual_energy_FIX.c", + "silk/fixed/process_gains_FIX.c", + "silk/fixed/LTP_analysis_filter_FIX.c", + "silk/fixed/k2a_FIX.c", + "silk/fixed/burg_modified_FIX.c", + "silk/fixed/find_pred_coefs_FIX.c" + ] + else: + opus_sources_silk = [ + "silk/float/LTP_scale_ctrl_FLP.c", + "silk/float/regularize_correlations_FLP.c", + "silk/float/corrMatrix_FLP.c", + "silk/float/LPC_analysis_filter_FLP.c", + "silk/float/levinsondurbin_FLP.c", + "silk/float/schur_FLP.c", + "silk/float/scale_vector_FLP.c", + "silk/float/apply_sine_window_FLP.c", + "silk/float/pitch_analysis_core_FLP.c", + "silk/float/wrappers_FLP.c", + "silk/float/bwexpander_FLP.c", + "silk/float/warped_autocorrelation_FLP.c", + "silk/float/solve_LS_FLP.c", + "silk/float/find_LPC_FLP.c", + "silk/float/autocorrelation_FLP.c", + "silk/float/find_pred_coefs_FLP.c", + "silk/float/find_pitch_lags_FLP.c", + "silk/float/burg_modified_FLP.c", + "silk/float/find_LTP_FLP.c", + "silk/float/energy_FLP.c", + "silk/float/sort_FLP.c", + "silk/float/LPC_inv_pred_gain_FLP.c", + "silk/float/k2a_FLP.c", + "silk/float/noise_shape_analysis_FLP.c", + "silk/float/inner_product_FLP.c", + "silk/float/process_gains_FLP.c", + "silk/float/encode_frame_FLP.c", + "silk/float/scale_copy_vector_FLP.c", + "silk/float/residual_energy_FLP.c", + "silk/float/LTP_analysis_filter_FLP.c", + "silk/float/prefilter_FLP.c" + ] + + thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources + opus_sources_silk] + + env_opus.add_source_files(env.modules_sources, thirdparty_sources) + env_opus.Append(CFLAGS=["-DHAVE_CONFIG_H"]) + + thirdparty_include_paths = [ + "", + "celt", + "opus", + "silk", + "silk/fixed", + "silk/float", + ] + env_opus.Append(CPPPATH=[thirdparty_dir + "/" + dir for dir in thirdparty_include_paths]) + + # also requires libogg + if (env['builtin_libogg'] != 'no'): + env_opus.Append(CPPPATH=["#thirdparty/libogg"]) + +# Module files +env_opus.add_source_files(env.modules_sources, "*.cpp") diff --git a/modules/opus/audio_stream_opus.cpp b/modules/opus/audio_stream_opus.cpp new file mode 100644 index 0000000000..4a6b2e224c --- /dev/null +++ b/modules/opus/audio_stream_opus.cpp @@ -0,0 +1,376 @@ +/*************************************************************************/ +/* audio_stream_opus.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Author: George Marques <george@gmarqu.es> */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#include "audio_stream_opus.h" + +const float AudioStreamPlaybackOpus::osrate=48000.0f; + +int AudioStreamPlaybackOpus::_op_read_func(void *_stream, unsigned char *_ptr, int _nbytes) { + FileAccess *fa=(FileAccess*)_stream; + + if(fa->eof_reached()) + return 0; + + uint8_t *dst = (uint8_t*)_ptr; + + int read = fa->get_buffer(dst, _nbytes); + + return read; +} + +int AudioStreamPlaybackOpus::_op_seek_func(void *_stream, opus_int64 _offset, int _whence){ + +#ifdef SEEK_SET + FileAccess *fa=(FileAccess*)_stream; + + switch (_whence) { + case SEEK_SET: { + fa->seek(_offset); + } break; + case SEEK_CUR: { + fa->seek(fa->get_pos()+_offset); + } break; + case SEEK_END: { + fa->seek_end(_offset); + } break; + default: { + ERR_PRINT("BUG, wtf was whence set to?\n"); + } + } + int ret=fa->eof_reached()?-1:0; + return ret; +#else + return -1; // no seeking +#endif +} + +int AudioStreamPlaybackOpus::_op_close_func(void *_stream) { + if (!_stream) + return 0; + FileAccess *fa=(FileAccess*)_stream; + if (fa->is_open()) + fa->close(); + return 0; +} + +opus_int64 AudioStreamPlaybackOpus::_op_tell_func(void *_stream) { + FileAccess *_fa = (FileAccess*)_stream; + return (opus_int64)_fa->get_pos(); +} + +void AudioStreamPlaybackOpus::_clear_stream() { + if(!stream_loaded) + return; + + op_free(opus_file); + _close_file(); + + stream_loaded=false; + stream_channels=1; + playing=false; +} + +void AudioStreamPlaybackOpus::_close_file() { + if (f) { + memdelete(f); + f=NULL; + } +} + +Error AudioStreamPlaybackOpus::_load_stream() { + + ERR_FAIL_COND_V(!stream_valid,ERR_UNCONFIGURED); + + _clear_stream(); + if (file=="") + return ERR_INVALID_DATA; + + Error err; + f=FileAccess::open(file,FileAccess::READ,&err); + + if (err) { + ERR_FAIL_COND_V( err, err ); + } + + int _err = 0; + + opus_file = op_open_callbacks(f,&_op_callbacks,NULL,0,&_err); + + switch (_err) { + case OP_EREAD: { // - Can't read the file. + memdelete(f); f=NULL; + ERR_FAIL_V( ERR_FILE_CANT_READ ); + } break; + case OP_EVERSION: // - Unrecognized version number. + case OP_ENOTFORMAT: // - Stream is not Opus data. + case OP_EIMPL : { // - Stream used non-implemented feature. + memdelete(f); f=NULL; + ERR_FAIL_V( ERR_FILE_UNRECOGNIZED ); + } break; + case OP_EBADLINK: // - Failed to find old data after seeking. + case OP_EBADTIMESTAMP: // - Timestamp failed the validity checks. + case OP_EBADHEADER: { // - Invalid or mising Opus bitstream header. + memdelete(f); f=NULL; + ERR_FAIL_V( ERR_FILE_CORRUPT ); + } break; + case OP_EFAULT: { // - Internal logic fault; indicates a bug or heap/stack corruption. + memdelete(f); f=NULL; + ERR_FAIL_V( ERR_BUG ); + } break; + } + repeats=0; + stream_loaded=true; + + + return OK; +} + +AudioStreamPlaybackOpus::AudioStreamPlaybackOpus() { + loops=false; + playing=false; + f = NULL; + stream_loaded=false; + stream_valid=false; + repeats=0; + paused=true; + stream_channels=0; + current_section=0; + length=0; + loop_restart_time=0; + pre_skip=0; + + _op_callbacks.read = _op_read_func; + _op_callbacks.seek = _op_seek_func; + _op_callbacks.tell = _op_tell_func; + _op_callbacks.close = _op_close_func; +} + +Error AudioStreamPlaybackOpus::set_file(const String &p_file) { + file=p_file; + stream_valid=false; + Error err; + f=FileAccess::open(file,FileAccess::READ,&err); + + if (err) { + ERR_FAIL_COND_V( err, err ); + } + + int _err; + + opus_file = op_open_callbacks(f,&_op_callbacks,NULL,0,&_err); + + switch (_err) { + case OP_EREAD: { // - Can't read the file. + memdelete(f); f=NULL; + ERR_FAIL_V( ERR_FILE_CANT_READ ); + } break; + case OP_EVERSION: // - Unrecognized version number. + case OP_ENOTFORMAT: // - Stream is not Opus data. + case OP_EIMPL : { // - Stream used non-implemented feature. + memdelete(f); f=NULL; + ERR_FAIL_V( ERR_FILE_UNRECOGNIZED ); + } break; + case OP_EBADLINK: // - Failed to find old data after seeking. + case OP_EBADTIMESTAMP: // - Timestamp failed the validity checks. + case OP_EBADHEADER: { // - Invalid or mising Opus bitstream header. + memdelete(f); f=NULL; + ERR_FAIL_V( ERR_FILE_CORRUPT ); + } break; + case OP_EFAULT: { // - Internal logic fault; indicates a bug or heap/stack corruption. + memdelete(f); f=NULL; + ERR_FAIL_V( ERR_BUG ); + } break; + } + + const OpusHead *oinfo = op_head(opus_file,-1); + + stream_channels=oinfo->channel_count; + pre_skip=oinfo->pre_skip; + frames_mixed=pre_skip; + ogg_int64_t len = op_pcm_total(opus_file,-1); + if(len < 0) { + length = 0; + } else { + length=(len/osrate); + } + + op_free(opus_file); + memdelete(f); + f=NULL; + stream_valid=true; + + + return OK; +} + +void AudioStreamPlaybackOpus::play(float p_from) { + if (playing) + stop(); + + if (_load_stream()!=OK) + return; + + frames_mixed=pre_skip; + playing=true; + if (p_from>0) { + seek_pos(p_from); + } +} + +void AudioStreamPlaybackOpus::stop() { + _clear_stream(); + playing=false; +} + +void AudioStreamPlaybackOpus::seek_pos(float p_time) { + if(!playing) return; + ogg_int64_t pcm_offset = (ogg_int64_t)(p_time * osrate); + bool ok = op_pcm_seek(opus_file,pcm_offset)==0; + if(!ok) { + ERR_PRINT("Seek time over stream size."); + return; + } + frames_mixed=osrate*p_time; +} + +int AudioStreamPlaybackOpus::mix(int16_t* p_bufer,int p_frames) { + if (!playing) + return 0; + + int total=p_frames; + + while (true) { + + int todo = p_frames; + + if (todo==0 || todo<MIN_MIX) { + break; + } + + int ret=op_read(opus_file,(opus_int16*)p_bufer,todo*stream_channels,¤t_section); + if (ret<0) { + playing = false; + ERR_EXPLAIN("Error reading Opus File: "+file); + ERR_BREAK(ret<0); + } else if (ret==0) { // end of song, reload? + op_free(opus_file); + + _close_file(); + + f=FileAccess::open(file,FileAccess::READ); + + int errv = 0; + opus_file = op_open_callbacks(f,&_op_callbacks,NULL,0,&errv); + if (errv!=0) { + playing=false; + break; // :( + } + + if (!has_loop()) { + playing=false; + repeats=1; + break; + } + + if (loop_restart_time) { + bool ok = op_pcm_seek(opus_file, (loop_restart_time*osrate)+pre_skip)==0; + if (!ok) { + playing=false; + ERR_PRINT("loop restart time rejected") + } + + frames_mixed=(loop_restart_time*osrate)+pre_skip; + } else { + frames_mixed=pre_skip; + } + repeats++; + continue; + + } + + stream_channels=op_head(opus_file,current_section)->channel_count; + + frames_mixed+=ret; + + p_bufer+=ret*stream_channels; + p_frames-=ret; + + } + + return total-p_frames; +} + +float AudioStreamPlaybackOpus::get_length() const { + if(!stream_loaded) { + if(const_cast<AudioStreamPlaybackOpus*>(this)->_load_stream() != OK) + return 0; + } + return length; +} + +float AudioStreamPlaybackOpus::get_pos() const { + + int32_t frames = int32_t(frames_mixed); + if (frames < 0) + frames=0; + return double(frames) / osrate; +} + +int AudioStreamPlaybackOpus::get_minimum_buffer_size() const { + return MIN_MIX; +} + +AudioStreamPlaybackOpus::~AudioStreamPlaybackOpus() { + _clear_stream(); +} + +RES ResourceFormatLoaderAudioStreamOpus::load(const String &p_path, const String& p_original_path, Error *r_error) { + if (r_error) + *r_error=OK; + + AudioStreamOpus *opus_stream = memnew(AudioStreamOpus); + opus_stream->set_file(p_path); + return Ref<AudioStreamOpus>(opus_stream); +} + +void ResourceFormatLoaderAudioStreamOpus::get_recognized_extensions(List<String> *p_extensions) const { + + p_extensions->push_back("opus"); +} +String ResourceFormatLoaderAudioStreamOpus::get_resource_type(const String &p_path) const { + + if (p_path.get_extension().to_lower()=="opus") + return "AudioStreamOpus"; + return ""; +} + +bool ResourceFormatLoaderAudioStreamOpus::handles_type(const String& p_type) const { + return (p_type=="AudioStream" || p_type=="AudioStreamOpus"); +} diff --git a/modules/opus/audio_stream_opus.h b/modules/opus/audio_stream_opus.h new file mode 100644 index 0000000000..5093456ccd --- /dev/null +++ b/modules/opus/audio_stream_opus.h @@ -0,0 +1,141 @@ +/*************************************************************************/ +/* audio_stream_opus.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Author: George Marques <george@gmarqu.es> */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef AUDIO_STREAM_OPUS_H +#define AUDIO_STREAM_OPUS_H + +#include "io/resource_loader.h" +#include "os/file_access.h" +#include "scene/resources/audio_stream.h" + +#include <opus/opusfile.h> + +class AudioStreamPlaybackOpus : public AudioStreamPlayback { + + GDCLASS(AudioStreamPlaybackOpus,AudioStreamPlayback) + + enum { + MIN_MIX=1024 + }; + + FileAccess *f; + + OpusFileCallbacks _op_callbacks; + float length; + static int _op_read_func(void *_stream, unsigned char *_ptr, int _nbytes); + static int _op_seek_func(void *_stream, opus_int64 _offset, int _whence); + static int _op_close_func(void *_stream); + static opus_int64 _op_tell_func(void *_stream); + static const float osrate; + + String file; + int64_t frames_mixed; + + bool stream_loaded; + volatile bool playing; + OggOpusFile *opus_file; + int stream_channels; + int current_section; + int pre_skip; + + bool paused; + bool loops; + int repeats; + + Error _load_stream(); + void _clear_stream(); + void _close_file(); + + bool stream_valid; + float loop_restart_time; + +public: + Error set_file(const String& p_file); + + virtual void play(float p_from=0); + virtual void stop(); + virtual bool is_playing() const { return playing; } + + virtual void set_loop_restart_time(float p_time) { loop_restart_time=p_time; } + + virtual void set_paused(bool p_paused) { paused=p_paused; } + virtual bool is_paused() const { return paused; } + + virtual void set_loop(bool p_enable) { loops=p_enable; } + virtual bool has_loop() const {return loops; } + + virtual float get_length() const; + + virtual String get_stream_name() const { return ""; } + + virtual int get_loop_count() const { return repeats; } + + virtual float get_pos() const; + virtual void seek_pos(float p_time); + + virtual int get_channels() const { return stream_channels; } + virtual int get_mix_rate() const { return osrate; } + + virtual int get_minimum_buffer_size() const; + + virtual int mix(int16_t* p_bufer,int p_frames); + + AudioStreamPlaybackOpus(); + ~AudioStreamPlaybackOpus(); +}; + + +class AudioStreamOpus: public AudioStream { + + GDCLASS(AudioStreamOpus,AudioStream) + + String file; +public: + + Ref<AudioStreamPlayback> instance_playback() { + Ref<AudioStreamPlaybackOpus> pb = memnew( AudioStreamPlaybackOpus ); + pb->set_file(file); + return pb; + } + + void set_file(const String& p_file) { file=p_file; } + +}; + +class ResourceFormatLoaderAudioStreamOpus: public ResourceFormatLoader { +public: + virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL); + virtual void get_recognized_extensions(List<String> *p_extensions) const; + virtual bool handles_type(const String& p_type) const; + virtual String get_resource_type(const String &p_path) const; +}; + +#endif // AUDIO_STREAM_OPUS_H diff --git a/modules/opus/config.py b/modules/opus/config.py new file mode 100644 index 0000000000..ef5daca05c --- /dev/null +++ b/modules/opus/config.py @@ -0,0 +1,8 @@ + +def can_build(platform): +# return True + return False + + +def configure(env): + pass diff --git a/modules/opus/register_types.cpp b/modules/opus/register_types.cpp new file mode 100644 index 0000000000..a177bc9463 --- /dev/null +++ b/modules/opus/register_types.cpp @@ -0,0 +1,45 @@ +/*************************************************************************/ +/* register_types.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#include "register_types.h" + +#include "audio_stream_opus.h" + +static ResourceFormatLoaderAudioStreamOpus *opus_stream_loader = NULL; + +void register_opus_types() { + + opus_stream_loader = memnew( ResourceFormatLoaderAudioStreamOpus ); + ResourceLoader::add_resource_format_loader(opus_stream_loader); + ClassDB::register_class<AudioStreamOpus>(); +} + +void unregister_opus_types() { + + memdelete( opus_stream_loader ); +} diff --git a/modules/opus/register_types.h b/modules/opus/register_types.h new file mode 100644 index 0000000000..09181b4f03 --- /dev/null +++ b/modules/opus/register_types.h @@ -0,0 +1,30 @@ +/*************************************************************************/ +/* register_types.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +void register_opus_types(); +void unregister_opus_types(); diff --git a/modules/pbm/SCsub b/modules/pbm/SCsub new file mode 100644 index 0000000000..fa328be025 --- /dev/null +++ b/modules/pbm/SCsub @@ -0,0 +1,8 @@ +#!/usr/bin/env python + +Import('env') +Import('env_modules') + +env_pbm = env_modules.Clone() + +env_pbm.add_source_files(env.modules_sources, "*.cpp") diff --git a/modules/pbm/bitmap_loader_pbm.cpp b/modules/pbm/bitmap_loader_pbm.cpp new file mode 100644 index 0000000000..ab0805a6b0 --- /dev/null +++ b/modules/pbm/bitmap_loader_pbm.cpp @@ -0,0 +1,252 @@ +/*************************************************************************/ +/* bitmap_loader_pbm.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#include "bitmap_loader_pbm.h" +#include "os/file_access.h" +#include "scene/resources/bit_mask.h" + + +static bool _get_token(FileAccessRef& f,uint8_t &saved,PoolVector<uint8_t>& r_token,bool p_binary=false,bool p_single_chunk=false) { + + + int token_max = r_token.size(); + PoolVector<uint8_t>::Write w; + if (token_max) + w=r_token.write(); + int ofs=0; + bool lf=false; + + + while(true) { + + uint8_t b; + if (saved) { + b=saved; + saved=0; + } else { + b = f->get_8(); + } + if (f->eof_reached()) { + if (ofs) { + w=PoolVector<uint8_t>::Write(); + r_token.resize(ofs); + return true; + } else { + return false; + } + } + + if (!ofs && !p_binary && b=='#') { + //skip comment + while(b!='\n') { + if (f->eof_reached()) { + return false; + } + + b = f->get_8(); + } + + lf=true; + + } else if (b<=32 && !(p_binary && (ofs || lf))) { + + if (b=='\n') { + lf=true; + } + + + if (ofs && !p_single_chunk) { + w=PoolVector<uint8_t>::Write(); + r_token.resize(ofs); + saved=b; + + return true; + } + } else { + + bool resized=false; + while (ofs>=token_max) { + if (token_max) + token_max<<=1; + else + token_max=1; + resized=true; + } + if (resized) { + w=PoolVector<uint8_t>::Write(); + r_token.resize(token_max); + w=r_token.write(); + } + w[ofs++]=b; + } + } + + return false; +} + +static int _get_number_from_token(PoolVector<uint8_t>& r_token) { + + int len = r_token.size(); + PoolVector<uint8_t>::Read r = r_token.read(); + return String::to_int((const char*)r.ptr(),len); + +} + + +RES ResourceFormatPBM::load(const String &p_path,const String& p_original_path,Error *r_error) { + +#define _RETURN(m_err)\ +{\ + if (r_error)\ + *r_error=m_err;\ + ERR_FAIL_V(RES());\ +} + + + FileAccessRef f=FileAccess::open(p_path,FileAccess::READ); + uint8_t saved=0; + if (!f) + _RETURN(ERR_CANT_OPEN); + + PoolVector<uint8_t> token; + + if (!_get_token(f,saved,token)) { + _RETURN(ERR_PARSE_ERROR); + } + + if (token.size()!=2) { + _RETURN(ERR_FILE_CORRUPT); + } + if (token[0]!='P') { + _RETURN(ERR_FILE_CORRUPT); + } + if (token[1]!='1' && token[1]!='4') { + _RETURN(ERR_FILE_CORRUPT); + } + + bool bits = token[1]=='4'; + + if (!_get_token(f,saved,token)) { + _RETURN(ERR_PARSE_ERROR); + } + + int width = _get_number_from_token(token); + if (width<=0) { + _RETURN(ERR_FILE_CORRUPT); + } + + + if (!_get_token(f,saved,token)) { + _RETURN(ERR_PARSE_ERROR); + } + + int height = _get_number_from_token(token); + if (height<=0) { + _RETURN(ERR_FILE_CORRUPT); + } + + + Ref<BitMap> bm; + bm.instance(); + bm->create(Size2i(width,height)); + + if (!bits) { + + int required_bytes = width*height; + if (!_get_token(f,saved,token,false,true)) { + _RETURN(ERR_PARSE_ERROR); + } + + if (token.size()<required_bytes) { + _RETURN(ERR_FILE_CORRUPT); + } + + PoolVector<uint8_t>::Read r=token.read(); + + for(int i=0;i<height;i++) { + for(int j=0;j<width;j++) { + + + char num = r[i*width+j]; + bm->set_bit(Point2i(j,i),num=='0'); + } + + } + + + + } else { + //a single, entire token of bits! + if (!_get_token(f,saved,token,true)) { + _RETURN(ERR_PARSE_ERROR); + } + int required_bytes = Math::ceil((width*height)/8.0); + if (token.size()<required_bytes) { + _RETURN(ERR_FILE_CORRUPT); + } + + PoolVector<uint8_t>::Read r=token.read(); + int bitwidth = width; + if (bitwidth % 8) + bitwidth+=8-(bitwidth%8); + + for(int i=0;i<height;i++) { + for(int j=0;j<width;j++) { + + int ofs = bitwidth*i+j; + + uint8_t byte = r[ofs/8]; + bool bit = (byte>>(7-(ofs%8)))&1; + + bm->set_bit(Point2i(j,i),!bit); + + } + + } + + } + + return bm; + + +} + +void ResourceFormatPBM::get_recognized_extensions(List<String> *p_extensions) const { + p_extensions->push_back("pbm"); +} +bool ResourceFormatPBM::handles_type(const String& p_type) const { + return p_type=="BitMap"; +} +String ResourceFormatPBM::get_resource_type(const String &p_path) const { + + if (p_path.get_extension().to_lower()=="pbm") + return "BitMap"; + return ""; +} + + diff --git a/modules/pbm/bitmap_loader_pbm.h b/modules/pbm/bitmap_loader_pbm.h new file mode 100644 index 0000000000..b60b38fcca --- /dev/null +++ b/modules/pbm/bitmap_loader_pbm.h @@ -0,0 +1,50 @@ +/*************************************************************************/ +/* bitmap_loader_pbm.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#ifndef BITMAP_LOADER_PBM_H +#define BITMAP_LOADER_PBM_H + +#include "io/resource_loader.h" + +/** + @author Juan Linietsky <reduzio@gmail.com> +*/ +class ResourceFormatPBM : public ResourceFormatLoader { + + +public: + + virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL); + virtual void get_recognized_extensions(List<String> *p_extensions) const; + virtual bool handles_type(const String& p_type) const; + virtual String get_resource_type(const String &p_path) const; +}; + + + +#endif diff --git a/modules/pbm/config.py b/modules/pbm/config.py new file mode 100644 index 0000000000..fb920482f5 --- /dev/null +++ b/modules/pbm/config.py @@ -0,0 +1,7 @@ + +def can_build(platform): + return True + + +def configure(env): + pass diff --git a/modules/pbm/register_types.cpp b/modules/pbm/register_types.cpp new file mode 100644 index 0000000000..0dd39ce1e4 --- /dev/null +++ b/modules/pbm/register_types.cpp @@ -0,0 +1,44 @@ +/*************************************************************************/ +/* register_types.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#include "register_types.h" + +#include "bitmap_loader_pbm.h" + +static ResourceFormatPBM * pbm_loader = NULL; + +void register_pbm_types() { + + pbm_loader = memnew( ResourceFormatPBM ); + ResourceLoader::add_resource_format_loader(pbm_loader); +} + +void unregister_pbm_types() { + + memdelete( pbm_loader ); +} diff --git a/modules/pbm/register_types.h b/modules/pbm/register_types.h new file mode 100644 index 0000000000..c9a125083d --- /dev/null +++ b/modules/pbm/register_types.h @@ -0,0 +1,30 @@ +/*************************************************************************/ +/* register_types.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +void register_pbm_types(); +void unregister_pbm_types(); diff --git a/modules/pvr/SCsub b/modules/pvr/SCsub new file mode 100644 index 0000000000..ddca7a794e --- /dev/null +++ b/modules/pvr/SCsub @@ -0,0 +1,24 @@ +#!/usr/bin/env python + +Import('env') +Import('env_modules') + +env_pvr = env_modules.Clone() + +# Thirdparty source files +# Not unbundled so far since not widespread as shared library +thirdparty_dir = "#thirdparty/pvrtccompressor/" +thirdparty_sources = [ + "BitScale.cpp", + "MortonTable.cpp", + "PvrTcDecoder.cpp", + "PvrTcEncoder.cpp", + "PvrTcPacket.cpp", +] +thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] + +env_pvr.add_source_files(env.modules_sources, thirdparty_sources) +env_pvr.Append(CPPPATH=[thirdparty_dir]) + +# Godot source files +env_pvr.add_source_files(env.modules_sources, "*.cpp") diff --git a/modules/pvr/config.py b/modules/pvr/config.py new file mode 100644 index 0000000000..fb920482f5 --- /dev/null +++ b/modules/pvr/config.py @@ -0,0 +1,7 @@ + +def can_build(platform): + return True + + +def configure(env): + pass diff --git a/modules/pvr/register_types.cpp b/modules/pvr/register_types.cpp new file mode 100644 index 0000000000..2464e78984 --- /dev/null +++ b/modules/pvr/register_types.cpp @@ -0,0 +1,44 @@ +/*************************************************************************/ +/* register_types.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#include "register_types.h" + +#include "texture_loader_pvr.h" + +static ResourceFormatPVR *resource_loader_pvr = NULL; + +void register_pvr_types() { + + resource_loader_pvr = memnew( ResourceFormatPVR ); + ResourceLoader::add_resource_format_loader(resource_loader_pvr); +} + +void unregister_pvr_types() { + + memdelete(resource_loader_pvr); +} diff --git a/modules/pvr/register_types.h b/modules/pvr/register_types.h new file mode 100644 index 0000000000..ac2ab748df --- /dev/null +++ b/modules/pvr/register_types.h @@ -0,0 +1,30 @@ +/*************************************************************************/ +/* register_types.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +void register_pvr_types(); +void unregister_pvr_types(); diff --git a/modules/pvr/texture_loader_pvr.cpp b/modules/pvr/texture_loader_pvr.cpp new file mode 100644 index 0000000000..9805675f2c --- /dev/null +++ b/modules/pvr/texture_loader_pvr.cpp @@ -0,0 +1,721 @@ +/*************************************************************************/ +/* texture_loader_pvr.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#include "texture_loader_pvr.h" +#include "os/file_access.h" +#include <string.h> +#include "PvrTcEncoder.h" +#include "RgbaBitmap.h" + +static void _pvrtc_decompress(Image* p_img); + +enum PVRFLags { + + PVR_HAS_MIPMAPS=0x00000100, + PVR_TWIDDLED=0x00000200, + PVR_NORMAL_MAP=0x00000400, + PVR_BORDER=0x00000800, + PVR_CUBE_MAP=0x00001000, + PVR_FALSE_MIPMAPS=0x00002000, + PVR_VOLUME_TEXTURES=0x00004000, + PVR_HAS_ALPHA=0x00008000, + PVR_VFLIP=0x00010000 + +}; + + + +RES ResourceFormatPVR::load(const String &p_path,const String& p_original_path,Error *r_error) { + + if (r_error) + *r_error=ERR_CANT_OPEN; + + Error err; + FileAccess *f = FileAccess::open(p_path,FileAccess::READ,&err); + if (!f) + return RES(); + + FileAccessRef faref(f); + + ERR_FAIL_COND_V(err,RES()); + + if (r_error) + *r_error=ERR_FILE_CORRUPT; + + uint32_t hsize = f->get_32(); + + ERR_FAIL_COND_V(hsize!=52,RES()); + uint32_t height = f->get_32(); + uint32_t width = f->get_32(); + uint32_t mipmaps = f->get_32(); + uint32_t flags = f->get_32(); + uint32_t surfsize = f->get_32(); + uint32_t bpp = f->get_32(); + uint32_t rmask = f->get_32(); + uint32_t gmask = f->get_32(); + uint32_t bmask = f->get_32(); + uint32_t amask = f->get_32(); + uint8_t pvrid[5]={0,0,0,0,0}; + f->get_buffer(pvrid,4); + ERR_FAIL_COND_V(String((char*)pvrid)!="PVR!",RES()); + uint32_t surfcount = f->get_32(); + +/* + print_line("height: "+itos(height)); + print_line("width: "+itos(width)); + print_line("mipmaps: "+itos(mipmaps)); + print_line("flags: "+itos(flags)); + print_line("surfsize: "+itos(surfsize)); + print_line("bpp: "+itos(bpp)); + print_line("rmask: "+itos(rmask)); + print_line("gmask: "+itos(gmask)); + print_line("bmask: "+itos(bmask)); + print_line("amask: "+itos(amask)); + print_line("surfcount: "+itos(surfcount)); +*/ + + PoolVector<uint8_t> data; + data.resize(surfsize); + + ERR_FAIL_COND_V(data.size()==0,RES()); + + + PoolVector<uint8_t>::Write w = data.write(); + f->get_buffer(&w[0],surfsize); + err = f->get_error(); + ERR_FAIL_COND_V(err!=OK,RES()); + + Image::Format format=Image::FORMAT_MAX; + + + switch(flags&0xFF) { + + case 0x18: + case 0xC: format=(flags&PVR_HAS_ALPHA)?Image::FORMAT_PVRTC2A:Image::FORMAT_PVRTC2; break; + case 0x19: + case 0xD: format=(flags&PVR_HAS_ALPHA)?Image::FORMAT_PVRTC4A:Image::FORMAT_PVRTC4; break; + case 0x16: + format=Image::FORMAT_L8; break; + case 0x17: + format=Image::FORMAT_LA8; break; + case 0x20: + case 0x80: + case 0x81: + format=Image::FORMAT_DXT1; break; + case 0x21: + case 0x22: + case 0x82: + case 0x83: + format=Image::FORMAT_DXT3; break; + case 0x23: + case 0x24: + case 0x84: + case 0x85: + format=Image::FORMAT_DXT5; break; + case 0x4: + case 0x15: + format=Image::FORMAT_RGB8; break; + case 0x5: + case 0x12: + format=Image::FORMAT_RGBA8; break; + case 0x36: + format=Image::FORMAT_ETC; break; + default: + ERR_EXPLAIN("Unsupported format in PVR texture: "+itos(flags&0xFF)); + ERR_FAIL_V(RES()); + + } + + w = PoolVector<uint8_t>::Write(); + + int tex_flags=Texture::FLAG_FILTER|Texture::FLAG_REPEAT; + + if (mipmaps) + tex_flags|=Texture::FLAG_MIPMAPS; + + + print_line("flip: "+itos(flags&PVR_VFLIP)); + + Image image(width,height,mipmaps,format,data); + ERR_FAIL_COND_V(image.empty(),RES()); + + Ref<ImageTexture> texture = memnew( ImageTexture ); + texture->create_from_image(image,tex_flags); + + if (r_error) + *r_error=OK; + + return texture; + +} + +void ResourceFormatPVR::get_recognized_extensions(List<String> *p_extensions) const { + + p_extensions->push_back("pvr"); +} +bool ResourceFormatPVR::handles_type(const String& p_type) const { + + return ClassDB::is_parent_class(p_type,"Texture"); +} +String ResourceFormatPVR::get_resource_type(const String &p_path) const { + + + if (p_path.get_extension().to_lower()=="pvr") + return "Texture"; + return ""; +} + + + +static void _compress_pvrtc4(Image * p_img) { + + Image img = *p_img; + + bool make_mipmaps=false; + if (img.get_width()%8 || img.get_height()%8) { + make_mipmaps=img.has_mipmaps(); + img.resize(img.get_width()+(8-(img.get_width()%8)),img.get_height()+(8-(img.get_height()%8))); + } + img.convert(Image::FORMAT_RGBA8); + if (!img.has_mipmaps() && make_mipmaps) + img.generate_mipmaps(); + + bool use_alpha=img.detect_alpha(); + + Image new_img; + new_img.create(img.get_width(),img.get_height(),true,use_alpha?Image::FORMAT_PVRTC4A:Image::FORMAT_PVRTC4); + PoolVector<uint8_t> data=new_img.get_data(); + { + PoolVector<uint8_t>::Write wr=data.write(); + PoolVector<uint8_t>::Read r=img.get_data().read(); + + + for(int i=0;i<=new_img.get_mipmap_count();i++) { + + int ofs,size,w,h; + img.get_mipmap_offset_size_and_dimensions(i,ofs,size,w,h); + Javelin::RgbaBitmap bm(w,h); + copymem(bm.GetData(),&r[ofs],size); + { + Javelin::ColorRgba<unsigned char> *dp = bm.GetData(); + for(int j=0;j<size/4;j++) { + SWAP(dp[j].r,dp[j].b); + } + } + + new_img.get_mipmap_offset_size_and_dimensions(i,ofs,size,w,h); + Javelin::PvrTcEncoder::EncodeRgba4Bpp(&wr[ofs],bm); + } + + } + + *p_img = Image(new_img.get_width(),new_img.get_height(),new_img.has_mipmaps(),new_img.get_format(),data); + +} + +ResourceFormatPVR::ResourceFormatPVR() { + + + Image::_image_decompress_pvrtc=_pvrtc_decompress; + Image::_image_compress_pvrtc4_func=_compress_pvrtc4; + Image::_image_compress_pvrtc2_func=_compress_pvrtc4; + +} + +///////////////////////////////////////////////////////// + +//PVRTC decompressor, Based on PVRTC decompressor by IMGTEC. + +///////////////////////////////////////////////////////// + + +#define PT_INDEX 2 +#define BLK_Y_SIZE 4 +#define BLK_X_MAX 8 +#define BLK_X_2BPP 8 +#define BLK_X_4BPP 4 + +#define WRAP_COORD(Val, Size) ((Val) & ((Size)-1)) + +/* + Define an expression to either wrap or clamp large or small vals to the + legal coordinate range +*/ +#define LIMIT_COORD(Val, Size, p_tiled) \ + ((p_tiled)? WRAP_COORD((Val), (Size)): CLAMP((Val), 0, (Size)-1)) + + +struct PVRTCBlock { + //blocks are 64 bits + uint32_t data[2]; +}; + + + +_FORCE_INLINE_ bool is_po2( uint32_t p_input ) { + + if( p_input==0 ) + return 0; + uint32_t minus1=p_input- 1; + return ((p_input|minus1)==(p_input^minus1))?1:0; +} + + +static void unpack_5554(const PVRTCBlock *p_block, int p_ab_colors[2][4]) { + + uint32_t raw_bits[2]; + raw_bits[0] = p_block->data[1] & (0xFFFE); + raw_bits[1] = p_block->data[1] >> 16; + + for(int i=0;i<2;i++) { + + if(raw_bits[i] & (1<<15)) { + + p_ab_colors[i][0]= (raw_bits[i] >> 10) & 0x1F; + p_ab_colors[i][1]= (raw_bits[i] >> 5) & 0x1F; + p_ab_colors[i][2]= raw_bits[i] & 0x1F; + if(i==0) + p_ab_colors[0][2]|= p_ab_colors[0][2] >> 4; + p_ab_colors[i][3] = 0xF; + } else { + + p_ab_colors[i][0] = (raw_bits[i] >> (8-1)) & 0x1E; + p_ab_colors[i][1] = (raw_bits[i] >> (4-1)) & 0x1E; + + p_ab_colors[i][0] |= p_ab_colors[i][0] >> 4; + p_ab_colors[i][1] |= p_ab_colors[i][1] >> 4; + + p_ab_colors[i][2] = (raw_bits[i] & 0xF) << 1; + + if(i==0) + p_ab_colors[0][2] |= p_ab_colors[0][2] >> 3; + else + p_ab_colors[0][2] |= p_ab_colors[0][2] >> 4; + + p_ab_colors[i][3] = (raw_bits[i] >> 11) & 0xE; + } + } +} + + +static void unpack_modulations(const PVRTCBlock *p_block, const int p_2bit, int p_modulation[8][16], int p_modulation_modes[8][16], int p_x, int p_y) { + + int block_mod_mode = p_block->data[1] & 1; + uint32_t modulation_bits = p_block->data[0]; + + if(p_2bit && block_mod_mode) { + + for(int y = 0; y < BLK_Y_SIZE; y++) { + for(int x = 0; x < BLK_X_2BPP; x++) { + + p_modulation_modes[y+p_y][x+p_x] = block_mod_mode; + + if(((x^y)&1) == 0) { + p_modulation[y+p_y][x+p_x] = modulation_bits & 3; + modulation_bits >>= 2; + } + } + } + + } else if(p_2bit) { + + for(int y = 0; y < BLK_Y_SIZE; y++) { + for(int x = 0; x < BLK_X_2BPP; x++) { + p_modulation_modes[y+p_y][x+p_x] = block_mod_mode; + + if(modulation_bits & 1) + p_modulation[y+p_y][x+p_x] = 0x3; + else + p_modulation[y+p_y][x+p_x] = 0x0; + + modulation_bits >>= 1; + } + } + } else { + for(int y = 0; y < BLK_Y_SIZE; y++) { + for(int x = 0; x < BLK_X_4BPP; x++) { + p_modulation_modes[y+p_y][x+p_x] = block_mod_mode; + p_modulation[y+p_y][x+p_x] = modulation_bits & 3; + modulation_bits >>= 2; + } + } + } + + ERR_FAIL_COND(modulation_bits!=0); +} + + + +static void interpolate_colors(const int p_colorp[4], const int p_colorq[4], const int p_colorr[4], const int p_colors[4], bool p_2bit, const int x, const int y, int r_result[4]) { + int u, v, uscale; + int k; + + int tmp1, tmp2; + + int P[4], Q[4], R[4], S[4]; + + for(k = 0; k < 4; k++) { + P[k] = p_colorp[k]; + Q[k] = p_colorq[k]; + R[k] = p_colorr[k]; + S[k] = p_colors[k]; + } + + v = (y & 0x3) | ((~y & 0x2) << 1); + + if(p_2bit) + u = (x & 0x7) | ((~x & 0x4) << 1); + else + u = (x & 0x3) | ((~x & 0x2) << 1); + + v = v - BLK_Y_SIZE/2; + + if(p_2bit) { + u = u - BLK_X_2BPP/2; + uscale = 8; + } else { + u = u - BLK_X_4BPP/2; + uscale = 4; + } + + for(k = 0; k < 4; k++) { + tmp1 = P[k] * uscale + u * (Q[k] - P[k]); + tmp2 = R[k] * uscale + u * (S[k] - R[k]); + + tmp1 = tmp1 * 4 + v * (tmp2 - tmp1); + + r_result[k] = tmp1; + } + + if(p_2bit) { + for(k = 0; k < 3; k++) { + r_result[k] >>= 2; + } + + r_result[3] >>= 1; + } else { + for(k = 0; k < 3; k++) { + r_result[k] >>= 1; + } + } + + for(k = 0; k < 4; k++) { + ERR_FAIL_COND(r_result[k] >= 256); + } + + + for(k = 0; k < 3; k++) { + r_result[k] += r_result[k] >> 5; + } + + r_result[3] += r_result[3] >> 4; + + for(k = 0; k < 4; k++) { + ERR_FAIL_COND(r_result[k] >= 256); + } + +} + + +static void get_modulation_value(int x, int y, const int p_2bit, const int p_modulation[8][16], const int p_modulation_modes[8][16], int *r_mod, int *p_dopt) +{ + static const int rep_vals0[4] = {0, 3, 5, 8}; + static const int rep_vals1[4] = {0, 4, 4, 8}; + + int mod_val; + + y = (y & 0x3) | ((~y & 0x2) << 1); + + if(p_2bit) + x = (x & 0x7) | ((~x & 0x4) << 1); + else + x = (x & 0x3) | ((~x & 0x2) << 1); + + *p_dopt = 0; + + if(p_modulation_modes[y][x]==0) { + mod_val = rep_vals0[p_modulation[y][x]]; + } else if(p_2bit) { + if(((x^y)&1)==0) + mod_val = rep_vals0[p_modulation[y][x]]; + else if(p_modulation_modes[y][x] == 1) { + mod_val = ( + rep_vals0[p_modulation[y-1][x]] + + rep_vals0[p_modulation[y+1][x]] + + rep_vals0[p_modulation[y][x-1]] + + rep_vals0[p_modulation[y][x+1]] + 2) / 4; + } else if(p_modulation_modes[y][x] == 2) { + mod_val = ( + rep_vals0[p_modulation[y][x-1]] + + rep_vals0[p_modulation[y][x+1]] + 1) / 2; + } else { + mod_val = ( + rep_vals0[p_modulation[y-1][x]] + + rep_vals0[p_modulation[y+1][x]] + 1) / 2; + } + } else { + mod_val = rep_vals1[p_modulation[y][x]]; + + *p_dopt = p_modulation[y][x] == PT_INDEX; + } + + *r_mod =mod_val; +} + + +static int disable_twiddling = 0; + +static uint32_t twiddle_uv(uint32_t p_height, uint32_t p_width, uint32_t p_y, uint32_t p_x) { + + uint32_t twiddled; + + uint32_t min_dimension; + uint32_t max_value; + + uint32_t scr_bit_pos; + uint32_t dst_bit_pos; + + int shift_count; + + ERR_FAIL_COND_V(p_y >= p_height,0); + ERR_FAIL_COND_V(p_x >= p_width,0); + + ERR_FAIL_COND_V(!is_po2(p_height),0); + ERR_FAIL_COND_V(!is_po2(p_width),0); + + if(p_height < p_width) { + min_dimension = p_height; + max_value = p_x; + } else { + min_dimension = p_width; + max_value = p_y; + } + + if(disable_twiddling) + return (p_y* p_width + p_x); + + scr_bit_pos = 1; + dst_bit_pos = 1; + twiddled = 0; + shift_count = 0; + + while(scr_bit_pos < min_dimension) { + if(p_y & scr_bit_pos) { + twiddled |= dst_bit_pos; + } + + if(p_x & scr_bit_pos) { + twiddled |= (dst_bit_pos << 1); + } + + scr_bit_pos <<= 1; + dst_bit_pos <<= 2; + shift_count += 1; + + } + + max_value >>= shift_count; + + twiddled |= (max_value << (2*shift_count)); + + return twiddled; +} + +static void decompress_pvrtc(PVRTCBlock *p_comp_img, const int p_2bit, const int p_width, const int p_height, const int p_tiled, unsigned char* p_dst) { + int x, y; + int i, j; + + int block_x, blk_y; + int block_xp1, blk_yp1; + int x_block_size; + int block_width, block_height; + + int p_x, p_y; + + int p_modulation[8][16]; + int p_modulation_modes[8][16]; + + int Mod, DoPT; + + unsigned int u_pos; + + // local neighbourhood of blocks + PVRTCBlock *p_blocks[2][2]; + + PVRTCBlock *prev[2][2] = {{NULL, NULL}, {NULL, NULL}}; + + struct + { + int Reps[2][4]; + }colors5554[2][2]; + + + int ASig[4], BSig[4]; + + int r_result[4]; + + if(p_2bit) + x_block_size = BLK_X_2BPP; + else + x_block_size = BLK_X_4BPP; + + + block_width = MAX(2, p_width / x_block_size); + block_height = MAX(2, p_height / BLK_Y_SIZE); + + for(y = 0; y < p_height; y++) + { + for(x = 0; x < p_width; x++) + { + + block_x = (x - x_block_size/2); + blk_y = (y - BLK_Y_SIZE/2); + + block_x = LIMIT_COORD(block_x, p_width, p_tiled); + blk_y = LIMIT_COORD(blk_y, p_height, p_tiled); + + + block_x /= x_block_size; + blk_y /= BLK_Y_SIZE; + + block_xp1 = LIMIT_COORD(block_x+1, block_width, p_tiled); + blk_yp1 = LIMIT_COORD(blk_y+1, block_height, p_tiled); + + p_blocks[0][0] = p_comp_img +twiddle_uv(block_height, block_width, blk_y, block_x); + p_blocks[0][1] = p_comp_img +twiddle_uv(block_height, block_width, blk_y, block_xp1); + p_blocks[1][0] = p_comp_img +twiddle_uv(block_height, block_width, blk_yp1, block_x); + p_blocks[1][1] = p_comp_img +twiddle_uv(block_height, block_width, blk_yp1, block_xp1); + + if(memcmp(prev, p_blocks, 4*sizeof(void*)) != 0) { + p_y = 0; + for(i = 0; i < 2; i++) { + p_x = 0; + for(j = 0; j < 2; j++) { + unpack_5554(p_blocks[i][j], colors5554[i][j].Reps); + + unpack_modulations( + p_blocks[i][j], + p_2bit, + p_modulation, + p_modulation_modes, + p_x, p_y); + + p_x += x_block_size; + } + + p_y += BLK_Y_SIZE; + } + + + memcpy(prev, p_blocks, 4*sizeof(void*)); + } + + + interpolate_colors( + colors5554[0][0].Reps[0], + colors5554[0][1].Reps[0], + colors5554[1][0].Reps[0], + colors5554[1][1].Reps[0], + p_2bit, x, y, + ASig); + + interpolate_colors( + colors5554[0][0].Reps[1], + colors5554[0][1].Reps[1], + colors5554[1][0].Reps[1], + colors5554[1][1].Reps[1], + p_2bit, x, y, + BSig); + + get_modulation_value(x,y, p_2bit, (const int (*)[16])p_modulation, (const int (*)[16])p_modulation_modes, + &Mod, &DoPT); + + for(i = 0; i < 4; i++) { + r_result[i] = ASig[i] * 8 + Mod * (BSig[i] - ASig[i]); + r_result[i] >>= 3; + } + + if(DoPT) + r_result[3] = 0; + + + u_pos = (x+y*p_width)<<2; + p_dst[u_pos+0] = (uint8_t)r_result[0]; + p_dst[u_pos+1] = (uint8_t)r_result[1]; + p_dst[u_pos+2] = (uint8_t)r_result[2]; + p_dst[u_pos+3] = (uint8_t)r_result[3]; + } + } +} + +static void _pvrtc_decompress(Image* p_img) { + + /* + static void decompress_pvrtc(const void *p_comp_img, const int p_2bit, const int p_width, const int p_height, unsigned char* p_dst) { + decompress_pvrtc((PVRTCBlock*)p_comp_img,p_2bit,p_width,p_height,1,p_dst); + } + */ + + ERR_FAIL_COND( p_img->get_format()!=Image::FORMAT_PVRTC2 && p_img->get_format()!=Image::FORMAT_PVRTC2A && p_img->get_format()!=Image::FORMAT_PVRTC4 && p_img->get_format()!=Image::FORMAT_PVRTC4A); + + bool _2bit = (p_img->get_format()==Image::FORMAT_PVRTC2 || p_img->get_format()==Image::FORMAT_PVRTC2A ); + + PoolVector<uint8_t> data = p_img->get_data(); + PoolVector<uint8_t>::Read r = data.read(); + + + PoolVector<uint8_t> newdata; + newdata.resize( p_img->get_width() * p_img->get_height() * 4); + PoolVector<uint8_t>::Write w=newdata.write(); + + decompress_pvrtc((PVRTCBlock*)r.ptr(),_2bit,p_img->get_width(),p_img->get_height(),0,(unsigned char*)w.ptr()); + + /* + for(int i=0;i<newdata.size();i++) { + print_line(itos(w[i])); + } + */ + + w=PoolVector<uint8_t>::Write(); + r=PoolVector<uint8_t>::Read(); + + bool make_mipmaps=p_img->has_mipmaps(); + Image newimg(p_img->get_width(),p_img->get_height(),false,Image::FORMAT_RGBA8,newdata); + if (make_mipmaps) + newimg.generate_mipmaps(); + *p_img=newimg; + +} + + + + + + + + diff --git a/modules/pvr/texture_loader_pvr.h b/modules/pvr/texture_loader_pvr.h new file mode 100644 index 0000000000..bad48b4569 --- /dev/null +++ b/modules/pvr/texture_loader_pvr.h @@ -0,0 +1,50 @@ +/*************************************************************************/ +/* texture_loader_pvr.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#ifndef TEXTURE_LOADER_PVR_H +#define TEXTURE_LOADER_PVR_H + + +#include "scene/resources/texture.h" +#include "io/resource_loader.h" + + +class ResourceFormatPVR : public ResourceFormatLoader{ +public: + + virtual RES load(const String &p_path,const String& p_original_path,Error *r_error=NULL); + virtual void get_recognized_extensions(List<String> *p_extensions) const; + virtual bool handles_type(const String& p_type) const; + virtual String get_resource_type(const String &p_path) const; + + ResourceFormatPVR(); + virtual ~ResourceFormatPVR() {} +}; + + +#endif // TEXTURE_LOADER_PVR_H diff --git a/modules/regex/SCsub b/modules/regex/SCsub new file mode 100644 index 0000000000..0882406761 --- /dev/null +++ b/modules/regex/SCsub @@ -0,0 +1,7 @@ +#!/usr/bin/env python + +Import('env') + +env.add_source_files(env.modules_sources, "*.cpp") + +Export('env') diff --git a/modules/regex/config.py b/modules/regex/config.py new file mode 100644 index 0000000000..5347cfd243 --- /dev/null +++ b/modules/regex/config.py @@ -0,0 +1,9 @@ +#!/usr/bin/env python + + +def can_build(platform): + return True + + +def configure(env): + pass diff --git a/modules/regex/regex.cpp b/modules/regex/regex.cpp new file mode 100644 index 0000000000..6d80532110 --- /dev/null +++ b/modules/regex/regex.cpp @@ -0,0 +1,1507 @@ +/*************************************************************************/ +/* regex.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "regex.h" +#include <wctype.h> +#include <wchar.h> + +static int RegEx_hex2int(const CharType c) +{ + if ('0' <= c && c <= '9') + return int(c - '0'); + else if ('a' <= c && c <= 'f') + return int(c - 'a') + 10; + else if ('A' <= c && c <= 'F') + return int(c - 'A') + 10; + return -1; +} + +struct RegExSearch { + + Ref<RegExMatch> match; + const CharType* str; + int end; + int eof; + + // For standard quantifier behaviour, test_parent is used to check the + // rest of the pattern. If the pattern matches, to prevent the parent + // from testing again, the complete flag is used as a shortcut out. + bool complete; + + // With lookahead, the position needs to rewind to its starting position + // when test_parent is used. Due to functional programming, this state + // has to be kept as a parameter. + Vector<int> lookahead_pos; + + CharType at(int p_pos) { + return str[p_pos]; + } + + RegExSearch(Ref<RegExMatch>& p_match, int p_end, int p_lookahead) : match(p_match) { + + str = p_match->string.c_str(); + end = p_end; + eof = p_match->string.length(); + complete = false; + lookahead_pos.resize(p_lookahead); + } + +}; + +struct RegExNode { + + RegExNode* next; + RegExNode* previous; + RegExNode* parent; + bool quantifiable; + int length; + + RegExNode() { + + next = NULL; + previous = NULL; + parent = NULL; + quantifiable = false; + length = -1; + } + + virtual ~RegExNode() { + + if (next) + memdelete(next); + } + + // For avoiding RTTI + virtual bool is_look_behind() { return false; } + + virtual int test(RegExSearch& s, int pos) const { + + return next ? next->test(s, pos) : -1; + } + + virtual int test_parent(RegExSearch& s, int pos) const { + + if (next) + pos = next->test(s, pos); + + if (pos >= 0) { + s.complete = true; + if (parent) + pos = parent->test_parent(s, pos); + } + + if (pos < 0) + s.complete = false; + + return pos; + } + + void increment_length(int amount, bool subtract = false) { + + if (amount >= 0 && length >= 0) { + if (!subtract) + length += amount; + else + length -= amount; + } else { + length = -1; + } + + if (parent) + parent->increment_length(amount, subtract); + + } + +}; + +struct RegExNodeChar : public RegExNode { + + CharType ch; + + RegExNodeChar(CharType p_char) { + + length = 1; + quantifiable = true; + ch = p_char; + } + + virtual int test(RegExSearch& s, int pos) const { + + if (s.end <= pos || 0 > pos || s.at(pos) != ch) + return -1; + + return next ? next->test(s, pos + 1) : pos + 1; + } + + static CharType parse_escape(const CharType*& c) { + + int point = 0; + switch (c[1]) { + case 'x': + for (int i = 2; i <= 3; ++i) { + int res = RegEx_hex2int(c[i]); + if (res == -1) + return '\0'; + point = (point << 4) + res; + } + c = &c[3]; + return CharType(point); + case 'u': + for (int i = 2; i <= 5; ++i) { + int res = RegEx_hex2int(c[i]); + if (res == -1) + return '\0'; + point = (point << 4) + res; + } + c = &c[5]; + return CharType(point); + case '0': ++c; return '\0'; + case 'a': ++c; return '\a'; + case 'e': ++c; return '\e'; + case 'f': ++c; return '\f'; + case 'n': ++c; return '\n'; + case 'r': ++c; return '\r'; + case 't': ++c; return '\t'; + case 'v': ++c; return '\v'; + case 'b': ++c; return '\b'; + default: break; + } + return (++c)[0]; + } +}; + +struct RegExNodeRange : public RegExNode { + + CharType start; + CharType end; + + RegExNodeRange(CharType p_start, CharType p_end) { + + length = 1; + quantifiable = true; + start = p_start; + end = p_end; + } + + virtual int test(RegExSearch& s, int pos) const { + + if (s.end <= pos || 0 > pos) + return -1; + + CharType c = s.at(pos); + if (c < start || end < c) + return -1; + + return next ? next->test(s, pos + 1) : pos + 1; + } +}; + +struct RegExNodeShorthand : public RegExNode { + + CharType repr; + + RegExNodeShorthand(CharType p_repr) { + + length = 1; + quantifiable = true; + repr = p_repr; + } + + virtual int test(RegExSearch& s, int pos) const { + + if (s.end <= pos || 0 > pos) + return -1; + + bool found = false; + bool invert = false; + CharType c = s.at(pos); + switch (repr) { + case '.': + found = true; + break; + case 'W': + invert = true; + case 'w': + found = (c == '_' || iswalnum(c) != 0); + break; + case 'D': + invert = true; + case 'd': + found = ('0' <= c && c <= '9'); + break; + case 'S': + invert = true; + case 's': + found = (iswspace(c) != 0); + break; + default: + break; + } + + if (found == invert) + return -1; + + return next ? next->test(s, pos + 1) : pos + 1; + } +}; + +struct RegExNodeClass : public RegExNode { + + enum Type { + Type_none, + Type_alnum, + Type_alpha, + Type_ascii, + Type_blank, + Type_cntrl, + Type_digit, + Type_graph, + Type_lower, + Type_print, + Type_punct, + Type_space, + Type_upper, + Type_xdigit, + Type_word + }; + + Type type; + + bool test_class(CharType c) const { + + static Vector<CharType> REGEX_NODE_SPACE = String(" \t\r\n\f"); + static Vector<CharType> REGEX_NODE_PUNCT = String("!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"); + + switch (type) { + case Type_alnum: + if ('0' <= c && c <= '9') return true; + if ('a' <= c && c <= 'z') return true; + if ('A' <= c && c <= 'Z') return true; + return false; + case Type_alpha: + if ('a' <= c && c <= 'z') return true; + if ('A' <= c && c <= 'Z') return true; + return false; + case Type_ascii: + return (0x00 <= c && c <= 0x7F); + case Type_blank: + return (c == ' ' || c == '\t'); + case Type_cntrl: + return ((0x00 <= c && c <= 0x1F) || c == 0x7F); + case Type_digit: + return ('0' <= c && c <= '9'); + case Type_graph: + return (0x20 < c && c < 0x7F); + case Type_lower: + return ('a' <= c && c <= 'z'); + case Type_print: + return (0x1F < c && c < 0x1F); + case Type_punct: + return (REGEX_NODE_PUNCT.find(c) >= 0); + case Type_space: + return (REGEX_NODE_SPACE.find(c) >= 0); + case Type_upper: + return ('A' <= c && c <= 'Z'); + case Type_xdigit: + if ('0' <= c && c <= '9') return true; + if ('a' <= c && c <= 'f') return true; + if ('A' <= c && c <= 'F') return true; + return false; + case Type_word: + if ('0' <= c && c <= '9') return true; + if ('a' <= c && c <= 'z') return true; + if ('A' <= c && c <= 'Z') return true; + return (c == '_'); + default: + return false; + } + return false; + } + + RegExNodeClass(Type p_type) { + + length = 1; + quantifiable = true; + type = p_type; + } + + virtual int test(RegExSearch& s, int pos) const { + + if (s.end <= pos || 0 > pos) + return -1; + + if (!test_class(s.at(pos))) + return -1; + + return next ? next->test(s, pos + 1) : pos + 1; + } + +#define REGEX_CMP_CLASS(POS, NAME) if (cmp_class(POS, #NAME)) return Type_ ## NAME + + static Type parse_type(const CharType*& p_pos) { + + REGEX_CMP_CLASS(p_pos, alnum); + REGEX_CMP_CLASS(p_pos, alpha); + REGEX_CMP_CLASS(p_pos, ascii); + REGEX_CMP_CLASS(p_pos, blank); + REGEX_CMP_CLASS(p_pos, cntrl); + REGEX_CMP_CLASS(p_pos, digit); + REGEX_CMP_CLASS(p_pos, graph); + REGEX_CMP_CLASS(p_pos, lower); + REGEX_CMP_CLASS(p_pos, print); + REGEX_CMP_CLASS(p_pos, punct); + REGEX_CMP_CLASS(p_pos, space); + REGEX_CMP_CLASS(p_pos, upper); + REGEX_CMP_CLASS(p_pos, xdigit); + REGEX_CMP_CLASS(p_pos, word); + return Type_none; + } + + static bool cmp_class(const CharType*& p_pos, const char* p_text) { + + unsigned int i = 0; + for (i = 0; p_text[i] != '\0'; ++i) + if (p_pos[i] != p_text[i]) + return false; + + if (p_pos[i++] != ':' || p_pos[i] != ']') + return false; + + p_pos = &p_pos[i]; + return true; + } +}; + +struct RegExNodeAnchorStart : public RegExNode { + + RegExNodeAnchorStart() { + + length = 0; + } + + virtual int test(RegExSearch& s, int pos) const { + + if (pos != 0) + return -1; + + return next ? next->test(s, pos) : pos; + } +}; + +struct RegExNodeAnchorEnd : public RegExNode { + + RegExNodeAnchorEnd() { + + length = 0; + } + + virtual int test(RegExSearch& s, int pos) const { + + if (pos != s.eof) + return -1; + + return next ? next->test(s, pos) : pos; + } +}; + +struct RegExNodeWordBoundary : public RegExNode { + + bool inverse; + + RegExNodeWordBoundary(bool p_inverse) { + + length = 0; + inverse = p_inverse; + } + + virtual int test(RegExSearch& s, int pos) const { + + bool left = false; + bool right = false; + + if (pos != 0) { + CharType c = s.at(pos - 1); + if (c == '_' || iswalnum(c)) + left = true; + } + + if (pos != s.eof) { + CharType c = s.at(pos); + if (c == '_' || iswalnum(c)) + right = true; + } + + if ((left == right) != inverse) + return -1; + + return next ? next->test(s, pos) : pos; + } +}; + +struct RegExNodeQuantifier : public RegExNode { + + int min; + int max; + bool greedy; + RegExNode* child; + + RegExNodeQuantifier(int p_min, int p_max) { + + min = p_min; + max = p_max; + greedy = true; + child = NULL; + } + + ~RegExNodeQuantifier() { + + if (child) + memdelete(child); + } + + virtual int test(RegExSearch& s, int pos) const { + + return test_step(s, pos, 0, pos); + } + + virtual int test_parent(RegExSearch& s, int pos) const { + + s.complete = false; + return pos; + } + + int test_step(RegExSearch& s, int pos, int level, int start) const { + + if (pos > s.end) + return -1; + + if (!greedy && level > min) { + int res = next ? next->test(s, pos) : pos; + if (s.complete) + return res; + + if (res >= 0 && parent->test_parent(s, res) >= 0) + return res; + } + + if (max >= 0 && level > max) + return -1; + + int res = pos; + if (level >= 1) { + if (level > min + 1 && pos == start) + return -1; + + res = child->test(s, pos); + if (s.complete) + return res; + } + + if (res >= 0) { + + int res_step = test_step(s, res, level + 1, start); + if (res_step >= 0) + return res_step; + + if (greedy && level >= min) { + if (next) + res = next->test(s, res); + if (s.complete) + return res; + + if (res >= 0 && parent->test_parent(s, res) >= 0) + return res; + } + } + return -1; + } +}; + +struct RegExNodeBackReference : public RegExNode { + + int id; + + RegExNodeBackReference(int p_id) { + + length = -1; + quantifiable = true; + id = p_id; + } + + virtual int test(RegExSearch& s, int pos) const { + + RegExMatch::Group& ref = s.match->captures[id]; + for (int i = 0; i < ref.length; ++i) { + + if (pos + i >= s.end) + return -1; + + if (s.at(ref.start + i) != s.at(pos + i)) + return -1; + } + return next ? next->test(s, pos + ref.length) : pos + ref.length; + } +}; + + +struct RegExNodeGroup : public RegExNode { + + bool inverse; + bool reset_pos; + Vector<RegExNode*> childset; + RegExNode* back; + + RegExNodeGroup() { + + length = 0; + quantifiable = true; + inverse = false; + reset_pos = false; + back = NULL; + } + + virtual ~RegExNodeGroup() { + + for (int i = 0; i < childset.size(); ++i) + memdelete(childset[i]); + } + + virtual int test(RegExSearch& s, int pos) const { + + for (int i = 0; i < childset.size(); ++i) { + + s.complete = false; + + int res = childset[i]->test(s, pos); + + if (s.complete) + return res; + + if (inverse) { + if (res < 0) + res = pos + 1; + else + return -1; + + if (i + 1 < childset.size()) + continue; + } + + if (res >= 0) { + if (reset_pos) + res = pos; + return next ? next->test(s, res) : res; + } + } + return -1; + } + + void add_child(RegExNode* node) { + + node->parent = this; + node->previous = back; + + if (back) + back->next = node; + else + childset.push_back(node); + + increment_length(node->length); + + back = node; + } + + void add_childset() { + + if (childset.size() > 0) + length = -1; + back = NULL; + } + + RegExNode* swap_back(RegExNode* node) { + + RegExNode* old = back; + + if (old) { + if (!old->previous) + childset.remove(childset.size() - 1); + back = old->previous; + increment_length(old->length, true); + } + + add_child(node); + + return old; + } +}; + +struct RegExNodeCapturing : public RegExNodeGroup { + + int id; + + RegExNodeCapturing(int p_id = 0) { + + id = p_id; + } + + virtual int test(RegExSearch& s, int pos) const { + + RegExMatch::Group& ref = s.match->captures[id]; + int old_start = ref.start; + ref.start = pos; + + int res = RegExNodeGroup::test(s, pos); + + if (res >= 0) { + if (!s.complete) + ref.length = res - pos; + } else { + ref.start = old_start; + } + + return res; + } + + virtual int test_parent(RegExSearch& s, int pos) const { + + RegExMatch::Group& ref = s.match->captures[id]; + ref.length = pos - ref.start; + return RegExNode::test_parent(s, pos); + } + + static Variant parse_name(const CharType*& c, bool p_allow_numeric) { + + if (c[1] == '0') { + return -1; + } else if ('1' <= c[1] && c[1] <= '9') { + if (!p_allow_numeric) + return -1; + int res = (++c)[0] - '0'; + while ('0' <= c[1] && c[1] <= '9') + res = res * 10 + int((++c)[0] - '0'); + if ((++c)[0] != '>') + return -1; + return res; + } else if (iswalnum(c[1])) { + String res(++c, 1); + while (iswalnum(c[1])) + res += String(++c, 1); + if ((++c)[0] != '>') + return -1; + return res; + } + return -1; + } +}; + +struct RegExNodeLookAhead : public RegExNodeGroup { + + int id; + + RegExNodeLookAhead(bool p_inverse, int p_id = 0) { + + quantifiable = false; + inverse = p_inverse; + reset_pos = true; + id = p_id; + } + + virtual int test(RegExSearch& s, int pos) const { + + s.lookahead_pos[id] = pos; + return RegExNodeGroup::test(s, pos); + } + + virtual int test_parent(RegExSearch& s, int pos) const { + + return RegExNode::test_parent(s, s.lookahead_pos[id]); + } +}; + +struct RegExNodeLookBehind : public RegExNodeGroup { + + RegExNodeLookBehind(bool p_inverse, int p_id = 0) { + + quantifiable = false; + inverse = p_inverse; + reset_pos = true; + } + + virtual bool is_look_behind() { return true; } + + virtual int test(RegExSearch& s, int pos) const { + + if (pos < length) + return -1; + return RegExNodeGroup::test(s, pos - length); + } +}; + +struct RegExNodeBracket : public RegExNode { + + bool inverse; + Vector<RegExNode*> children; + + RegExNodeBracket() { + + length = 1; + quantifiable = true; + inverse = false; + } + + virtual ~RegExNodeBracket() { + + for (int i = 0; i < children.size(); ++i) + memdelete(children[i]); + } + + virtual int test(RegExSearch& s, int pos) const { + + for (int i = 0; i < children.size(); ++i) { + + int res = children[i]->test(s, pos); + + if (inverse) { + if (res < 0) + res = pos + 1; + else + return -1; + + if (i + 1 < children.size()) + continue; + } + + if (res >= 0) + return next ? next->test(s, res) : res; + } + return -1; + } + + void add_child(RegExNode* node) { + + node->parent = this; + children.push_back(node); + } + + void pop_back() { + + memdelete(children[children.size() - 1]); + children.remove(children.size() - 1); + } +}; + +#define REGEX_EXPAND_FAIL(MSG)\ +{\ + ERR_PRINT(MSG);\ + return String();\ +} + +String RegExMatch::expand(const String& p_template) const { + + String res; + for (const CharType* c = p_template.c_str(); *c != '\0'; ++c) { + if (c[0] == '\\') { + if (('1' <= c[1] && c[1] <= '9') || (c[1] == 'g' && c[2] == '{')) { + + int ref = 0; + bool unclosed = false; + + if (c[1] == 'g') { + unclosed = true; + c = &c[2]; + } + + while ('0' <= c[1] && c[1] <= '9') { + ref = ref * 10 + int(c[1] - '0'); + ++c; + } + + if (unclosed) { + if (c[1] != '}') + REGEX_EXPAND_FAIL("unclosed backreference '{'"); + ++c; + } + + res += get_string(ref); + + } else if (c[1] =='g' && c[2] == '<') { + + const CharType* d = &c[2]; + + Variant name = RegExNodeCapturing::parse_name(d, true); + if (name == Variant(-1)) + REGEX_EXPAND_FAIL("unrecognised character for group name"); + + c = d; + + res += get_string(name); + + } else { + + const CharType* d = c; + CharType ch = RegExNodeChar::parse_escape(d); + if (c == d) + REGEX_EXPAND_FAIL("invalid escape token"); + res += String(&ch, 1); + c = d; + } + } else { + res += String(c, 1); + } + } + return res; +} + +int RegExMatch::get_group_count() const { + + int count = 0; + for (int i = 1; i < captures.size(); ++i) + if (captures[i].name.get_type() == Variant::INT) + ++count; + return count; +} + +Array RegExMatch::get_group_array() const { + + Array res; + for (int i = 1; i < captures.size(); ++i) { + const RegExMatch::Group& capture = captures[i]; + if (capture.name.get_type() != Variant::INT) + continue; + + if (capture.start >= 0) + res.push_back(string.substr(capture.start, capture.length)); + else + res.push_back(String()); + } + return res; +} + +Array RegExMatch::get_names() const { + + Array res; + for (int i = 1; i < captures.size(); ++i) + if (captures[i].name.get_type() == Variant::STRING) + res.push_back(captures[i].name); + return res; +} + +Dictionary RegExMatch::get_name_dict() const { + + Dictionary res; + for (int i = 1; i < captures.size(); ++i) { + const RegExMatch::Group& capture = captures[i]; + if (capture.name.get_type() != Variant::STRING) + continue; + + if (capture.start >= 0) + res[capture.name] = string.substr(capture.start, capture.length); + else + res[capture.name] = String(); + } + return res; +} + +String RegExMatch::get_string(const Variant& p_name) const { + + for (int i = 0; i < captures.size(); ++i) { + + const RegExMatch::Group& capture = captures[i]; + + if (capture.name != p_name) + continue; + + if (capture.start == -1) + return String(); + + return string.substr(capture.start, capture.length); + } + return String(); +} + +int RegExMatch::get_start(const Variant& p_name) const { + + for (int i = 0; i < captures.size(); ++i) + if (captures[i].name == p_name) + return captures[i].start; + return -1; +} + +int RegExMatch::get_end(const Variant& p_name) const { + + for (int i = 0; i < captures.size(); ++i) + if (captures[i].name == p_name) + return captures[i].start + captures[i].length; + return -1; +} + +RegExMatch::RegExMatch() { + +} + +static bool RegEx_is_shorthand(CharType ch) { + + switch (ch) { + case 'w': + case 'W': + case 'd': + case 'D': + case 's': + case 'S': + return true; + default: + break; + } + return false; +} + +#define REGEX_COMPILE_FAIL(MSG)\ +{\ + ERR_PRINT(MSG);\ + clear();\ + return FAILED;\ +} + +Error RegEx::compile(const String& p_pattern) { + + ERR_FAIL_COND_V(p_pattern.length() == 0, FAILED); + + if (pattern == p_pattern && root) + return OK; + + clear(); + pattern = p_pattern; + group_names.push_back(0); + RegExNodeGroup* root_group = memnew(RegExNodeCapturing(0)); + root = root_group; + Vector<RegExNodeGroup*> stack; + stack.push_back(root_group); + int lookahead_level = 0; + int numeric_groups = 0; + const int numeric_max = 9; + + for (const CharType* c = p_pattern.c_str(); *c != '\0'; ++c) { + + switch (c[0]) { + case '(': + if (c[1] == '?') { + + RegExNodeGroup* group = NULL; + switch (c[2]) { + case ':': + c = &c[2]; + group = memnew(RegExNodeGroup()); + break; + case '!': + case '=': + group = memnew(RegExNodeLookAhead((c[2] == '!'), lookahead_level++)); + if (lookahead_depth < lookahead_level) + lookahead_depth = lookahead_level; + c = &c[2]; + break; + case '<': + if (c[3] == '!' || c[3] == '=') { + group = memnew(RegExNodeLookBehind((c[3] == '!'), lookahead_level++)); + c = &c[3]; + } + break; + case 'P': + if (c[3] == '<') { + const CharType* d = &c[3]; + Variant name = RegExNodeCapturing::parse_name(d, false); + if (name == Variant(-1)) + REGEX_COMPILE_FAIL("unrecognised character for group name"); + group = memnew(RegExNodeCapturing(group_names.size())); + group_names.push_back(name); + c = d; + } + default: + break; + } + if (!group) + REGEX_COMPILE_FAIL("unrecognised qualifier for group"); + stack[0]->add_child(group); + stack.insert(0, group); + + } else if (numeric_groups < numeric_max) { + + RegExNodeCapturing* group = memnew(RegExNodeCapturing(group_names.size())); + group_names.push_back(++numeric_groups); + stack[0]->add_child(group); + stack.insert(0, group); + + } else { + + RegExNodeGroup* group = memnew(RegExNodeGroup()); + stack[0]->add_child(group); + stack.insert(0, group); + } + break; + case ')': + if (stack.size() == 1) + REGEX_COMPILE_FAIL("unexpected ')'"); + stack.remove(0); + break; + case '\\': + if (('1' <= c[1] && c[1] <= '9') || (c[1] == 'g' && c[2] == '{')) { + + int ref = 0; + bool unclosed = false; + + if (c[1] == 'g') { + unclosed = true; + c = &c[2]; + } + + while ('0' <= c[1] && c[1] <= '9') { + ref = ref * 10 + int(c[1] - '0'); + ++c; + } + + if (unclosed) { + if (c[1] != '}') + REGEX_COMPILE_FAIL("unclosed backreference '{'"); + ++c; + } + + if (ref > numeric_groups || ref <= 0) + REGEX_COMPILE_FAIL("backreference not found"); + + for (int i = 0; i < stack.size(); ++i) + if (stack[i]->is_look_behind()) + REGEX_COMPILE_FAIL("backreferences inside lookbehind not supported"); + + for (int i = 0; i < group_names.size(); ++i) { + if (group_names[i].get_type() == Variant::INT && int(group_names[i]) == ref) { + ref = group_names[i]; + break; + } + } + + stack[0]->add_child(memnew(RegExNodeBackReference(ref))); + + } if (c[1] =='g' && c[2] == '<') { + + const CharType* d = &c[2]; + + Variant name = RegExNodeCapturing::parse_name(d, true); + if (name == Variant(-1)) + REGEX_COMPILE_FAIL("unrecognised character for group name"); + + c = d; + + for (int i = 0; i < stack.size(); ++i) + if (stack[i]->is_look_behind()) + REGEX_COMPILE_FAIL("backreferences inside lookbehind not supported"); + + int ref = -1; + + for (int i = 0; i < group_names.size(); ++i) { + if (group_names[i].get_type() == Variant::INT && int(group_names[i]) == ref) { + ref = group_names[i]; + break; + } + } + + if (ref == -1) + REGEX_COMPILE_FAIL("backreference not found"); + + stack[0]->add_child(memnew(RegExNodeBackReference(ref))); + + } else if (c[1] == 'b' || c[1] == 'B') { + + stack[0]->add_child(memnew(RegExNodeWordBoundary(*(++c) == 'B'))); + + } else if (RegEx_is_shorthand(c[1])) { + + stack[0]->add_child(memnew(RegExNodeShorthand(*(++c)))); + + } else { + + const CharType* d = c; + CharType ch = RegExNodeChar::parse_escape(d); + if (c == d) + REGEX_COMPILE_FAIL("invalid escape token"); + stack[0]->add_child(memnew(RegExNodeChar(ch))); + c = d; + + } + break; + case '[': + { + RegExNodeBracket* bracket = memnew(RegExNodeBracket()); + stack[0]->add_child(bracket); + if (c[1] == '^') { + bracket->inverse = true; + ++c; + } + bool first_child = true; + CharType previous_child; + bool previous_child_single = false; + while (true) { + ++c; + if (!first_child && c[0] == ']') { + + break; + + } else if (c[0] == '\0') { + + REGEX_COMPILE_FAIL("unclosed bracket expression '['"); + + } else if (c[0] == '\\') { + + if (RegEx_is_shorthand(c[1])) { + bracket->add_child(memnew(RegExNodeShorthand(*(++c)))); + } else { + const CharType* d = c; + CharType ch = RegExNodeChar::parse_escape(d); + if (c == d) + REGEX_COMPILE_FAIL("invalid escape token"); + bracket->add_child(memnew(RegExNodeChar(ch))); + c = d; + previous_child = ch; + previous_child_single = true; + } + + } else if (c[0] == ']' && c[1] == ':') { + + const CharType* d = &c[2]; + RegExNodeClass::Type type = RegExNodeClass::parse_type(d); + if (type != RegExNodeClass::Type_none) { + + c = d; + previous_child_single = false; + + } else { + + bracket->add_child(memnew(RegExNodeChar('['))); + previous_child = '['; + previous_child_single = true; + } + } else if (previous_child_single && c[0] == '-') { + + if (c[1] != '\0' && c[1] != ']') { + + CharType next; + + if (c[1] == '\\') { + const CharType* d = ++c; + next = RegExNodeChar::parse_escape(d); + if (c == d) + REGEX_COMPILE_FAIL("invalid escape token"); + } else { + next = *(++c); + } + + if (next < previous_child) + REGEX_COMPILE_FAIL("text range out of order"); + + bracket->pop_back(); + bracket->add_child(memnew(RegExNodeRange(previous_child, next))); + previous_child_single = false; + } else { + + bracket->add_child(memnew(RegExNodeChar('-'))); + previous_child = '-'; + previous_child_single = true; + } + } else { + + bracket->add_child(memnew(RegExNodeChar(c[0]))); + previous_child = c[0]; + previous_child_single = true; + } + first_child = false; + } + } + break; + case '|': + for (int i = 0; i < stack.size(); ++i) + if (stack[i]->is_look_behind()) + REGEX_COMPILE_FAIL("alternations inside lookbehind not supported"); + stack[0]->add_childset(); + break; + case '^': + stack[0]->add_child(memnew(RegExNodeAnchorStart())); + break; + case '$': + stack[0]->add_child(memnew(RegExNodeAnchorEnd())); + break; + case '.': + stack[0]->add_child(memnew(RegExNodeShorthand('.'))); + break; + case '?': + case '*': + case '+': + case '{': + { + int min_val = 0; + int max_val = -1; + bool valid = true; + const CharType* d = c; + bool max_set = true; + switch (c[0]) { + case '?': + min_val = 0; + max_val = 1; + break; + case '*': + min_val = 0; + max_val = -1; + break; + case '+': + min_val = 1; + max_val = -1; + break; + case '{': + max_set = false; + while (valid) { + ++d; + if (d[0] == '}') { + break; + } else if (d[0] == ',') { + max_set = true; + } else if ('0' <= d[0] && d[0] <= '9') { + if (max_set) { + if (max_val < 0) + max_val = int(d[0] - '0'); + else + max_val = max_val * 10 + int(d[0] - '0'); + } else { + min_val = min_val * 10 + int(d[0] - '0'); + } + } else { + valid = false; + } + } + break; + default: + break; + } + + if (!max_set) + max_val = min_val; + + if (valid) { + + c = d; + + if (stack[0]->back == NULL || !stack[0]->back->quantifiable) + REGEX_COMPILE_FAIL("element not quantifiable"); + + if (min_val != max_val) + for (int i = 0; i < stack.size(); ++i) + if (stack[i]->is_look_behind()) + REGEX_COMPILE_FAIL("variable length quantifiers inside lookbehind not supported"); + + RegExNodeQuantifier* quant = memnew(RegExNodeQuantifier(min_val, max_val)); + quant->child = stack[0]->swap_back(quant); + quant->child->previous = NULL; + quant->child->parent = quant; + + if (min_val == max_val && quant->child->length >= 0) + quant->length = max_val * quant->child->length; + + if (c[1] == '?') { + quant->greedy = false; + ++c; + } + break; + } + } + default: + stack[0]->add_child(memnew(RegExNodeChar(c[0]))); + break; + } + } + if (stack.size() > 1) + REGEX_COMPILE_FAIL("unclosed group '('"); + return OK; +} + +Ref<RegExMatch> RegEx::search(const String& p_text, int p_start, int p_end) const { + + ERR_FAIL_COND_V(!is_valid(), NULL); + ERR_FAIL_COND_V(p_start < 0, NULL); + ERR_FAIL_COND_V(p_start >= p_text.length(), NULL); + ERR_FAIL_COND_V(p_end > p_text.length(), NULL); + ERR_FAIL_COND_V(p_end != -1 && p_end < p_start, NULL); + + Ref<RegExMatch> res = memnew(RegExMatch()); + + for (int i = 0; i < group_names.size(); ++i) { + RegExMatch::Group group; + group.name = group_names[i]; + res->captures.push_back(group); + } + + res->string = p_text; + + if (p_end == -1) + p_end = p_text.length(); + + RegExSearch s(res, p_end, lookahead_depth); + + for (int i = p_start; i <= s.end; ++i) { + for (int c = 0; c < group_names.size(); ++c) { + res->captures[c].start = -1; + res->captures[c].length = 0; + } + if (root->test(s, i) >= 0) + break; + } + + if (res->captures[0].start >= 0) + return res; + return NULL; +} + +String RegEx::sub(const String& p_text, const String& p_replacement, bool p_all, int p_start, int p_end) const { + + ERR_FAIL_COND_V(!is_valid(), p_text); + ERR_FAIL_COND_V(p_start < 0, p_text); + ERR_FAIL_COND_V(p_start >= p_text.length(), p_text); + ERR_FAIL_COND_V(p_end > p_text.length(), p_text); + ERR_FAIL_COND_V(p_end != -1 && p_end < p_start, p_text); + + String text = p_text; + int start = p_start; + + if (p_end == -1) + p_end = p_text.length(); + + while (start < text.length() && (p_all || start == p_start)) { + + Ref<RegExMatch> m = search(text, start, p_end); + + RegExMatch::Group& s = m->captures[0]; + + if (s.start < 0) + break; + + String res = text.substr(0, s.start) + m->expand(p_replacement); + + start = res.length(); + + if (s.length == 0) + ++start; + + int sub_end = s.start + s.length; + if (sub_end < text.length()) + res += text.substr(sub_end, text.length() - sub_end); + + p_end += res.length() - text.length(); + + text = res; + } + return text; +} + +void RegEx::clear() { + + if (root) + memdelete(root); + + root = NULL; + group_names.clear(); + lookahead_depth = 0; +} + +bool RegEx::is_valid() const { + + return (root != NULL); +} + +String RegEx::get_pattern() const { + + return pattern; +} + +int RegEx::get_group_count() const { + + int count = 0; + for (int i = 1; i < group_names.size(); ++i) + if (group_names[i].get_type() == Variant::INT) + ++count; + return count; +} + +Array RegEx::get_names() const { + + Array res; + for (int i = 1; i < group_names.size(); ++i) + if (group_names[i].get_type() == Variant::STRING) + res.push_back(group_names[i]); + return res; +} + +RegEx::RegEx() { + + root = NULL; + lookahead_depth = 0; +} + +RegEx::RegEx(const String& p_pattern) { + + root = NULL; + compile(p_pattern); +} + +RegEx::~RegEx() { + + if (root) + memdelete(root); +} + +void RegExMatch::_bind_methods() { + + ClassDB::bind_method(D_METHOD("expand","template"),&RegExMatch::expand); + ClassDB::bind_method(D_METHOD("get_group_count"),&RegExMatch::get_group_count); + ClassDB::bind_method(D_METHOD("get_group_array"),&RegExMatch::get_group_array); + ClassDB::bind_method(D_METHOD("get_names"),&RegExMatch::get_names); + ClassDB::bind_method(D_METHOD("get_name_dict"),&RegExMatch::get_name_dict); + ClassDB::bind_method(D_METHOD("get_string","name"),&RegExMatch::get_string, DEFVAL(0)); + ClassDB::bind_method(D_METHOD("get_start","name"),&RegExMatch::get_start, DEFVAL(0)); + ClassDB::bind_method(D_METHOD("get_end","name"),&RegExMatch::get_end, DEFVAL(0)); +} + +void RegEx::_bind_methods() { + + ClassDB::bind_method(D_METHOD("clear"),&RegEx::clear); + ClassDB::bind_method(D_METHOD("compile","pattern"),&RegEx::compile); + ClassDB::bind_method(D_METHOD("search","text","start","end"),&RegEx::search, DEFVAL(0), DEFVAL(-1)); + ClassDB::bind_method(D_METHOD("sub","text","replacement","all","start","end"),&RegEx::sub, DEFVAL(false), DEFVAL(0), DEFVAL(-1)); + ClassDB::bind_method(D_METHOD("is_valid"),&RegEx::is_valid); + ClassDB::bind_method(D_METHOD("get_pattern"),&RegEx::get_pattern); + ClassDB::bind_method(D_METHOD("get_group_count"),&RegEx::get_group_count); + ClassDB::bind_method(D_METHOD("get_names"),&RegEx::get_names); + + ADD_PROPERTY(PropertyInfo(Variant::STRING, "pattern"), "compile", "get_pattern"); +} + diff --git a/modules/regex/regex.h b/modules/regex/regex.h new file mode 100644 index 0000000000..193d818da3 --- /dev/null +++ b/modules/regex/regex.h @@ -0,0 +1,114 @@ +/*************************************************************************/ +/* regex.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef REGEX_H +#define REGEX_H + +#include "core/vector.h" +#include "core/ustring.h" +#include "core/dictionary.h" +#include "core/reference.h" +#include "core/resource.h" + +class RegExNode; + +class RegExMatch : public Reference { + + GDCLASS(RegExMatch, Reference); + + struct Group { + Variant name; + int start; + int length; + }; + + Vector<Group> captures; + String string; + + friend class RegEx; + friend class RegExSearch; + friend class RegExNodeCapturing; + friend class RegExNodeBackReference; + +protected: + + static void _bind_methods(); + +public: + + String expand(const String& p_template) const; + + int get_group_count() const; + Array get_group_array() const; + + Array get_names() const; + Dictionary get_name_dict() const; + + String get_string(const Variant& p_name) const; + int get_start(const Variant& p_name) const; + int get_end(const Variant& p_name) const; + + RegExMatch(); + +}; + +class RegEx : public Resource { + + GDCLASS(RegEx, Resource); + + RegExNode* root; + Vector<Variant> group_names; + String pattern; + int lookahead_depth; + +protected: + + static void _bind_methods(); + +public: + + void clear(); + Error compile(const String& p_pattern); + + Ref<RegExMatch> search(const String& p_text, int p_start = 0, int p_end = -1) const; + String sub(const String& p_text, const String& p_replacement, bool p_all = false, int p_start = 0, int p_end = -1) const; + + bool is_valid() const; + String get_pattern() const; + int get_group_count() const; + Array get_names() const; + + RegEx(); + RegEx(const String& p_pattern); + ~RegEx(); + +}; + +#endif // REGEX_H + diff --git a/modules/regex/register_types.cpp b/modules/regex/register_types.cpp new file mode 100644 index 0000000000..c62a04d80f --- /dev/null +++ b/modules/regex/register_types.cpp @@ -0,0 +1,43 @@ +/*************************************************************************/ +/* register_types.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "register_types.h" +#include "class_db.h" +#include "regex.h" + +void register_regex_types() { + + ClassDB::register_class<RegExMatch>(); + ClassDB::register_class<RegEx>(); +} + +void unregister_regex_types() { + +} + diff --git a/modules/regex/register_types.h b/modules/regex/register_types.h new file mode 100644 index 0000000000..5d676b6daa --- /dev/null +++ b/modules/regex/register_types.h @@ -0,0 +1,31 @@ +/*************************************************************************/ +/* register_types.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +void register_regex_types(); +void unregister_regex_types(); diff --git a/modules/register_module_types.h b/modules/register_module_types.h index 683ce7c6b8..7d9a130ea1 100644 --- a/modules/register_module_types.h +++ b/modules/register_module_types.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/modules/squish/SCsub b/modules/squish/SCsub new file mode 100644 index 0000000000..cca7c038f1 --- /dev/null +++ b/modules/squish/SCsub @@ -0,0 +1,29 @@ +#!/usr/bin/env python + +Import('env') +Import('env_modules') + +env_squish = env_modules.Clone() + +# Thirdparty source files +if (env['builtin_squish'] != 'no'): + thirdparty_dir = "#thirdparty/squish/" + thirdparty_sources = [ + "alpha.cpp", + "clusterfit.cpp", + "colourblock.cpp", + "colourfit.cpp", + "colourset.cpp", + "maths.cpp", + "rangefit.cpp", + "singlecolourfit.cpp", + "squish.cpp", + ] + + thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] + + env_squish.add_source_files(env.modules_sources, thirdparty_sources) + env_squish.Append(CPPPATH=[thirdparty_dir]) + +# Godot source files +env_squish.add_source_files(env.modules_sources, "*.cpp") diff --git a/modules/squish/config.py b/modules/squish/config.py new file mode 100644 index 0000000000..cc8f098010 --- /dev/null +++ b/modules/squish/config.py @@ -0,0 +1,11 @@ + +def can_build(platform): + return True + + +def configure(env): + # Tools only, disabled for non-tools + # TODO: Find a cleaner way to achieve that + if (env["tools"] == "no"): + env["module_squish_enabled"] = "no" + env.disabled_modules.append("squish") diff --git a/modules/squish/image_compress_squish.cpp b/modules/squish/image_compress_squish.cpp new file mode 100644 index 0000000000..28c200596b --- /dev/null +++ b/modules/squish/image_compress_squish.cpp @@ -0,0 +1,91 @@ +/*************************************************************************/ +/* image_compress_squish.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#include "image_compress_squish.h" + +#include "print_string.h" + +#include <squish.h> + +void image_compress_squish(Image *p_image) { + + int w=p_image->get_width(); + int h=p_image->get_height(); + + if (!p_image->has_mipmaps() ) { + ERR_FAIL_COND( !w || w % 4 != 0); + ERR_FAIL_COND( !h || h % 4 != 0); + } else { + ERR_FAIL_COND( !w || w !=nearest_power_of_2(w) ); + ERR_FAIL_COND( !h || h !=nearest_power_of_2(h) ); + }; + + if (p_image->get_format()>=Image::FORMAT_DXT1) + return; //do not compress, already compressed + + int shift=0; + int squish_comp=squish::kColourRangeFit; + Image::Format target_format; + + if (p_image->get_format()==Image::FORMAT_LA8) { + //compressed normalmap + target_format = Image::FORMAT_DXT5; squish_comp|=squish::kDxt5; + } else if (p_image->detect_alpha()!=Image::ALPHA_NONE) { + + target_format = Image::FORMAT_DXT3; squish_comp|=squish::kDxt3; + } else { + target_format = Image::FORMAT_DXT1; shift=1; squish_comp|=squish::kDxt1; + } + + p_image->convert(Image::FORMAT_RGBA8); //always expects rgba + + PoolVector<uint8_t> data; + int target_size = Image::get_image_data_size(w,h,target_format,p_image->has_mipmaps()?-1:0); + int mm_count = p_image->has_mipmaps() ? Image::get_image_required_mipmaps(w,h,target_format) : 0; + data.resize(target_size); + + PoolVector<uint8_t>::Read rb = p_image->get_data().read(); + PoolVector<uint8_t>::Write wb = data.write(); + + int dst_ofs=0; + + for(int i=0;i<=mm_count;i++) { + + int src_ofs = p_image->get_mipmap_offset(i); + squish::CompressImage( &rb[src_ofs],w,h,&wb[dst_ofs],squish_comp); + dst_ofs+=(MAX(4,w)*MAX(4,h))>>shift; + w>>=1; + h>>=1; + } + + rb = PoolVector<uint8_t>::Read(); + wb = PoolVector<uint8_t>::Write(); + + p_image->create(p_image->get_width(),p_image->get_height(),p_image->has_mipmaps(),target_format,data); + +} diff --git a/modules/squish/image_compress_squish.h b/modules/squish/image_compress_squish.h new file mode 100644 index 0000000000..198889402a --- /dev/null +++ b/modules/squish/image_compress_squish.h @@ -0,0 +1,36 @@ +/*************************************************************************/ +/* image_compress_squish.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#ifndef IMAGE_COMPRESS_SQUISH_H +#define IMAGE_COMPRESS_SQUISH_H + +#include "image.h" + +void image_compress_squish(Image *p_image); + +#endif // IMAGE_COMPRESS_SQUISH_H diff --git a/modules/ik/register_types.cpp b/modules/squish/register_types.cpp index e7df7f55b2..995711c758 100644 --- a/modules/ik/register_types.cpp +++ b/modules/squish/register_types.cpp @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -27,21 +27,16 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "register_types.h" -#ifndef _3D_DISABLED -#include "object_type_db.h" -#include "ik.h" -#endif - -void register_ik_types() { -#ifndef _3D_DISABLED - ObjectTypeDB::register_type<InverseKinematics>(); -#endif -} +#ifdef TOOLS_ENABLED +#include "image_compress_squish.h" +void register_squish_types() { -void unregister_ik_types() { + Image::set_compress_bc_func(image_compress_squish); +} +void unregister_squish_types() {} -} +#endif diff --git a/modules/squish/register_types.h b/modules/squish/register_types.h new file mode 100644 index 0000000000..0db4301997 --- /dev/null +++ b/modules/squish/register_types.h @@ -0,0 +1,32 @@ +/*************************************************************************/ +/* register_types.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#ifdef TOOLS_ENABLED +void register_squish_types(); +void unregister_squish_types(); +#endif diff --git a/modules/stb_vorbis/SCsub b/modules/stb_vorbis/SCsub new file mode 100644 index 0000000000..897d05961c --- /dev/null +++ b/modules/stb_vorbis/SCsub @@ -0,0 +1,10 @@ +#!/usr/bin/env python + +Import('env') +Import('env_modules') + +# Thirdparty source files + +env_stb_vorbis = env_modules.Clone() + +env_stb_vorbis.add_source_files(env.modules_sources, "*.cpp") diff --git a/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp b/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp new file mode 100644 index 0000000000..ee7cbeece9 --- /dev/null +++ b/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp @@ -0,0 +1,232 @@ + +#include "audio_stream_ogg_vorbis.h" +#include "thirdparty/stb_vorbis/stb_vorbis.c" +#include "os/file_access.h" + + +void AudioStreamPlaybackOGGVorbis::_mix_internal(AudioFrame* p_buffer,int p_frames) { + + ERR_FAIL_COND(!active); + + int todo=p_frames; + + while(todo) { + + int mixed = stb_vorbis_get_samples_float_interleaved(ogg_stream,2,(float*)p_buffer,todo*2); + todo-=mixed; + + if (todo) { + //end of file! + if (vorbis_stream->loop) { + //loop + seek_pos(0); + loops++; + } else { + for(int i=mixed;i<p_frames;i++) { + p_buffer[i]=AudioFrame(0,0); + } + active=false; + } + } + } + + +} + +float AudioStreamPlaybackOGGVorbis::get_stream_sampling_rate() { + + return vorbis_stream->sample_rate; +} + + +void AudioStreamPlaybackOGGVorbis::start(float p_from_pos) { + + seek_pos(p_from_pos); + active=true; + loops=0; + _begin_resample(); + + +} + +void AudioStreamPlaybackOGGVorbis::stop() { + + active=false; +} +bool AudioStreamPlaybackOGGVorbis::is_playing() const { + + return active; +} + +int AudioStreamPlaybackOGGVorbis::get_loop_count() const { + + return loops; +} + +float AudioStreamPlaybackOGGVorbis::get_pos() const { + + return float(frames_mixed)/vorbis_stream->sample_rate; +} +void AudioStreamPlaybackOGGVorbis::seek_pos(float p_time) { + + if (!active) + return; + + stb_vorbis_seek(ogg_stream, uint32_t(p_time*vorbis_stream->sample_rate)); +} + +float AudioStreamPlaybackOGGVorbis::get_length() const { + + return vorbis_stream->length; +} + +AudioStreamPlaybackOGGVorbis::~AudioStreamPlaybackOGGVorbis() { + if (ogg_alloc.alloc_buffer) { + AudioServer::get_singleton()->audio_data_free(ogg_alloc.alloc_buffer); + stb_vorbis_close(ogg_stream); + } +} + +Ref<AudioStreamPlayback> AudioStreamOGGVorbis::instance_playback() { + + + + Ref<AudioStreamPlaybackOGGVorbis> ovs; + printf("instance at %p, data %p\n",this,data); + + ERR_FAIL_COND_V(data==NULL,ovs); + + ovs.instance(); + ovs->vorbis_stream=Ref<AudioStreamOGGVorbis>(this); + ovs->ogg_alloc.alloc_buffer=(char*)AudioServer::get_singleton()->audio_data_alloc(decode_mem_size); + ovs->ogg_alloc.alloc_buffer_length_in_bytes=decode_mem_size; + ovs->frames_mixed=0; + ovs->active=false; + ovs->loops=0; + int error ; + ovs->ogg_stream = stb_vorbis_open_memory( (const unsigned char*)data, data_len, &error, &ovs->ogg_alloc ); + if (!ovs->ogg_stream) { + + AudioServer::get_singleton()->audio_data_free(ovs->ogg_alloc.alloc_buffer); + ovs->ogg_alloc.alloc_buffer=NULL; + ERR_FAIL_COND_V(!ovs->ogg_stream,Ref<AudioStreamPlaybackOGGVorbis>()); + } + + return ovs; +} + +String AudioStreamOGGVorbis::get_stream_name() const { + + return "";//return stream_name; +} + +void AudioStreamOGGVorbis::set_data(const PoolVector<uint8_t>& p_data) { + + int src_data_len=p_data.size(); +#define MAX_TEST_MEM (1<<20) + + uint32_t alloc_try=1024; + PoolVector<char> alloc_mem; + PoolVector<char>::Write w; + stb_vorbis * ogg_stream=NULL; + stb_vorbis_alloc ogg_alloc; + + while(alloc_try<MAX_TEST_MEM) { + + alloc_mem.resize(alloc_try); + w = alloc_mem.write(); + + ogg_alloc.alloc_buffer=w.ptr(); + ogg_alloc.alloc_buffer_length_in_bytes=alloc_try; + + PoolVector<uint8_t>::Read src_datar = p_data.read(); + + int error; + ogg_stream = stb_vorbis_open_memory( (const unsigned char*)src_datar.ptr(), src_data_len, &error, &ogg_alloc ); + + if (!ogg_stream && error==VORBIS_outofmem) { + w = PoolVector<char>::Write(); + alloc_try*=2; + } else { + + ERR_FAIL_COND(alloc_try==MAX_TEST_MEM); + ERR_FAIL_COND(ogg_stream==NULL); + + stb_vorbis_info info = stb_vorbis_get_info(ogg_stream); + + channels = info.channels; + sample_rate = info.sample_rate; + decode_mem_size = alloc_try; + //does this work? (it's less mem..) + //decode_mem_size = ogg_alloc.alloc_buffer_length_in_bytes + info.setup_memory_required + info.temp_memory_required + info.max_frame_size; + + //print_line("succeded "+itos(ogg_alloc.alloc_buffer_length_in_bytes)+" setup "+itos(info.setup_memory_required)+" setup temp "+itos(info.setup_temp_memory_required)+" temp "+itos(info.temp_memory_required)+" maxframe"+itos(info.max_frame_size)); + + length=stb_vorbis_stream_length_in_seconds(ogg_stream); + stb_vorbis_close(ogg_stream); + + data = AudioServer::get_singleton()->audio_data_alloc(src_data_len,src_datar.ptr()); + data_len=src_data_len; + + break; + } + } + + + printf("create at %p, data %p\n",this,data); + +} + +PoolVector<uint8_t> AudioStreamOGGVorbis::get_data() const { + + PoolVector<uint8_t> vdata; + + if (data_len && data) { + vdata.resize(data_len); + { + PoolVector<uint8_t>::Write w = vdata.write(); + copymem(w.ptr(),data,data_len); + } + + } + + return vdata; +} + +void AudioStreamOGGVorbis::set_loop(bool p_enable) { + loop=p_enable; +} + +bool AudioStreamOGGVorbis::has_loop() const { + + return loop; +} + + +void AudioStreamOGGVorbis::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_data","data"),&AudioStreamOGGVorbis::set_data); + ClassDB::bind_method(D_METHOD("get_data"),&AudioStreamOGGVorbis::get_data); + + ClassDB::bind_method(D_METHOD("set_loop","enable"),&AudioStreamOGGVorbis::set_loop); + ClassDB::bind_method(D_METHOD("has_loop"),&AudioStreamOGGVorbis::has_loop); + + ADD_PROPERTY(PropertyInfo(Variant::POOL_BYTE_ARRAY,"data",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),"set_data","get_data"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL,"loop",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),"set_loop","has_loop"); + +} + +AudioStreamOGGVorbis::AudioStreamOGGVorbis() { + + + data=NULL; + length=0; + sample_rate=1; + channels=1; + decode_mem_size=0; + loop=false; +} + + + + diff --git a/modules/stb_vorbis/audio_stream_ogg_vorbis.h b/modules/stb_vorbis/audio_stream_ogg_vorbis.h new file mode 100644 index 0000000000..21ce23740c --- /dev/null +++ b/modules/stb_vorbis/audio_stream_ogg_vorbis.h @@ -0,0 +1,83 @@ +#ifndef AUDIO_STREAM_STB_VORBIS_H +#define AUDIO_STREAM_STB_VORBIS_H + +#include "servers/audio/audio_stream.h" +#include "io/resource_loader.h" + +#define STB_VORBIS_HEADER_ONLY +#include "thirdparty/stb_vorbis/stb_vorbis.c" +#undef STB_VORBIS_HEADER_ONLY + + +class AudioStreamOGGVorbis; + +class AudioStreamPlaybackOGGVorbis : public AudioStreamPlaybackResampled { + + GDCLASS( AudioStreamPlaybackOGGVorbis, AudioStreamPlaybackResampled ) + + stb_vorbis * ogg_stream; + stb_vorbis_alloc ogg_alloc; + uint32_t frames_mixed; + bool active; + int loops; + +friend class AudioStreamOGGVorbis; + + Ref<AudioStreamOGGVorbis> vorbis_stream; +protected: + + virtual void _mix_internal(AudioFrame* p_buffer, int p_frames); + virtual float get_stream_sampling_rate(); + +public: + virtual void start(float p_from_pos=0.0); + virtual void stop(); + virtual bool is_playing() const; + + virtual int get_loop_count() const; //times it looped + + virtual float get_pos() const; + virtual void seek_pos(float p_time); + + virtual float get_length() const; //if supported, otherwise return 0 + + AudioStreamPlaybackOGGVorbis() { } + ~AudioStreamPlaybackOGGVorbis(); +}; + +class AudioStreamOGGVorbis : public AudioStream { + + GDCLASS( AudioStreamOGGVorbis, AudioStream ) + OBJ_SAVE_TYPE( AudioStream ) //children are all saved as AudioStream, so they can be exchanged + RES_BASE_EXTENSION("asogg"); + +friend class AudioStreamPlaybackOGGVorbis; + + void *data; + uint32_t data_len; + + int decode_mem_size; + float sample_rate; + int channels; + float length; + bool loop; +protected: + + static void _bind_methods(); +public: + + void set_loop(bool p_enable); + bool has_loop() const; + + virtual Ref<AudioStreamPlayback> instance_playback(); + virtual String get_stream_name() const; + + void set_data(const PoolVector<uint8_t>& p_data); + PoolVector<uint8_t> get_data() const; + + AudioStreamOGGVorbis(); +}; + + + +#endif diff --git a/modules/stb_vorbis/config.py b/modules/stb_vorbis/config.py new file mode 100644 index 0000000000..fb920482f5 --- /dev/null +++ b/modules/stb_vorbis/config.py @@ -0,0 +1,7 @@ + +def can_build(platform): + return True + + +def configure(env): + pass diff --git a/modules/stb_vorbis/register_types.cpp b/modules/stb_vorbis/register_types.cpp new file mode 100644 index 0000000000..41fbc6fbd7 --- /dev/null +++ b/modules/stb_vorbis/register_types.cpp @@ -0,0 +1,45 @@ +/*************************************************************************/ +/* register_types.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#include "register_types.h" +#include "audio_stream_ogg_vorbis.h" +#include "resource_importer_ogg_vorbis.h" + +void register_stb_vorbis_types() { + +#ifdef TOOLS_ENABLED + Ref<ResourceImporterOGGVorbis> ogg_import; + ogg_import.instance(); + ResourceFormatImporter::get_singleton()->add_importer(ogg_import); +#endif + ClassDB::register_class<AudioStreamOGGVorbis>(); +} + +void unregister_stb_vorbis_types() { + +} diff --git a/modules/stb_vorbis/register_types.h b/modules/stb_vorbis/register_types.h new file mode 100644 index 0000000000..2824aa9f0c --- /dev/null +++ b/modules/stb_vorbis/register_types.h @@ -0,0 +1,30 @@ +/*************************************************************************/ +/* register_types.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +void register_stb_vorbis_types(); +void unregister_stb_vorbis_types(); diff --git a/modules/stb_vorbis/resource_importer_ogg_vorbis.cpp b/modules/stb_vorbis/resource_importer_ogg_vorbis.cpp new file mode 100644 index 0000000000..6f90c8587b --- /dev/null +++ b/modules/stb_vorbis/resource_importer_ogg_vorbis.cpp @@ -0,0 +1,84 @@ +#include "resource_importer_ogg_vorbis.h" + +#include "io/resource_saver.h" +#include "os/file_access.h" +#include "scene/resources/texture.h" + +String ResourceImporterOGGVorbis::get_importer_name() const { + + return "ogg_vorbis"; +} + +String ResourceImporterOGGVorbis::get_visible_name() const{ + + return "OGGVorbis"; +} +void ResourceImporterOGGVorbis::get_recognized_extensions(List<String> *p_extensions) const{ + + p_extensions->push_back("ogg"); +} + +String ResourceImporterOGGVorbis::get_save_extension() const { + return "asogg"; +} + +String ResourceImporterOGGVorbis::get_resource_type() const{ + + return "AudioStreamOGGVorbis"; +} + +bool ResourceImporterOGGVorbis::get_option_visibility(const String& p_option,const Map<StringName,Variant>& p_options) const { + + return true; +} + +int ResourceImporterOGGVorbis::get_preset_count() const { + return 0; +} +String ResourceImporterOGGVorbis::get_preset_name(int p_idx) const { + + return String(); +} + + +void ResourceImporterOGGVorbis::get_import_options(List<ImportOption> *r_options,int p_preset) const { + + + r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL,"loop"),true)); + +} + + + +Error ResourceImporterOGGVorbis::import(const String& p_source_file, const String& p_save_path, const Map<StringName,Variant>& p_options, List<String>* r_platform_variants, List<String> *r_gen_files) { + + bool loop = p_options["loop"]; + + FileAccess *f = FileAccess::open(p_source_file,FileAccess::READ); + if (!f) { + ERR_FAIL_COND_V(!f,ERR_CANT_OPEN); + } + + size_t len = f->get_len(); + + PoolVector<uint8_t> data; + data.resize(len); + PoolVector<uint8_t>::Write w = data.write(); + + f->get_buffer(w.ptr(),len); + + memdelete(f); + + Ref<AudioStreamOGGVorbis> ogg_stream; + ogg_stream.instance(); + + ogg_stream->set_data(data); + ogg_stream->set_loop(loop); + + return ResourceSaver::save(p_save_path+".asogg",ogg_stream); +} + +ResourceImporterOGGVorbis::ResourceImporterOGGVorbis() +{ + +} diff --git a/modules/stb_vorbis/resource_importer_ogg_vorbis.h b/modules/stb_vorbis/resource_importer_ogg_vorbis.h new file mode 100644 index 0000000000..8a3b2d8ec6 --- /dev/null +++ b/modules/stb_vorbis/resource_importer_ogg_vorbis.h @@ -0,0 +1,28 @@ +#ifndef RESOURCEIMPORTEROGGVORBIS_H +#define RESOURCEIMPORTEROGGVORBIS_H + + +#include "io/resource_import.h" +#include "audio_stream_ogg_vorbis.h" + +class ResourceImporterOGGVorbis : public ResourceImporter { + GDCLASS(ResourceImporterOGGVorbis,ResourceImporter) +public: + virtual String get_importer_name() const; + virtual String get_visible_name() const; + virtual void get_recognized_extensions(List<String> *p_extensions) const; + virtual String get_save_extension() const; + virtual String get_resource_type() const; + + virtual int get_preset_count() const; + virtual String get_preset_name(int p_idx) const; + + virtual void get_import_options(List<ImportOption> *r_options,int p_preset=0) const; + virtual bool get_option_visibility(const String& p_option,const Map<StringName,Variant>& p_options) const; + + virtual Error import(const String& p_source_file,const String& p_save_path,const Map<StringName,Variant>& p_options,List<String>* r_platform_variants,List<String>* r_gen_files=NULL); + + ResourceImporterOGGVorbis(); +}; + +#endif // RESOURCEIMPORTEROGGVORBIS_H diff --git a/modules/theora/SCsub b/modules/theora/SCsub new file mode 100644 index 0000000000..2de4d29640 --- /dev/null +++ b/modules/theora/SCsub @@ -0,0 +1,83 @@ +#!/usr/bin/env python + +Import('env') +Import('env_modules') + +env_theora = env_modules.Clone() + +# Thirdparty source files +if (env['builtin_libtheora'] != 'no'): + thirdparty_dir = "#thirdparty/libtheora/" + thirdparty_sources = [ + #"analyze.c", + #"apiwrapper.c", + "bitpack.c", + "cpu.c", + #"decapiwrapper.c", + "decinfo.c", + "decode.c", + "dequant.c", + #"encapiwrapper.c", + #"encfrag.c", + #"encinfo.c", + #"encode.c", + #"encoder_disabled.c", + #"enquant.c", + #"fdct.c", + "fragment.c", + "huffdec.c", + #"huffenc.c", + "idct.c", + "info.c", + "internal.c", + #"mathops.c", + #"mcenc.c", + "quant.c", + #"rate.c", + "state.c", + #"tokenize.c", + ] + + thirdparty_sources_x86 = [ + #"x86/mmxencfrag.c", + #"x86/mmxfdct.c", + "x86/mmxfrag.c", + "x86/mmxidct.c", + "x86/mmxstate.c", + #"x86/sse2fdct.c", + #"x86/x86enc.c", + "x86/x86state.c", + ] + + thirdparty_sources_x86_vc = [ + #"x86_vc/mmxencfrag.c", + #"x86_vc/mmxfdct.c", + "x86_vc/mmxfrag.c", + "x86_vc/mmxidct.c", + "x86_vc/mmxstate.c", + #"x86_vc/x86enc.c", + "x86_vc/x86state.c", + ] + + if (env["x86_libtheora_opt_gcc"]): + thirdparty_sources += thirdparty_sources_x86 + + if (env["x86_libtheora_opt_vc"]): + thirdparty_sources += thirdparty_sources_x86_vc + + if (env["x86_libtheora_opt_gcc"] or env["x86_libtheora_opt_vc"]): + env_theora.Append(CCFLAGS=["-DOC_X86_ASM"]) + + thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] + + env_theora.add_source_files(env.modules_sources, thirdparty_sources) + env_theora.Append(CPPPATH=[thirdparty_dir]) + + # also requires libogg and libvorbis + if (env['builtin_libogg'] != 'no'): + env_theora.Append(CPPPATH=["#thirdparty/libogg"]) + if (env['builtin_libvorbis'] != 'no'): + env_theora.Append(CPPPATH=["#thirdparty/libvorbis"]) + +# Godot source files +env_theora.add_source_files(env.modules_sources, "*.cpp") diff --git a/modules/theora/config.py b/modules/theora/config.py new file mode 100644 index 0000000000..8eefe81288 --- /dev/null +++ b/modules/theora/config.py @@ -0,0 +1,8 @@ + +def can_build(platform): +# return True + return False + + +def configure(env): + pass diff --git a/modules/theora/register_types.cpp b/modules/theora/register_types.cpp new file mode 100644 index 0000000000..58f63465c9 --- /dev/null +++ b/modules/theora/register_types.cpp @@ -0,0 +1,45 @@ +/*************************************************************************/ +/* register_types.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#include "register_types.h" + +#include "video_stream_theora.h" + +static ResourceFormatLoaderVideoStreamTheora* theora_stream_loader = NULL; + +void register_theora_types() { + + theora_stream_loader = memnew( ResourceFormatLoaderVideoStreamTheora ); + ResourceLoader::add_resource_format_loader(theora_stream_loader); + ClassDB::register_class<VideoStreamTheora>(); +} + +void unregister_theora_types() { + + memdelete( theora_stream_loader ); +} diff --git a/modules/theora/register_types.h b/modules/theora/register_types.h new file mode 100644 index 0000000000..582aa785c7 --- /dev/null +++ b/modules/theora/register_types.h @@ -0,0 +1,30 @@ +/*************************************************************************/ +/* register_types.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +void register_theora_types(); +void unregister_theora_types(); diff --git a/modules/theora/video_stream_theora.cpp b/modules/theora/video_stream_theora.cpp new file mode 100644 index 0000000000..2a7b2707bf --- /dev/null +++ b/modules/theora/video_stream_theora.cpp @@ -0,0 +1,943 @@ +/*************************************************************************/ +/* video_stream_theora.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#include "video_stream_theora.h" + +#include "global_config.h" +#include "os/os.h" +#include "yuv2rgb.h" + +int VideoStreamPlaybackTheora:: buffer_data() { + + char *buffer=ogg_sync_buffer(&oy,4096); + +#ifdef THEORA_USE_THREAD_STREAMING + + int read; + + do { + thread_sem->post(); + read = MIN(ring_buffer.data_left(),4096); + if (read) { + ring_buffer.read((uint8_t*)buffer,read); + ogg_sync_wrote(&oy,read); + } else { + OS::get_singleton()->delay_usec(100); + } + + } while(read==0); + + return read; + +#else + + int bytes=file->get_buffer((uint8_t*)buffer, 4096); + ogg_sync_wrote(&oy,bytes); + return(bytes); + +#endif +} + +int VideoStreamPlaybackTheora::queue_page(ogg_page *page){ + if(theora_p) { + ogg_stream_pagein(&to,page); + if (to.e_o_s) + theora_eos=true; + } + if(vorbis_p) { + ogg_stream_pagein(&vo,page); + if (vo.e_o_s) + vorbis_eos=true; + } + return 0; +} + +void VideoStreamPlaybackTheora::video_write(void){ + th_ycbcr_buffer yuv; + th_decode_ycbcr_out(td,yuv); + + // FIXME: The way stuff is commented out with `//*/` closing comments + // sounds very fishy... + + /* + int y_offset, uv_offset; + y_offset=(ti.pic_x&~1)+yuv[0].stride*(ti.pic_y&~1); + + { + int pixels = size.x * size.y; + frame_data.resize(pixels * 4); + PoolVector<uint8_t>::Write w = frame_data.write(); + char* dst = (char*)w.ptr(); + int p = 0; + for (int i=0; i<size.y; i++) { + + char *in_y = (char *)yuv[0].data+y_offset+yuv[0].stride*i; + char *out = dst + (int)size.x * 4 * i; + for (int j=0;j<size.x;j++) { + + dst[p++] = in_y[j]; + dst[p++] = in_y[j]; + dst[p++] = in_y[j]; + dst[p++] = 255; + }; + } + format = Image::FORMAT_RGBA8; + } + //*/ + + //* + + int pitch = 4; + frame_data.resize(size.x * size.y * pitch); + { + PoolVector<uint8_t>::Write w = frame_data.write(); + char* dst = (char*)w.ptr(); + + //uv_offset=(ti.pic_x/2)+(yuv[1].stride)*(ti.pic_y/2); + + if (px_fmt == TH_PF_444) { + + yuv444_2_rgb8888((uint8_t*)dst, (uint8_t*)yuv[0].data, (uint8_t*)yuv[1].data, (uint8_t*)yuv[2].data, size.x, size.y, yuv[0].stride, yuv[1].stride, size.x<<2, 0); + + } else if (px_fmt == TH_PF_422) { + + yuv422_2_rgb8888((uint8_t*)dst, (uint8_t*)yuv[0].data, (uint8_t*)yuv[1].data, (uint8_t*)yuv[2].data, size.x, size.y, yuv[0].stride, yuv[1].stride, size.x<<2, 0); + + } else if (px_fmt == TH_PF_420) { + + yuv420_2_rgb8888((uint8_t*)dst, (uint8_t*)yuv[0].data, (uint8_t*)yuv[2].data, (uint8_t*)yuv[1].data, size.x, size.y, yuv[0].stride, yuv[1].stride, size.x<<2, 0); + }; + + format = Image::FORMAT_RGBA8; + } + + Image img(size.x,size.y,0,Image::FORMAT_RGBA8,frame_data); //zero copy image creation + + texture->set_data(img); //zero copy send to visual server + + /* + + if (px_fmt == TH_PF_444) { + + int pitch = 3; + frame_data.resize(size.x * size.y * pitch); + PoolVector<uint8_t>::Write w = frame_data.write(); + char* dst = (char*)w.ptr(); + + for(int i=0;i<size.y;i++) { + + char *in_y = (char *)yuv[0].data+y_offset+yuv[0].stride*i; + char *out = dst + (int)size.x * pitch * i; + char *in_u = (char *)yuv[1].data+uv_offset+yuv[1].stride*i; + char *in_v = (char *)yuv[2].data+uv_offset+yuv[2].stride*i; + for (int j=0;j<size.x;j++) { + + out[j*3+0] = in_y[j]; + out[j*3+1] = in_u[j]; + out[j*3+2] = in_v[j]; + }; + } + + format = Image::FORMAT_YUV_444; + + } else { + + int div; + if (px_fmt!=TH_PF_422) { + div = 2; + } + + bool rgba = true; + if (rgba) { + + int pitch = 4; + frame_data.resize(size.x * size.y * pitch); + PoolVector<uint8_t>::Write w = frame_data.write(); + char* dst = (char*)w.ptr(); + + uv_offset=(ti.pic_x/2)+(yuv[1].stride)*(ti.pic_y / div); + for(int i=0;i<size.y;i++) { + char *in_y = (char *)yuv[0].data+y_offset+yuv[0].stride*i; + char *in_u = (char *)yuv[1].data+uv_offset+yuv[1].stride*(i/div); + char *in_v = (char *)yuv[2].data+uv_offset+yuv[2].stride*(i/div); + uint8_t *out = (uint8_t*)dst + (int)size.x * pitch * i; + int ofs = 0; + for (int j=0;j<size.x;j++) { + + uint8_t y, u, v; + y = in_y[j]; + u = in_u[j/2]; + v = in_v[j/2]; + + int32_t r = Math::fast_ftoi(1.164 * (y - 16) + 1.596 * (v - 128)); + int32_t g = Math::fast_ftoi(1.164 * (y - 16) - 0.813 * (v - 128) - 0.391 * (u - 128)); + int32_t b = Math::fast_ftoi(1.164 * (y - 16) + 2.018 * (u - 128)); + + out[ofs++] = CLAMP(r, 0, 255); + out[ofs++] = CLAMP(g, 0, 255); + out[ofs++] = CLAMP(b, 0, 255); + out[ofs++] = 255; + } + } + + format = Image::FORMAT_RGBA8; + + } else { + + int pitch = 2; + frame_data.resize(size.x * size.y * pitch); + PoolVector<uint8_t>::Write w = frame_data.write(); + char* dst = (char*)w.ptr(); + + uv_offset=(ti.pic_x/2)+(yuv[1].stride)*(ti.pic_y / div); + for(int i=0;i<size.y;i++) { + char *in_y = (char *)yuv[0].data+y_offset+yuv[0].stride*i; + char *out = dst + (int)size.x * pitch * i; + for (int j=0;j<size.x;j++) + out[j*2] = in_y[j]; + char *in_u = (char *)yuv[1].data+uv_offset+yuv[1].stride*(i/div); + char *in_v = (char *)yuv[2].data+uv_offset+yuv[2].stride*(i/div); + for (int j=0;j<(int)size.x>>1;j++) { + out[j*4+1] = in_u[j]; + out[j*4+3] = in_v[j]; + } + } + + format = Image::FORMAT_YUV_422; + }; + }; + //*/ + + frames_pending = 1; +} + +void VideoStreamPlaybackTheora::clear() { + + if (!file) + return; + + if(vorbis_p){ + ogg_stream_clear(&vo); + if (vorbis_p >= 3) { + vorbis_block_clear(&vb); + vorbis_dsp_clear(&vd); + }; + vorbis_comment_clear(&vc); + vorbis_info_clear(&vi); + vorbis_p = 0; + } + if(theora_p){ + ogg_stream_clear(&to); + th_decode_free(td); + th_comment_clear(&tc); + th_info_clear(&ti); + theora_p = 0; + } + ogg_sync_clear(&oy); + +#ifdef THEORA_USE_THREAD_STREAMING + thread_exit=true; + thread_sem->post(); //just in case + Thread::wait_to_finish(thread); + memdelete(thread); + thread=NULL; + ring_buffer.clear(); +#endif + //file_name = ""; + + theora_p = 0; + vorbis_p = 0; + videobuf_ready = 0; + frames_pending = 0; + videobuf_time = 0; + theora_eos=false; + vorbis_eos=false; + + if (file) { + memdelete(file); + } + file=NULL; + playing = false; +}; + +void VideoStreamPlaybackTheora::set_file(const String& p_file) { + + ERR_FAIL_COND(playing); + ogg_packet op; + th_setup_info *ts = NULL; + + file_name = p_file; + if (file) { + memdelete(file); + } + file = FileAccess::open(p_file, FileAccess::READ); + ERR_FAIL_COND(!file); + +#ifdef THEORA_USE_THREAD_STREAMING + thread_exit=false; + thread_eof=false; + //pre-fill buffer + int to_read = ring_buffer.space_left(); + int read = file->get_buffer(read_buffer.ptr(),to_read); + ring_buffer.write(read_buffer.ptr(),read); + + thread=Thread::create(_streaming_thread,this); + +#endif + + ogg_sync_init(&oy); + + /* init supporting Vorbis structures needed in header parsing */ + vorbis_info_init(&vi); + vorbis_comment_init(&vc); + + /* init supporting Theora structures needed in header parsing */ + th_comment_init(&tc); + th_info_init(&ti); + + theora_eos=false; + vorbis_eos=false; + + /* Ogg file open; parse the headers */ + /* Only interested in Vorbis/Theora streams */ + int stateflag = 0; + + int audio_track_skip=audio_track; + + + while(!stateflag){ + int ret=buffer_data(); + if(ret==0)break; + while(ogg_sync_pageout(&oy,&og)>0){ + ogg_stream_state test; + + /* is this a mandated initial header? If not, stop parsing */ + if(!ogg_page_bos(&og)){ + /* don't leak the page; get it into the appropriate stream */ + queue_page(&og); + stateflag=1; + break; + } + + ogg_stream_init(&test,ogg_page_serialno(&og)); + ogg_stream_pagein(&test,&og); + ogg_stream_packetout(&test,&op); + + + /* identify the codec: try theora */ + if(!theora_p && th_decode_headerin(&ti,&tc,&ts,&op)>=0){ + /* it is theora */ + copymem(&to,&test,sizeof(test)); + theora_p=1; + }else if(!vorbis_p && vorbis_synthesis_headerin(&vi,&vc,&op)>=0){ + + + /* it is vorbis */ + if (audio_track_skip) { + vorbis_info_clear(&vi); + vorbis_comment_clear(&vc); + ogg_stream_clear(&test); + vorbis_info_init(&vi); + vorbis_comment_init(&vc); + + audio_track_skip--; + } else { + copymem(&vo,&test,sizeof(test)); + vorbis_p=1; + } + }else{ + /* whatever it is, we don't care about it */ + ogg_stream_clear(&test); + } + } + /* fall through to non-bos page parsing */ + } + + /* we're expecting more header packets. */ + while((theora_p && theora_p<3) || (vorbis_p && vorbis_p<3)){ + int ret; + + /* look for further theora headers */ + while(theora_p && (theora_p<3) && (ret=ogg_stream_packetout(&to,&op))){ + if(ret<0){ + fprintf(stderr,"Error parsing Theora stream headers; " + "corrupt stream?\n"); + clear(); + return; + } + if(!th_decode_headerin(&ti,&tc,&ts,&op)){ + fprintf(stderr,"Error parsing Theora stream headers; " + "corrupt stream?\n"); + clear(); + return; + } + theora_p++; + } + + /* look for more vorbis header packets */ + while(vorbis_p && (vorbis_p<3) && (ret=ogg_stream_packetout(&vo,&op))){ + if(ret<0){ + fprintf(stderr,"Error parsing Vorbis stream headers; corrupt stream?\n"); + clear(); + return; + } + ret = vorbis_synthesis_headerin(&vi,&vc,&op); + if(ret){ + fprintf(stderr,"Error parsing Vorbis stream headers; corrupt stream?\n"); + clear(); + return; + } + vorbis_p++; + if(vorbis_p==3)break; + } + + /* The header pages/packets will arrive before anything else we + care about, or the stream is not obeying spec */ + + if(ogg_sync_pageout(&oy,&og)>0){ + queue_page(&og); /* demux into the appropriate stream */ + }else{ + int ret=buffer_data(); /* someone needs more data */ + if(ret==0){ + fprintf(stderr,"End of file while searching for codec headers.\n"); + clear(); + return; + } + } + } + + /* and now we have it all. initialize decoders */ + if(theora_p){ + td=th_decode_alloc(&ti,ts); + printf("Ogg logical stream %lx is Theora %dx%d %.02f fps", + to.serialno,ti.pic_width,ti.pic_height, + (double)ti.fps_numerator/ti.fps_denominator); + px_fmt=ti.pixel_fmt; + switch(ti.pixel_fmt){ + case TH_PF_420: printf(" 4:2:0 video\n"); break; + case TH_PF_422: printf(" 4:2:2 video\n"); break; + case TH_PF_444: printf(" 4:4:4 video\n"); break; + case TH_PF_RSVD: + default: + printf(" video\n (UNKNOWN Chroma sampling!)\n"); + break; + } + if(ti.pic_width!=ti.frame_width || ti.pic_height!=ti.frame_height) + printf(" Frame content is %dx%d with offset (%d,%d).\n", + ti.frame_width, ti.frame_height, ti.pic_x, ti.pic_y); + th_decode_ctl(td,TH_DECCTL_GET_PPLEVEL_MAX,&pp_level_max, + sizeof(pp_level_max)); + pp_level=pp_level_max; + pp_level=0; + th_decode_ctl(td,TH_DECCTL_SET_PPLEVEL,&pp_level,sizeof(pp_level)); + pp_inc=0; + + /*{ + int arg = 0xffff; + th_decode_ctl(td,TH_DECCTL_SET_TELEMETRY_MBMODE,&arg,sizeof(arg)); + th_decode_ctl(td,TH_DECCTL_SET_TELEMETRY_MV,&arg,sizeof(arg)); + th_decode_ctl(td,TH_DECCTL_SET_TELEMETRY_QI,&arg,sizeof(arg)); + arg=10; + th_decode_ctl(td,TH_DECCTL_SET_TELEMETRY_BITS,&arg,sizeof(arg)); + }*/ + + int w; + int h; + w=(ti.pic_x+ti.frame_width+1&~1)-(ti.pic_x&~1); + h=(ti.pic_y+ti.frame_height+1&~1)-(ti.pic_y&~1); + size.x = w; + size.y = h; + + texture->create(w,h,Image::FORMAT_RGBA8,Texture::FLAG_FILTER|Texture::FLAG_VIDEO_SURFACE); + + }else{ + /* tear down the partial theora setup */ + th_info_clear(&ti); + th_comment_clear(&tc); + } + + th_setup_free(ts); + + if(vorbis_p){ + vorbis_synthesis_init(&vd,&vi); + vorbis_block_init(&vd,&vb); + fprintf(stderr,"Ogg logical stream %lx is Vorbis %d channel %ld Hz audio.\n", + vo.serialno,vi.channels,vi.rate); + //_setup(vi.channels, vi.rate); + + }else{ + /* tear down the partial vorbis setup */ + vorbis_info_clear(&vi); + vorbis_comment_clear(&vc); + } + + playing = false; + buffering=true; + time=0; + audio_frames_wrote=0; + + +}; + +float VideoStreamPlaybackTheora::get_time() const { + + //print_line("total: "+itos(get_total())+" todo: "+itos(get_todo())); + //return MAX(0,time-((get_total())/(float)vi.rate)); + return time-AudioServer::get_singleton()->get_output_delay()-delay_compensation;//-((get_total())/(float)vi.rate); +}; + +Ref<Texture> VideoStreamPlaybackTheora::get_texture() { + + return texture; +} + +void VideoStreamPlaybackTheora::update(float p_delta) { + + if (!file) + return; + + if (!playing || paused) { + //printf("not playing\n"); + return; + }; + + + +#ifdef THEORA_USE_THREAD_STREAMING + thread_sem->post(); +#endif + + //double ctime =AudioServer::get_singleton()->get_mix_time(); + + //print_line("play "+rtos(p_delta)); + time+=p_delta; + + if (videobuf_time>get_time()) { + return; //no new frames need to be produced + } + + bool frame_done=false; + bool audio_done=!vorbis_p; + + while (!frame_done || (!audio_done && !vorbis_eos)) { + //a frame needs to be produced + + ogg_packet op; + bool no_theora=false; + + + while (vorbis_p) { + int ret; + float **pcm; + + bool buffer_full=false; + + /* if there's pending, decoded audio, grab it */ + if ((ret=vorbis_synthesis_pcmout(&vd,&pcm))>0) { + + + + const int AUXBUF_LEN=4096; + int to_read = ret; + int16_t aux_buffer[AUXBUF_LEN]; + + while(to_read) { + + int m = MIN(AUXBUF_LEN/vi.channels,to_read); + + int count = 0; + + for(int j=0;j<m;j++){ + for(int i=0;i<vi.channels;i++){ + + int val=Math::fast_ftoi(pcm[i][j]*32767.f); + if(val>32767)val=32767; + if(val<-32768)val=-32768; + aux_buffer[count++] = val; + } + } + + if (mix_callback) { + int mixed = mix_callback(mix_udata,aux_buffer,m); + to_read-=mixed; + if (mixed!=m) { //could mix no more + buffer_full=true; + break; + } + } else { + to_read-=m; //just pretend we sent the audio + } + + + } + + + int tr = vorbis_synthesis_read(&vd, ret-to_read); + + + if (vd.granulepos>=0) { + //print_line("wrote: "+itos(audio_frames_wrote)+" gpos: "+itos(vd.granulepos)); + } + + //print_line("mix audio!"); + + audio_frames_wrote+=ret-to_read; + + //print_line("AGP: "+itos(vd.granulepos)+" added "+itos(ret-to_read)); + + + } else { + + /* no pending audio; is there a pending packet to decode? */ + if (ogg_stream_packetout(&vo,&op)>0){ + if(vorbis_synthesis(&vb,&op)==0) { /* test for success! */ + vorbis_synthesis_blockin(&vd,&vb); + } + } else { /* we need more data; break out to suck in another page */ + //printf("need moar data\n"); + break; + }; + } + + + audio_done = videobuf_time < (audio_frames_wrote/float(vi.rate)); + + if (buffer_full) + break; + } + + while(theora_p && !frame_done){ + /* theora is one in, one out... */ + if(ogg_stream_packetout(&to,&op)>0){ + + + if(false && pp_inc){ + pp_level+=pp_inc; + th_decode_ctl(td,TH_DECCTL_SET_PPLEVEL,&pp_level, + sizeof(pp_level)); + pp_inc=0; + } + /*HACK: This should be set after a seek or a gap, but we might not have + a granulepos for the first packet (we only have them for the last + packet on a page), so we just set it as often as we get it. + To do this right, we should back-track from the last packet on the + page and compute the correct granulepos for the first packet after + a seek or a gap.*/ + if(op.granulepos>=0){ + th_decode_ctl(td,TH_DECCTL_SET_GRANPOS,&op.granulepos, + sizeof(op.granulepos)); + } + ogg_int64_t videobuf_granulepos; + if(th_decode_packetin(td,&op,&videobuf_granulepos)==0){ + videobuf_time=th_granule_time(td,videobuf_granulepos); + + //printf("frame time %f, play time %f, ready %i\n", (float)videobuf_time, get_time(), videobuf_ready); + + /* is it already too old to be useful? This is only actually + useful cosmetically after a SIGSTOP. Note that we have to + decode the frame even if we don't show it (for now) due to + keyframing. Soon enough libtheora will be able to deal + with non-keyframe seeks. */ + + if(videobuf_time>=get_time()) { + frame_done=true; + } else{ + /*If we are too slow, reduce the pp level.*/ + pp_inc=pp_level>0?-1:0; + } + } else { + + } + + } else { + no_theora=true; + break; + } + } + + + //print_line("no theora: "+itos(no_theora)+" theora eos: "+itos(theora_eos)+" frame done "+itos(frame_done)); + +#ifdef THEORA_USE_THREAD_STREAMING + if (file && thread_eof && no_theora && theora_eos && ring_buffer.data_left()==0) { +#else + if (file && /*!videobuf_ready && */ no_theora && theora_eos) { +#endif + printf("video done, stopping\n"); + stop(); + return; + }; + #if 0 + if (!videobuf_ready || audio_todo > 0){ + /* no data yet for somebody. Grab another page */ + + buffer_data(); + while(ogg_sync_pageout(&oy,&og)>0){ + queue_page(&og); + } + } + #else + + + if (!frame_done || !audio_done){ + //what's the point of waiting for audio to grab a page? + + buffer_data(); + while(ogg_sync_pageout(&oy,&og)>0){ + queue_page(&og); + } + } + #endif + /* If playback has begun, top audio buffer off immediately. */ + //if(stateflag) audio_write_nonblocking(); + + /* are we at or past time for this video frame? */ + if(videobuf_ready && videobuf_time<=get_time()){ + + //video_write(); + //videobuf_ready=0; + } else { + //printf("frame at %f not ready (time %f), ready %i\n", (float)videobuf_time, get_time(), videobuf_ready); + } + + float tdiff=videobuf_time-get_time(); + /*If we have lots of extra time, increase the post-processing level.*/ + if(tdiff>ti.fps_denominator*0.25/ti.fps_numerator){ + pp_inc=pp_level<pp_level_max?1:0; + } + else if(tdiff<ti.fps_denominator*0.05/ti.fps_numerator){ + pp_inc=pp_level>0?-1:0; + } + + } + + video_write(); + +}; + + +void VideoStreamPlaybackTheora::play() { + + if (!playing) + time=0; + else { + stop(); + } + + playing = true; + delay_compensation=GlobalConfig::get_singleton()->get("audio/video_delay_compensation_ms"); + delay_compensation/=1000.0; + + +}; + +void VideoStreamPlaybackTheora::stop() { + + if (playing) { + + clear(); + set_file(file_name); //reset + } + playing = false; + time=0; +}; + +bool VideoStreamPlaybackTheora::is_playing() const { + + return playing; +}; + +void VideoStreamPlaybackTheora::set_paused(bool p_paused) { + + paused=p_paused; + //pau = !p_paused; +}; + +bool VideoStreamPlaybackTheora::is_paused(bool p_paused) const { + + return paused; +}; + +void VideoStreamPlaybackTheora::set_loop(bool p_enable) { + +}; + +bool VideoStreamPlaybackTheora::has_loop() const { + + return false; +}; + +float VideoStreamPlaybackTheora::get_length() const { + + return 0; +}; + +String VideoStreamPlaybackTheora::get_stream_name() const { + + return ""; +}; + +int VideoStreamPlaybackTheora::get_loop_count() const { + + return 0; +}; + +float VideoStreamPlaybackTheora::get_pos() const { + + return get_time(); +}; + +void VideoStreamPlaybackTheora::seek_pos(float p_time) { + + // no +}; + +void VideoStreamPlaybackTheora::set_mix_callback(AudioMixCallback p_callback,void *p_userdata) { + + mix_callback=p_callback; + mix_udata=p_userdata; +} + +int VideoStreamPlaybackTheora::get_channels() const{ + + return vi.channels; +} + +void VideoStreamPlaybackTheora::set_audio_track(int p_idx) { + + audio_track=p_idx; +} + +int VideoStreamPlaybackTheora::get_mix_rate() const{ + + return vi.rate; +} + +#ifdef THEORA_USE_THREAD_STREAMING + + +void VideoStreamPlaybackTheora::_streaming_thread(void *ud) { + + VideoStreamPlaybackTheora *vs=(VideoStreamPlaybackTheora*)ud; + + while(!vs->thread_exit) { + + //just fill back the buffer + if (!vs->thread_eof) { + + int to_read = vs->ring_buffer.space_left(); + if (to_read) { + int read = vs->file->get_buffer(vs->read_buffer.ptr(),to_read); + vs->ring_buffer.write(vs->read_buffer.ptr(),read); + vs->thread_eof=vs->file->eof_reached(); + } + + + } + + vs->thread_sem->wait(); + } +} + +#endif + +VideoStreamPlaybackTheora::VideoStreamPlaybackTheora() { + + file = NULL; + theora_p = 0; + vorbis_p = 0; + videobuf_ready = 0; + playing = false; + frames_pending = 0; + videobuf_time = 0; + paused=false; + + buffering=false; + texture = Ref<ImageTexture>( memnew(ImageTexture )); + mix_callback=NULL; + mix_udata=NULL; + audio_track=0; + delay_compensation=0; + audio_frames_wrote=0; + +#ifdef THEORA_USE_THREAD_STREAMING + int rb_power = nearest_shift(RB_SIZE_KB*1024); + ring_buffer.resize(rb_power); + read_buffer.resize(RB_SIZE_KB*1024); + thread_sem=Semaphore::create(); + thread=NULL; + thread_exit=false; + thread_eof=false; + +#endif +}; + +VideoStreamPlaybackTheora::~VideoStreamPlaybackTheora() { + +#ifdef THEORA_USE_THREAD_STREAMING + + memdelete(thread_sem); +#endif + clear(); + + if (file) + memdelete(file); + + +}; + + +RES ResourceFormatLoaderVideoStreamTheora::load(const String &p_path,const String& p_original_path, Error *r_error) { + if (r_error) + *r_error=ERR_FILE_CANT_OPEN; + + VideoStreamTheora *stream = memnew(VideoStreamTheora); + stream->set_file(p_path); + + if (r_error) + *r_error=OK; + + return Ref<VideoStreamTheora>(stream); +} + +void ResourceFormatLoaderVideoStreamTheora::get_recognized_extensions(List<String> *p_extensions) const { + + p_extensions->push_back("ogm"); + p_extensions->push_back("ogv"); +} +bool ResourceFormatLoaderVideoStreamTheora::handles_type(const String& p_type) const { + return (p_type=="VideoStream" || p_type=="VideoStreamTheora"); +} + +String ResourceFormatLoaderVideoStreamTheora::get_resource_type(const String &p_path) const { + + String exl=p_path.get_extension().to_lower(); + if (exl=="ogm" || exl=="ogv") + return "VideoStreamTheora"; + return ""; +} diff --git a/modules/theora/video_stream_theora.h b/modules/theora/video_stream_theora.h new file mode 100644 index 0000000000..0e1f5fa864 --- /dev/null +++ b/modules/theora/video_stream_theora.h @@ -0,0 +1,199 @@ +/*************************************************************************/ +/* video_stream_theora.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#ifndef VIDEO_STREAM_THEORA_H +#define VIDEO_STREAM_THEORA_H + +#include "io/resource_loader.h" +#include "os/file_access.h" +#include "os/thread.h" +#include "os/semaphore.h" +#include "ring_buffer.h" +#include "scene/resources/video_stream.h" + +#include <theora/theoradec.h> +#include <vorbis/codec.h> + +//#define THEORA_USE_THREAD_STREAMING + +class VideoStreamPlaybackTheora : public VideoStreamPlayback { + + GDCLASS(VideoStreamPlaybackTheora, VideoStreamPlayback); + + enum { + MAX_FRAMES = 4, + }; + + //Image frames[MAX_FRAMES]; + Image::Format format; + PoolVector<uint8_t> frame_data; + int frames_pending; + FileAccess* file; + String file_name; + int audio_frames_wrote; + Point2i size; + + int buffer_data(); + int queue_page(ogg_page *page); + void video_write(void); + float get_time() const; + + bool theora_eos; + bool vorbis_eos; + + ogg_sync_state oy; + ogg_page og; + ogg_stream_state vo; + ogg_stream_state to; + th_info ti; + th_comment tc; + th_dec_ctx *td; + vorbis_info vi; + vorbis_dsp_state vd; + vorbis_block vb; + vorbis_comment vc; + th_pixel_fmt px_fmt; + double videobuf_time; + int pp_inc; + + int theora_p; + int vorbis_p; + int pp_level_max; + int pp_level; + int videobuf_ready; + + bool playing; + bool buffering; + + double last_update_time; + double time; + double delay_compensation; + + Ref<ImageTexture> texture; + + AudioMixCallback mix_callback; + void* mix_udata; + bool paused; + +#ifdef THEORA_USE_THREAD_STREAMING + + enum { + RB_SIZE_KB=1024 + }; + + RingBuffer<uint8_t> ring_buffer; + Vector<uint8_t> read_buffer; + bool thread_eof; + Semaphore *thread_sem; + Thread *thread; + volatile bool thread_exit; + + static void _streaming_thread(void *ud); + +#endif + + + int audio_track; + +protected: + + void clear(); + +public: + + virtual void play(); + virtual void stop(); + virtual bool is_playing() const; + + virtual void set_paused(bool p_paused); + virtual bool is_paused(bool p_paused) const; + + virtual void set_loop(bool p_enable); + virtual bool has_loop() const; + + virtual float get_length() const; + + virtual String get_stream_name() const; + + virtual int get_loop_count() const; + + virtual float get_pos() const; + virtual void seek_pos(float p_time); + + + void set_file(const String& p_file); + + virtual Ref<Texture> get_texture(); + virtual void update(float p_delta); + + virtual void set_mix_callback(AudioMixCallback p_callback,void *p_userdata); + virtual int get_channels() const; + virtual int get_mix_rate() const; + + virtual void set_audio_track(int p_idx); + + VideoStreamPlaybackTheora(); + ~VideoStreamPlaybackTheora(); +}; + + + +class VideoStreamTheora : public VideoStream { + + GDCLASS(VideoStreamTheora,VideoStream); + + String file; + int audio_track; + + +public: + + Ref<VideoStreamPlayback> instance_playback() { + Ref<VideoStreamPlaybackTheora> pb = memnew( VideoStreamPlaybackTheora ); + pb->set_audio_track(audio_track); + pb->set_file(file); + return pb; + } + + void set_file(const String& p_file) { file=p_file; } + void set_audio_track(int p_track) { audio_track=p_track; } + + VideoStreamTheora() { audio_track=0; } + +}; + +class ResourceFormatLoaderVideoStreamTheora : public ResourceFormatLoader { +public: + virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL); + virtual void get_recognized_extensions(List<String> *p_extensions) const; + virtual bool handles_type(const String& p_type) const; + virtual String get_resource_type(const String &p_path) const; + +}; + +#endif diff --git a/modules/theora/yuv2rgb.h b/modules/theora/yuv2rgb.h new file mode 100644 index 0000000000..3b81607a65 --- /dev/null +++ b/modules/theora/yuv2rgb.h @@ -0,0 +1,1120 @@ +#ifndef YUV2RGB_H +#define YUV2RGB_H + +#include "typedefs.h" + +static const uint32_t tables[256*3] = { + /* y_table */ + 0x7FFFFFEDU, + 0x7FFFFFEFU, + 0x7FFFFFF0U, + 0x7FFFFFF1U, + 0x7FFFFFF2U, + 0x7FFFFFF3U, + 0x7FFFFFF4U, + 0x7FFFFFF6U, + 0x7FFFFFF7U, + 0x7FFFFFF8U, + 0x7FFFFFF9U, + 0x7FFFFFFAU, + 0x7FFFFFFBU, + 0x7FFFFFFDU, + 0x7FFFFFFEU, + 0x7FFFFFFFU, + 0x80000000U, + 0x80400801U, + 0x80A01002U, + 0x80E01803U, + 0x81202805U, + 0x81803006U, + 0x81C03807U, + 0x82004008U, + 0x82604809U, + 0x82A0500AU, + 0x82E0600CU, + 0x8340680DU, + 0x8380700EU, + 0x83C0780FU, + 0x84208010U, + 0x84608811U, + 0x84A09813U, + 0x8500A014U, + 0x8540A815U, + 0x8580B016U, + 0x85E0B817U, + 0x8620C018U, + 0x8660D01AU, + 0x86C0D81BU, + 0x8700E01CU, + 0x8740E81DU, + 0x87A0F01EU, + 0x87E0F81FU, + 0x88210821U, + 0x88811022U, + 0x88C11823U, + 0x89012024U, + 0x89412825U, + 0x89A13026U, + 0x89E14028U, + 0x8A214829U, + 0x8A81502AU, + 0x8AC1582BU, + 0x8B01602CU, + 0x8B61682DU, + 0x8BA1782FU, + 0x8BE18030U, + 0x8C418831U, + 0x8C819032U, + 0x8CC19833U, + 0x8D21A034U, + 0x8D61B036U, + 0x8DA1B837U, + 0x8E01C038U, + 0x8E41C839U, + 0x8E81D03AU, + 0x8EE1D83BU, + 0x8F21E83DU, + 0x8F61F03EU, + 0x8FC1F83FU, + 0x90020040U, + 0x90420841U, + 0x90A21042U, + 0x90E22044U, + 0x91222845U, + 0x91823046U, + 0x91C23847U, + 0x92024048U, + 0x92624849U, + 0x92A2504AU, + 0x92E2604CU, + 0x9342684DU, + 0x9382704EU, + 0x93C2784FU, + 0x94228050U, + 0x94628851U, + 0x94A29853U, + 0x9502A054U, + 0x9542A855U, + 0x9582B056U, + 0x95E2B857U, + 0x9622C058U, + 0x9662D05AU, + 0x96C2D85BU, + 0x9702E05CU, + 0x9742E85DU, + 0x97A2F05EU, + 0x97E2F85FU, + 0x98230861U, + 0x98831062U, + 0x98C31863U, + 0x99032064U, + 0x99632865U, + 0x99A33066U, + 0x99E34068U, + 0x9A434869U, + 0x9A83506AU, + 0x9AC3586BU, + 0x9B23606CU, + 0x9B63686DU, + 0x9BA3786FU, + 0x9BE38070U, + 0x9C438871U, + 0x9C839072U, + 0x9CC39873U, + 0x9D23A074U, + 0x9D63B076U, + 0x9DA3B877U, + 0x9E03C078U, + 0x9E43C879U, + 0x9E83D07AU, + 0x9EE3D87BU, + 0x9F23E87DU, + 0x9F63F07EU, + 0x9FC3F87FU, + 0xA0040080U, + 0xA0440881U, + 0xA0A41082U, + 0xA0E42084U, + 0xA1242885U, + 0xA1843086U, + 0xA1C43887U, + 0xA2044088U, + 0xA2644889U, + 0xA2A4588BU, + 0xA2E4608CU, + 0xA344688DU, + 0xA384708EU, + 0xA3C4788FU, + 0xA4248090U, + 0xA4649092U, + 0xA4A49893U, + 0xA504A094U, + 0xA544A895U, + 0xA584B096U, + 0xA5E4B897U, + 0xA624C098U, + 0xA664D09AU, + 0xA6C4D89BU, + 0xA704E09CU, + 0xA744E89DU, + 0xA7A4F09EU, + 0xA7E4F89FU, + 0xA82508A1U, + 0xA88510A2U, + 0xA8C518A3U, + 0xA90520A4U, + 0xA96528A5U, + 0xA9A530A6U, + 0xA9E540A8U, + 0xAA4548A9U, + 0xAA8550AAU, + 0xAAC558ABU, + 0xAB2560ACU, + 0xAB6568ADU, + 0xABA578AFU, + 0xAC0580B0U, + 0xAC4588B1U, + 0xAC8590B2U, + 0xACE598B3U, + 0xAD25A0B4U, + 0xAD65B0B6U, + 0xADA5B8B7U, + 0xAE05C0B8U, + 0xAE45C8B9U, + 0xAE85D0BAU, + 0xAEE5D8BBU, + 0xAF25E8BDU, + 0xAF65F0BEU, + 0xAFC5F8BFU, + 0xB00600C0U, + 0xB04608C1U, + 0xB0A610C2U, + 0xB0E620C4U, + 0xB12628C5U, + 0xB18630C6U, + 0xB1C638C7U, + 0xB20640C8U, + 0xB26648C9U, + 0xB2A658CBU, + 0xB2E660CCU, + 0xB34668CDU, + 0xB38670CEU, + 0xB3C678CFU, + 0xB42680D0U, + 0xB46690D2U, + 0xB4A698D3U, + 0xB506A0D4U, + 0xB546A8D5U, + 0xB586B0D6U, + 0xB5E6B8D7U, + 0xB626C8D9U, + 0xB666D0DAU, + 0xB6C6D8DBU, + 0xB706E0DCU, + 0xB746E8DDU, + 0xB7A6F0DEU, + 0xB7E6F8DFU, + 0xB82708E1U, + 0xB88710E2U, + 0xB8C718E3U, + 0xB90720E4U, + 0xB96728E5U, + 0xB9A730E6U, + 0xB9E740E8U, + 0xBA4748E9U, + 0xBA8750EAU, + 0xBAC758EBU, + 0xBB2760ECU, + 0xBB6768EDU, + 0xBBA778EFU, + 0xBC0780F0U, + 0xBC4788F1U, + 0xBC8790F2U, + 0xBCE798F3U, + 0xBD27A0F4U, + 0xBD67B0F6U, + 0xBDC7B8F7U, + 0xBE07C0F8U, + 0xBE47C8F9U, + 0xBEA7D0FAU, + 0xBEE7D8FBU, + 0xBF27E8FDU, + 0xBF87F0FEU, + 0xBFC7F8FFU, + 0xC0080100U, + 0xC0480901U, + 0xC0A81102U, + 0xC0E82104U, + 0xC0E82104U, + 0xC0E82104U, + 0xC0E82104U, + 0xC0E82104U, + 0xC0E82104U, + 0xC0E82104U, + 0xC0E82104U, + 0xC0E82104U, + 0xC0E82104U, + 0xC0E82104U, + 0xC0E82104U, + 0xC0E82104U, + 0xC0E82104U, + 0xC0E82104U, + 0xC0E82104U, + 0xC0E82104U, + /* u_table */ + 0x0C400103U, + 0x0C200105U, + 0x0C200107U, + 0x0C000109U, + 0x0BE0010BU, + 0x0BC0010DU, + 0x0BA0010FU, + 0x0BA00111U, + 0x0B800113U, + 0x0B600115U, + 0x0B400117U, + 0x0B400119U, + 0x0B20011BU, + 0x0B00011DU, + 0x0AE0011FU, + 0x0AE00121U, + 0x0AC00123U, + 0x0AA00125U, + 0x0A800127U, + 0x0A600129U, + 0x0A60012BU, + 0x0A40012DU, + 0x0A20012FU, + 0x0A000131U, + 0x0A000132U, + 0x09E00134U, + 0x09C00136U, + 0x09A00138U, + 0x09A0013AU, + 0x0980013CU, + 0x0960013EU, + 0x09400140U, + 0x09400142U, + 0x09200144U, + 0x09000146U, + 0x08E00148U, + 0x08C0014AU, + 0x08C0014CU, + 0x08A0014EU, + 0x08800150U, + 0x08600152U, + 0x08600154U, + 0x08400156U, + 0x08200158U, + 0x0800015AU, + 0x0800015CU, + 0x07E0015EU, + 0x07C00160U, + 0x07A00162U, + 0x07A00164U, + 0x07800166U, + 0x07600168U, + 0x0740016AU, + 0x0720016CU, + 0x0720016EU, + 0x07000170U, + 0x06E00172U, + 0x06C00174U, + 0x06C00176U, + 0x06A00178U, + 0x0680017AU, + 0x0660017CU, + 0x0660017EU, + 0x06400180U, + 0x06200182U, + 0x06000184U, + 0x05E00185U, + 0x05E00187U, + 0x05C00189U, + 0x05A0018BU, + 0x0580018DU, + 0x0580018FU, + 0x05600191U, + 0x05400193U, + 0x05200195U, + 0x05200197U, + 0x05000199U, + 0x04E0019BU, + 0x04C0019DU, + 0x04C0019FU, + 0x04A001A1U, + 0x048001A3U, + 0x046001A5U, + 0x044001A7U, + 0x044001A9U, + 0x042001ABU, + 0x040001ADU, + 0x03E001AFU, + 0x03E001B1U, + 0x03C001B3U, + 0x03A001B5U, + 0x038001B7U, + 0x038001B9U, + 0x036001BBU, + 0x034001BDU, + 0x032001BFU, + 0x032001C1U, + 0x030001C3U, + 0x02E001C5U, + 0x02C001C7U, + 0x02A001C9U, + 0x02A001CBU, + 0x028001CDU, + 0x026001CFU, + 0x024001D1U, + 0x024001D3U, + 0x022001D5U, + 0x020001D7U, + 0x01E001D8U, + 0x01E001DAU, + 0x01C001DCU, + 0x01A001DEU, + 0x018001E0U, + 0x016001E2U, + 0x016001E4U, + 0x014001E6U, + 0x012001E8U, + 0x010001EAU, + 0x010001ECU, + 0x00E001EEU, + 0x00C001F0U, + 0x00A001F2U, + 0x00A001F4U, + 0x008001F6U, + 0x006001F8U, + 0x004001FAU, + 0x004001FCU, + 0x002001FEU, + 0x00000200U, + 0xFFE00202U, + 0xFFC00204U, + 0xFFC00206U, + 0xFFA00208U, + 0xFF80020AU, + 0xFF60020CU, + 0xFF60020EU, + 0xFF400210U, + 0xFF200212U, + 0xFF000214U, + 0xFF000216U, + 0xFEE00218U, + 0xFEC0021AU, + 0xFEA0021CU, + 0xFEA0021EU, + 0xFE800220U, + 0xFE600222U, + 0xFE400224U, + 0xFE200226U, + 0xFE200228U, + 0xFE000229U, + 0xFDE0022BU, + 0xFDC0022DU, + 0xFDC0022FU, + 0xFDA00231U, + 0xFD800233U, + 0xFD600235U, + 0xFD600237U, + 0xFD400239U, + 0xFD20023BU, + 0xFD00023DU, + 0xFCE0023FU, + 0xFCE00241U, + 0xFCC00243U, + 0xFCA00245U, + 0xFC800247U, + 0xFC800249U, + 0xFC60024BU, + 0xFC40024DU, + 0xFC20024FU, + 0xFC200251U, + 0xFC000253U, + 0xFBE00255U, + 0xFBC00257U, + 0xFBC00259U, + 0xFBA0025BU, + 0xFB80025DU, + 0xFB60025FU, + 0xFB400261U, + 0xFB400263U, + 0xFB200265U, + 0xFB000267U, + 0xFAE00269U, + 0xFAE0026BU, + 0xFAC0026DU, + 0xFAA0026FU, + 0xFA800271U, + 0xFA800273U, + 0xFA600275U, + 0xFA400277U, + 0xFA200279U, + 0xFA20027BU, + 0xFA00027CU, + 0xF9E0027EU, + 0xF9C00280U, + 0xF9A00282U, + 0xF9A00284U, + 0xF9800286U, + 0xF9600288U, + 0xF940028AU, + 0xF940028CU, + 0xF920028EU, + 0xF9000290U, + 0xF8E00292U, + 0xF8E00294U, + 0xF8C00296U, + 0xF8A00298U, + 0xF880029AU, + 0xF860029CU, + 0xF860029EU, + 0xF84002A0U, + 0xF82002A2U, + 0xF80002A4U, + 0xF80002A6U, + 0xF7E002A8U, + 0xF7C002AAU, + 0xF7A002ACU, + 0xF7A002AEU, + 0xF78002B0U, + 0xF76002B2U, + 0xF74002B4U, + 0xF74002B6U, + 0xF72002B8U, + 0xF70002BAU, + 0xF6E002BCU, + 0xF6C002BEU, + 0xF6C002C0U, + 0xF6A002C2U, + 0xF68002C4U, + 0xF66002C6U, + 0xF66002C8U, + 0xF64002CAU, + 0xF62002CCU, + 0xF60002CEU, + 0xF60002CFU, + 0xF5E002D1U, + 0xF5C002D3U, + 0xF5A002D5U, + 0xF5A002D7U, + 0xF58002D9U, + 0xF56002DBU, + 0xF54002DDU, + 0xF52002DFU, + 0xF52002E1U, + 0xF50002E3U, + 0xF4E002E5U, + 0xF4C002E7U, + 0xF4C002E9U, + 0xF4A002EBU, + 0xF48002EDU, + 0xF46002EFU, + 0xF46002F1U, + 0xF44002F3U, + 0xF42002F5U, + 0xF40002F7U, + 0xF3E002F9U, + 0xF3E002FBU, + /* v_table */ + 0x1A09A000U, + 0x19E9A800U, + 0x19A9B800U, + 0x1969C800U, + 0x1949D000U, + 0x1909E000U, + 0x18C9E800U, + 0x18A9F800U, + 0x186A0000U, + 0x182A1000U, + 0x180A2000U, + 0x17CA2800U, + 0x17AA3800U, + 0x176A4000U, + 0x172A5000U, + 0x170A6000U, + 0x16CA6800U, + 0x168A7800U, + 0x166A8000U, + 0x162A9000U, + 0x160AA000U, + 0x15CAA800U, + 0x158AB800U, + 0x156AC000U, + 0x152AD000U, + 0x14EAE000U, + 0x14CAE800U, + 0x148AF800U, + 0x146B0000U, + 0x142B1000U, + 0x13EB2000U, + 0x13CB2800U, + 0x138B3800U, + 0x134B4000U, + 0x132B5000U, + 0x12EB6000U, + 0x12CB6800U, + 0x128B7800U, + 0x124B8000U, + 0x122B9000U, + 0x11EBA000U, + 0x11ABA800U, + 0x118BB800U, + 0x114BC000U, + 0x112BD000U, + 0x10EBE000U, + 0x10ABE800U, + 0x108BF800U, + 0x104C0000U, + 0x100C1000U, + 0x0FEC2000U, + 0x0FAC2800U, + 0x0F8C3800U, + 0x0F4C4000U, + 0x0F0C5000U, + 0x0EEC5800U, + 0x0EAC6800U, + 0x0E6C7800U, + 0x0E4C8000U, + 0x0E0C9000U, + 0x0DEC9800U, + 0x0DACA800U, + 0x0D6CB800U, + 0x0D4CC000U, + 0x0D0CD000U, + 0x0CCCD800U, + 0x0CACE800U, + 0x0C6CF800U, + 0x0C4D0000U, + 0x0C0D1000U, + 0x0BCD1800U, + 0x0BAD2800U, + 0x0B6D3800U, + 0x0B2D4000U, + 0x0B0D5000U, + 0x0ACD5800U, + 0x0AAD6800U, + 0x0A6D7800U, + 0x0A2D8000U, + 0x0A0D9000U, + 0x09CD9800U, + 0x098DA800U, + 0x096DB800U, + 0x092DC000U, + 0x090DD000U, + 0x08CDD800U, + 0x088DE800U, + 0x086DF800U, + 0x082E0000U, + 0x07EE1000U, + 0x07CE1800U, + 0x078E2800U, + 0x076E3800U, + 0x072E4000U, + 0x06EE5000U, + 0x06CE5800U, + 0x068E6800U, + 0x064E7800U, + 0x062E8000U, + 0x05EE9000U, + 0x05CE9800U, + 0x058EA800U, + 0x054EB800U, + 0x052EC000U, + 0x04EED000U, + 0x04AED800U, + 0x048EE800U, + 0x044EF000U, + 0x042F0000U, + 0x03EF1000U, + 0x03AF1800U, + 0x038F2800U, + 0x034F3000U, + 0x030F4000U, + 0x02EF5000U, + 0x02AF5800U, + 0x028F6800U, + 0x024F7000U, + 0x020F8000U, + 0x01EF9000U, + 0x01AF9800U, + 0x016FA800U, + 0x014FB000U, + 0x010FC000U, + 0x00EFD000U, + 0x00AFD800U, + 0x006FE800U, + 0x004FF000U, + 0x00100000U, + 0xFFD01000U, + 0xFFB01800U, + 0xFF702800U, + 0xFF303000U, + 0xFF104000U, + 0xFED05000U, + 0xFEB05800U, + 0xFE706800U, + 0xFE307000U, + 0xFE108000U, + 0xFDD09000U, + 0xFD909800U, + 0xFD70A800U, + 0xFD30B000U, + 0xFD10C000U, + 0xFCD0D000U, + 0xFC90D800U, + 0xFC70E800U, + 0xFC30F000U, + 0xFBF10000U, + 0xFBD11000U, + 0xFB911800U, + 0xFB712800U, + 0xFB313000U, + 0xFAF14000U, + 0xFAD14800U, + 0xFA915800U, + 0xFA516800U, + 0xFA317000U, + 0xF9F18000U, + 0xF9D18800U, + 0xF9919800U, + 0xF951A800U, + 0xF931B000U, + 0xF8F1C000U, + 0xF8B1C800U, + 0xF891D800U, + 0xF851E800U, + 0xF831F000U, + 0xF7F20000U, + 0xF7B20800U, + 0xF7921800U, + 0xF7522800U, + 0xF7123000U, + 0xF6F24000U, + 0xF6B24800U, + 0xF6925800U, + 0xF6526800U, + 0xF6127000U, + 0xF5F28000U, + 0xF5B28800U, + 0xF5729800U, + 0xF552A800U, + 0xF512B000U, + 0xF4F2C000U, + 0xF4B2C800U, + 0xF472D800U, + 0xF452E800U, + 0xF412F000U, + 0xF3D30000U, + 0xF3B30800U, + 0xF3731800U, + 0xF3532800U, + 0xF3133000U, + 0xF2D34000U, + 0xF2B34800U, + 0xF2735800U, + 0xF2336800U, + 0xF2137000U, + 0xF1D38000U, + 0xF1B38800U, + 0xF1739800U, + 0xF133A800U, + 0xF113B000U, + 0xF0D3C000U, + 0xF093C800U, + 0xF073D800U, + 0xF033E000U, + 0xF013F000U, + 0xEFD40000U, + 0xEF940800U, + 0xEF741800U, + 0xEF342000U, + 0xEEF43000U, + 0xEED44000U, + 0xEE944800U, + 0xEE745800U, + 0xEE346000U, + 0xEDF47000U, + 0xEDD48000U, + 0xED948800U, + 0xED549800U, + 0xED34A000U, + 0xECF4B000U, + 0xECD4C000U, + 0xEC94C800U, + 0xEC54D800U, + 0xEC34E000U, + 0xEBF4F000U, + 0xEBB50000U, + 0xEB950800U, + 0xEB551800U, + 0xEB352000U, + 0xEAF53000U, + 0xEAB54000U, + 0xEA954800U, + 0xEA555800U, + 0xEA156000U, + 0xE9F57000U, + 0xE9B58000U, + 0xE9958800U, + 0xE9559800U, + 0xE915A000U, + 0xE8F5B000U, + 0xE8B5C000U, + 0xE875C800U, + 0xE855D800U, + 0xE815E000U, + 0xE7F5F000U, + 0xE7B60000U, + 0xE7760800U, + 0xE7561800U, + 0xE7162000U, + 0xE6D63000U, + 0xE6B64000U, + 0xE6764800U, + 0xE6365800U +}; + +#define FLAGS 0x40080100 +#define READUV(U,V) (tables[256 + (U)] + tables[512 + (V)]) +#define READY(Y) tables[Y] +#define FIXUP(Y) \ +do { \ + int tmp = (Y) & FLAGS; \ + if (tmp != 0) \ + { \ + tmp -= tmp>>8; \ + (Y) |= tmp; \ + tmp = FLAGS & ~(Y>>1); \ + (Y) += tmp>>8; \ + } \ +} while (0 == 1) + +#define STORE(Y,DSTPTR) \ +do { \ + *(DSTPTR)++ = (Y); \ + *(DSTPTR)++ = (Y)>>22; \ + *(DSTPTR)++ = (Y)>>11; \ + *(DSTPTR)++ = 255; \ +} while (0 == 1) + +static void yuv422_2_rgb8888(uint8_t *dst_ptr, + const uint8_t *y_ptr, + const uint8_t *u_ptr, + const uint8_t *v_ptr, + int32_t width, + int32_t height, + int32_t y_span, + int32_t uv_span, + int32_t dst_span, + int32_t dither) +{ + height -= 1; + while (height > 0) + { + height -= width<<16; + height += 1<<16; + while (height < 0) + { + /* Do top row pair */ + uint32_t uv, y0, y1; + + uv = READUV(*u_ptr++,*v_ptr++); + y0 = uv + READY(*y_ptr++); + y1 = uv + READY(*y_ptr++); + FIXUP(y0); + FIXUP(y1); + STORE(y0, dst_ptr); + STORE(y1, dst_ptr); + height += (2<<16); + } + if ((height>>16) == 0) + { + /* Trailing top row pix */ + uint32_t uv, y0; + + uv = READUV(*u_ptr,*v_ptr); + y0 = uv + READY(*y_ptr++); + FIXUP(y0); + STORE(y0, dst_ptr); + } + dst_ptr += dst_span-width*4; + y_ptr += y_span-width; + u_ptr += uv_span-(width>>1); + v_ptr += uv_span-(width>>1); + height = (height<<16)>>16; + height -= 1; + if (height == 0) + break; + height -= width<<16; + height += 1<<16; + while (height < 0) + { + /* Do second row pair */ + uint32_t uv, y0, y1; + + uv = READUV(*u_ptr++,*v_ptr++); + y0 = uv + READY(*y_ptr++); + y1 = uv + READY(*y_ptr++); + FIXUP(y0); + FIXUP(y1); + STORE(y0, dst_ptr); + STORE(y1, dst_ptr); + height += (2<<16); + } + if ((height>>16) == 0) + { + /* Trailing bottom row pix */ + uint32_t uv, y0; + + uv = READUV(*u_ptr,*v_ptr); + y0 = uv + READY(*y_ptr++); + FIXUP(y0); + STORE(y0, dst_ptr); + } + dst_ptr += dst_span-width*4; + y_ptr += y_span-width; + u_ptr += uv_span-(width>>1); + v_ptr += uv_span-(width>>1); + height = (height<<16)>>16; + height -= 1; + } +} + + +#undef FLAGS +#undef READUV +#undef READY +#undef FIXUP +#undef STORE + + +#define FLAGS 0x40080100 +#define READUV(U,V) (tables[256 + (U)] + tables[512 + (V)]) +#define READY(Y) tables[Y] +#define FIXUP(Y) \ +do { \ + int tmp = (Y) & FLAGS; \ + if (tmp != 0) \ + { \ + tmp -= tmp>>8; \ + (Y) |= tmp; \ + tmp = FLAGS & ~(Y>>1); \ + (Y) += tmp>>8; \ + } \ +} while (0 == 1) + +#define STORE(Y,DSTPTR) \ +do { \ + (DSTPTR) = 0xFF000000 | (Y & 0xFF) | (0xFF00 & (Y>>14)) | (0xFF0000 & (Y<<5));\ +} while (0 == 1) + +static void yuv420_2_rgb8888(uint8_t *dst_ptr_, + const uint8_t *y_ptr, + const uint8_t *u_ptr, + const uint8_t *v_ptr, + int32_t width, + int32_t height, + int32_t y_span, + int32_t uv_span, + int32_t dst_span, + int32_t dither) +{ + uint32_t *dst_ptr = (uint32_t *)(void *)dst_ptr_; + dst_span >>= 2; + + height -= 1; + while (height > 0) + { + height -= width<<16; + height += 1<<16; + while (height < 0) + { + /* Do 2 column pairs */ + uint32_t uv, y0, y1; + + uv = READUV(*u_ptr++,*v_ptr++); + y1 = uv + READY(y_ptr[y_span]); + y0 = uv + READY(*y_ptr++); + FIXUP(y1); + FIXUP(y0); + STORE(y1, dst_ptr[dst_span]); + STORE(y0, *dst_ptr++); + y1 = uv + READY(y_ptr[y_span]); + y0 = uv + READY(*y_ptr++); + FIXUP(y1); + FIXUP(y0); + STORE(y1, dst_ptr[dst_span]); + STORE(y0, *dst_ptr++); + height += (2<<16); + } + if ((height>>16) == 0) + { + /* Trailing column pair */ + uint32_t uv, y0, y1; + + uv = READUV(*u_ptr,*v_ptr); + y1 = uv + READY(y_ptr[y_span]); + y0 = uv + READY(*y_ptr++); + FIXUP(y1); + FIXUP(y0); + STORE(y0, dst_ptr[dst_span]); + STORE(y1, *dst_ptr++); + } + dst_ptr += dst_span*2-width; + y_ptr += y_span*2-width; + u_ptr += uv_span-(width>>1); + v_ptr += uv_span-(width>>1); + height = (height<<16)>>16; + height -= 2; + } + if (height == 0) + { + /* Trail row */ + height -= width<<16; + height += 1<<16; + while (height < 0) + { + /* Do a row pair */ + uint32_t uv, y0, y1; + + uv = READUV(*u_ptr++,*v_ptr++); + y1 = uv + READY(*y_ptr++); + y0 = uv + READY(*y_ptr++); + FIXUP(y1); + FIXUP(y0); + STORE(y1, *dst_ptr++); + STORE(y0, *dst_ptr++); + height += (2<<16); + } + if ((height>>16) == 0) + { + /* Trailing pix */ + uint32_t uv, y0; + + uv = READUV(*u_ptr++,*v_ptr++); + y0 = uv + READY(*y_ptr++); + FIXUP(y0); + STORE(y0, *dst_ptr++); + } + } +} + + + +#undef FLAGS +#undef READUV +#undef READY +#undef FIXUP +#undef STORE + +#define FLAGS 0x40080100 +#define READUV(U,V) (tables[256 + (U)] + tables[512 + (V)]) +#define READY(Y) tables[Y] +#define FIXUP(Y) \ +do { \ + int tmp = (Y) & FLAGS; \ + if (tmp != 0) \ + { \ + tmp -= tmp>>8; \ + (Y) |= tmp; \ + tmp = FLAGS & ~(Y>>1); \ + (Y) += tmp>>8; \ + } \ +} while (0 == 1) + +#define STORE(Y,DSTPTR) \ +do { \ + *(DSTPTR)++ = (Y); \ + *(DSTPTR)++ = (Y)>>22; \ + *(DSTPTR)++ = (Y)>>11; \ + *(DSTPTR)++ = 255; \ +} while (0 == 1) + +static void yuv444_2_rgb8888(uint8_t *dst_ptr, + const uint8_t *y_ptr, + const uint8_t *u_ptr, + const uint8_t *v_ptr, + int32_t width, + int32_t height, + int32_t y_span, + int32_t uv_span, + int32_t dst_span, + int32_t dither) +{ + height -= 1; + while (height > 0) + { + height -= width<<16; + height += 1<<16; + while (height < 0) + { + /* Do top row pair */ + uint32_t uv, y0, y1; + + uv = READUV(*u_ptr++,*v_ptr++); + y0 = uv + READY(*y_ptr++); + FIXUP(y0); + STORE(y0, dst_ptr); + uv = READUV(*u_ptr++,*v_ptr++); + y1 = uv + READY(*y_ptr++); + FIXUP(y1); + STORE(y1, dst_ptr); + height += (2<<16); + } + if ((height>>16) == 0) + { + /* Trailing top row pix */ + uint32_t uv, y0; + + uv = READUV(*u_ptr++,*v_ptr++); + y0 = uv + READY(*y_ptr++); + FIXUP(y0); + STORE(y0, dst_ptr); + } + dst_ptr += dst_span-width*4; + y_ptr += y_span-width; + u_ptr += uv_span-width; + v_ptr += uv_span-width; + height = (height<<16)>>16; + height -= 1; + if (height == 0) + break; + height -= width<<16; + height += 1<<16; + while (height < 0) + { + /* Do second row pair */ + uint32_t uv, y0, y1; + + uv = READUV(*u_ptr++,*v_ptr++); + y0 = uv + READY(*y_ptr++); + FIXUP(y0); + STORE(y0, dst_ptr); + uv = READUV(*u_ptr++,*v_ptr++); + y1 = uv + READY(*y_ptr++); + FIXUP(y1); + STORE(y1, dst_ptr); + height += (2<<16); + } + if ((height>>16) == 0) + { + /* Trailing bottom row pix */ + uint32_t uv, y0; + + uv = READUV(*u_ptr++,*v_ptr++); + y0 = uv + READY(*y_ptr++); + FIXUP(y0); + STORE(y0, dst_ptr); + } + dst_ptr += dst_span-width*4; + y_ptr += y_span-width; + u_ptr += uv_span-width; + v_ptr += uv_span-width; + height = (height<<16)>>16; + height -= 1; + } +} +#endif // YUV2RGB_H diff --git a/modules/visual_script/SCsub b/modules/visual_script/SCsub index 403fe68f66..0882406761 100644 --- a/modules/visual_script/SCsub +++ b/modules/visual_script/SCsub @@ -1,5 +1,7 @@ +#!/usr/bin/env python + Import('env') -env.add_source_files(env.modules_sources,"*.cpp") +env.add_source_files(env.modules_sources, "*.cpp") Export('env') diff --git a/modules/visual_script/config.py b/modules/visual_script/config.py index ea7e83378a..5698a37295 100644 --- a/modules/visual_script/config.py +++ b/modules/visual_script/config.py @@ -1,11 +1,8 @@ def can_build(platform): - return True + return True def configure(env): - pass - - - + pass diff --git a/modules/visual_script/register_types.cpp b/modules/visual_script/register_types.cpp index ad54149b51..5fe87a4956 100644 --- a/modules/visual_script/register_types.cpp +++ b/modules/visual_script/register_types.cpp @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -48,58 +48,58 @@ void register_visual_script_types() { //script_language_gd->init(); ScriptServer::register_language(visual_script_language); - ObjectTypeDB::register_type<VisualScript>(); - ObjectTypeDB::register_virtual_type<VisualScriptNode>(); - ObjectTypeDB::register_virtual_type<VisualScriptFunctionState>(); - ObjectTypeDB::register_type<VisualScriptFunction>(); - ObjectTypeDB::register_type<VisualScriptOperator>(); - ObjectTypeDB::register_type<VisualScriptVariableSet>(); - ObjectTypeDB::register_type<VisualScriptVariableGet>(); - ObjectTypeDB::register_type<VisualScriptConstant>(); - ObjectTypeDB::register_type<VisualScriptIndexGet>(); - ObjectTypeDB::register_type<VisualScriptIndexSet>(); - ObjectTypeDB::register_type<VisualScriptGlobalConstant>(); - ObjectTypeDB::register_type<VisualScriptClassConstant>(); - ObjectTypeDB::register_type<VisualScriptMathConstant>(); - ObjectTypeDB::register_type<VisualScriptBasicTypeConstant>(); - ObjectTypeDB::register_type<VisualScriptEngineSingleton>(); - ObjectTypeDB::register_type<VisualScriptSceneNode>(); - ObjectTypeDB::register_type<VisualScriptSceneTree>(); - ObjectTypeDB::register_type<VisualScriptResourcePath>(); - ObjectTypeDB::register_type<VisualScriptSelf>(); - ObjectTypeDB::register_type<VisualScriptCustomNode>(); - ObjectTypeDB::register_type<VisualScriptSubCall>(); - ObjectTypeDB::register_type<VisualScriptComment>(); - ObjectTypeDB::register_type<VisualScriptConstructor>(); - ObjectTypeDB::register_type<VisualScriptLocalVar>(); - ObjectTypeDB::register_type<VisualScriptLocalVarSet>(); - ObjectTypeDB::register_type<VisualScriptInputAction>(); - ObjectTypeDB::register_type<VisualScriptDeconstruct>(); - ObjectTypeDB::register_type<VisualScriptPreload>(); - ObjectTypeDB::register_type<VisualScriptTypeCast>(); - - - ObjectTypeDB::register_type<VisualScriptFunctionCall>(); - ObjectTypeDB::register_type<VisualScriptPropertySet>(); - ObjectTypeDB::register_type<VisualScriptPropertyGet>(); -// ObjectTypeDB::register_type<VisualScriptScriptCall>(); - ObjectTypeDB::register_type<VisualScriptEmitSignal>(); - - ObjectTypeDB::register_type<VisualScriptReturn>(); - ObjectTypeDB::register_type<VisualScriptCondition>(); - ObjectTypeDB::register_type<VisualScriptWhile>(); - ObjectTypeDB::register_type<VisualScriptIterator>(); - ObjectTypeDB::register_type<VisualScriptSequence>(); - ObjectTypeDB::register_type<VisualScriptInputFilter>(); - ObjectTypeDB::register_type<VisualScriptSwitch >(); - - ObjectTypeDB::register_type<VisualScriptYield>(); - ObjectTypeDB::register_type<VisualScriptYieldSignal>(); - - ObjectTypeDB::register_type<VisualScriptBuiltinFunc>(); - - - ObjectTypeDB::register_type<VisualScriptExpression>(); + ClassDB::register_class<VisualScript>(); + ClassDB::register_virtual_class<VisualScriptNode>(); + ClassDB::register_virtual_class<VisualScriptFunctionState>(); + ClassDB::register_class<VisualScriptFunction>(); + ClassDB::register_class<VisualScriptOperator>(); + ClassDB::register_class<VisualScriptVariableSet>(); + ClassDB::register_class<VisualScriptVariableGet>(); + ClassDB::register_class<VisualScriptConstant>(); + ClassDB::register_class<VisualScriptIndexGet>(); + ClassDB::register_class<VisualScriptIndexSet>(); + ClassDB::register_class<VisualScriptGlobalConstant>(); + ClassDB::register_class<VisualScriptClassConstant>(); + ClassDB::register_class<VisualScriptMathConstant>(); + ClassDB::register_class<VisualScriptBasicTypeConstant>(); + ClassDB::register_class<VisualScriptEngineSingleton>(); + ClassDB::register_class<VisualScriptSceneNode>(); + ClassDB::register_class<VisualScriptSceneTree>(); + ClassDB::register_class<VisualScriptResourcePath>(); + ClassDB::register_class<VisualScriptSelf>(); + ClassDB::register_class<VisualScriptCustomNode>(); + ClassDB::register_class<VisualScriptSubCall>(); + ClassDB::register_class<VisualScriptComment>(); + ClassDB::register_class<VisualScriptConstructor>(); + ClassDB::register_class<VisualScriptLocalVar>(); + ClassDB::register_class<VisualScriptLocalVarSet>(); + ClassDB::register_class<VisualScriptInputAction>(); + ClassDB::register_class<VisualScriptDeconstruct>(); + ClassDB::register_class<VisualScriptPreload>(); + ClassDB::register_class<VisualScriptTypeCast>(); + + + ClassDB::register_class<VisualScriptFunctionCall>(); + ClassDB::register_class<VisualScriptPropertySet>(); + ClassDB::register_class<VisualScriptPropertyGet>(); + //ClassDB::register_type<VisualScriptScriptCall>(); + ClassDB::register_class<VisualScriptEmitSignal>(); + + ClassDB::register_class<VisualScriptReturn>(); + ClassDB::register_class<VisualScriptCondition>(); + ClassDB::register_class<VisualScriptWhile>(); + ClassDB::register_class<VisualScriptIterator>(); + ClassDB::register_class<VisualScriptSequence>(); + ClassDB::register_class<VisualScriptInputFilter>(); + ClassDB::register_class<VisualScriptSwitch >(); + + ClassDB::register_class<VisualScriptYield>(); + ClassDB::register_class<VisualScriptYieldSignal>(); + + ClassDB::register_class<VisualScriptBuiltinFunc>(); + + + ClassDB::register_class<VisualScriptExpression>(); register_visual_script_nodes(); register_visual_script_func_nodes(); diff --git a/modules/visual_script/register_types.h b/modules/visual_script/register_types.h index 0a5805eb0b..f6904420bd 100644 --- a/modules/visual_script/register_types.h +++ b/modules/visual_script/register_types.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp index 4de593760d..6941ed5486 100644 --- a/modules/visual_script/visual_script.cpp +++ b/modules/visual_script/visual_script.cpp @@ -2,7 +2,7 @@ #include "visual_script_nodes.h" #include "scene/main/node.h" #include "os/os.h" -#include "globals.h" +#include "global_config.h" @@ -104,13 +104,13 @@ Array VisualScriptNode::_get_default_input_values() const { void VisualScriptNode::_bind_methods() { - ObjectTypeDB::bind_method(_MD("get_visual_script:VisualScript"),&VisualScriptNode::get_visual_script); - ObjectTypeDB::bind_method(_MD("set_default_input_value","port_idx","value:Variant"),&VisualScriptNode::set_default_input_value); - ObjectTypeDB::bind_method(_MD("get_default_input_value:Variant","port_idx"),&VisualScriptNode::get_default_input_value); - ObjectTypeDB::bind_method(_MD("_set_default_input_values","values"),&VisualScriptNode::_set_default_input_values); - ObjectTypeDB::bind_method(_MD("_get_default_input_values"),&VisualScriptNode::_get_default_input_values); + ClassDB::bind_method(D_METHOD("get_visual_script:VisualScript"),&VisualScriptNode::get_visual_script); + ClassDB::bind_method(D_METHOD("set_default_input_value","port_idx","value:Variant"),&VisualScriptNode::set_default_input_value); + ClassDB::bind_method(D_METHOD("get_default_input_value:Variant","port_idx"),&VisualScriptNode::get_default_input_value); + ClassDB::bind_method(D_METHOD("_set_default_input_values","values"),&VisualScriptNode::_set_default_input_values); + ClassDB::bind_method(D_METHOD("_get_default_input_values"),&VisualScriptNode::_get_default_input_values); - ADD_PROPERTY(PropertyInfo(Variant::ARRAY,"_default_input_values",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_default_input_values"),_SCS("_get_default_input_values")); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY,"_default_input_values",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),"_set_default_input_values","_get_default_input_values"); ADD_SIGNAL(MethodInfo("ports_changed")); } @@ -122,7 +122,7 @@ VisualScriptNode::TypeGuess VisualScriptNode::guess_output_type(TypeGuess* p_inp tg.type=pinfo.type; if (pinfo.hint==PROPERTY_HINT_RESOURCE_TYPE) { - tg.obj_type=pinfo.hint_string; + tg.GDCLASS=pinfo.hint_string; } return tg; @@ -1130,6 +1130,7 @@ void VisualScript::get_script_property_list(List<PropertyInfo> *p_list) const { } } +#ifdef TOOLS_ENABLED bool VisualScript::are_subnodes_edited() const { for(const Map<StringName,Function>::Element *E=functions.front();E;E=E->next()) { @@ -1143,7 +1144,7 @@ bool VisualScript::are_subnodes_edited() const { return false; } - +#endif void VisualScript::_set_data(const Dictionary& p_data) { @@ -1316,65 +1317,65 @@ void VisualScript::_bind_methods() { - ObjectTypeDB::bind_method(_MD("_node_ports_changed"),&VisualScript::_node_ports_changed); + ClassDB::bind_method(D_METHOD("_node_ports_changed"),&VisualScript::_node_ports_changed); - ObjectTypeDB::bind_method(_MD("add_function","name"),&VisualScript::add_function); - ObjectTypeDB::bind_method(_MD("has_function","name"),&VisualScript::has_function); - ObjectTypeDB::bind_method(_MD("remove_function","name"),&VisualScript::remove_function); - ObjectTypeDB::bind_method(_MD("rename_function","name","new_name"),&VisualScript::rename_function); - ObjectTypeDB::bind_method(_MD("set_function_scroll","ofs"),&VisualScript::set_function_scroll); - ObjectTypeDB::bind_method(_MD("get_function_scroll"),&VisualScript::get_function_scroll); + ClassDB::bind_method(D_METHOD("add_function","name"),&VisualScript::add_function); + ClassDB::bind_method(D_METHOD("has_function","name"),&VisualScript::has_function); + ClassDB::bind_method(D_METHOD("remove_function","name"),&VisualScript::remove_function); + ClassDB::bind_method(D_METHOD("rename_function","name","new_name"),&VisualScript::rename_function); + ClassDB::bind_method(D_METHOD("set_function_scroll","ofs"),&VisualScript::set_function_scroll); + ClassDB::bind_method(D_METHOD("get_function_scroll"),&VisualScript::get_function_scroll); - ObjectTypeDB::bind_method(_MD("add_node","func","id","node","pos"),&VisualScript::add_node,DEFVAL(Point2())); - ObjectTypeDB::bind_method(_MD("remove_node","func","id"),&VisualScript::remove_node); - ObjectTypeDB::bind_method(_MD("get_function_node_id","name"),&VisualScript::get_function_node_id); + ClassDB::bind_method(D_METHOD("add_node","func","id","node","pos"),&VisualScript::add_node,DEFVAL(Point2())); + ClassDB::bind_method(D_METHOD("remove_node","func","id"),&VisualScript::remove_node); + ClassDB::bind_method(D_METHOD("get_function_node_id","name"),&VisualScript::get_function_node_id); - ObjectTypeDB::bind_method(_MD("get_node","func","id"),&VisualScript::get_node); - ObjectTypeDB::bind_method(_MD("has_node","func","id"),&VisualScript::has_node); - ObjectTypeDB::bind_method(_MD("set_node_pos","func","id","pos"),&VisualScript::set_node_pos); - ObjectTypeDB::bind_method(_MD("get_node_pos","func","id"),&VisualScript::get_node_pos); + ClassDB::bind_method(D_METHOD("get_node","func","id"),&VisualScript::get_node); + ClassDB::bind_method(D_METHOD("has_node","func","id"),&VisualScript::has_node); + ClassDB::bind_method(D_METHOD("set_node_pos","func","id","pos"),&VisualScript::set_node_pos); + ClassDB::bind_method(D_METHOD("get_node_pos","func","id"),&VisualScript::get_node_pos); - ObjectTypeDB::bind_method(_MD("sequence_connect","func","from_node","from_output","to_node"),&VisualScript::sequence_connect); - ObjectTypeDB::bind_method(_MD("sequence_disconnect","func","from_node","from_output","to_node"),&VisualScript::sequence_disconnect); - ObjectTypeDB::bind_method(_MD("has_sequence_connection","func","from_node","from_output","to_node"),&VisualScript::has_sequence_connection); + ClassDB::bind_method(D_METHOD("sequence_connect","func","from_node","from_output","to_node"),&VisualScript::sequence_connect); + ClassDB::bind_method(D_METHOD("sequence_disconnect","func","from_node","from_output","to_node"),&VisualScript::sequence_disconnect); + ClassDB::bind_method(D_METHOD("has_sequence_connection","func","from_node","from_output","to_node"),&VisualScript::has_sequence_connection); - ObjectTypeDB::bind_method(_MD("data_connect","func","from_node","from_port","to_node","to_port"),&VisualScript::data_connect); - ObjectTypeDB::bind_method(_MD("data_disconnect","func","from_node","from_port","to_node","to_port"),&VisualScript::data_disconnect); - ObjectTypeDB::bind_method(_MD("has_data_connection","func","from_node","from_port","to_node","to_port"),&VisualScript::has_data_connection); + ClassDB::bind_method(D_METHOD("data_connect","func","from_node","from_port","to_node","to_port"),&VisualScript::data_connect); + ClassDB::bind_method(D_METHOD("data_disconnect","func","from_node","from_port","to_node","to_port"),&VisualScript::data_disconnect); + ClassDB::bind_method(D_METHOD("has_data_connection","func","from_node","from_port","to_node","to_port"),&VisualScript::has_data_connection); - ObjectTypeDB::bind_method(_MD("add_variable","name","default_value","export"),&VisualScript::add_variable,DEFVAL(Variant()),DEFVAL(false)); - ObjectTypeDB::bind_method(_MD("has_variable","name"),&VisualScript::has_variable); - ObjectTypeDB::bind_method(_MD("remove_variable","name"),&VisualScript::remove_variable); - ObjectTypeDB::bind_method(_MD("set_variable_default_value","name","value"),&VisualScript::set_variable_default_value); - ObjectTypeDB::bind_method(_MD("get_variable_default_value","name"),&VisualScript::get_variable_default_value); - ObjectTypeDB::bind_method(_MD("set_variable_info","name","value"),&VisualScript::_set_variable_info); - ObjectTypeDB::bind_method(_MD("get_variable_info","name"),&VisualScript::_get_variable_info); - ObjectTypeDB::bind_method(_MD("set_variable_export","name","enable"),&VisualScript::set_variable_export); - ObjectTypeDB::bind_method(_MD("get_variable_export","name"),&VisualScript::get_variable_export); - ObjectTypeDB::bind_method(_MD("rename_variable","name","new_name"),&VisualScript::rename_variable); + ClassDB::bind_method(D_METHOD("add_variable","name","default_value","export"),&VisualScript::add_variable,DEFVAL(Variant()),DEFVAL(false)); + ClassDB::bind_method(D_METHOD("has_variable","name"),&VisualScript::has_variable); + ClassDB::bind_method(D_METHOD("remove_variable","name"),&VisualScript::remove_variable); + ClassDB::bind_method(D_METHOD("set_variable_default_value","name","value"),&VisualScript::set_variable_default_value); + ClassDB::bind_method(D_METHOD("get_variable_default_value","name"),&VisualScript::get_variable_default_value); + ClassDB::bind_method(D_METHOD("set_variable_info","name","value"),&VisualScript::_set_variable_info); + ClassDB::bind_method(D_METHOD("get_variable_info","name"),&VisualScript::_get_variable_info); + ClassDB::bind_method(D_METHOD("set_variable_export","name","enable"),&VisualScript::set_variable_export); + ClassDB::bind_method(D_METHOD("get_variable_export","name"),&VisualScript::get_variable_export); + ClassDB::bind_method(D_METHOD("rename_variable","name","new_name"),&VisualScript::rename_variable); - ObjectTypeDB::bind_method(_MD("add_custom_signal","name"),&VisualScript::add_custom_signal); - ObjectTypeDB::bind_method(_MD("has_custom_signal","name"),&VisualScript::has_custom_signal); - ObjectTypeDB::bind_method(_MD("custom_signal_add_argument","name","type","argname","index"),&VisualScript::custom_signal_add_argument,DEFVAL(-1)); - ObjectTypeDB::bind_method(_MD("custom_signal_set_argument_type","name","argidx","type"),&VisualScript::custom_signal_set_argument_type); - ObjectTypeDB::bind_method(_MD("custom_signal_get_argument_type","name","argidx"),&VisualScript::custom_signal_get_argument_type); - ObjectTypeDB::bind_method(_MD("custom_signal_set_argument_name","name","argidx","argname"),&VisualScript::custom_signal_set_argument_name); - ObjectTypeDB::bind_method(_MD("custom_signal_get_argument_name","name","argidx"),&VisualScript::custom_signal_get_argument_name); - ObjectTypeDB::bind_method(_MD("custom_signal_remove_argument","argidx"),&VisualScript::custom_signal_remove_argument); - ObjectTypeDB::bind_method(_MD("custom_signal_get_argument_count","name"),&VisualScript::custom_signal_get_argument_count); - ObjectTypeDB::bind_method(_MD("custom_signal_swap_argument","name","argidx","withidx"),&VisualScript::custom_signal_swap_argument); - ObjectTypeDB::bind_method(_MD("remove_custom_signal","name"),&VisualScript::remove_custom_signal); - ObjectTypeDB::bind_method(_MD("rename_custom_signal","name","new_name"),&VisualScript::rename_custom_signal); + ClassDB::bind_method(D_METHOD("add_custom_signal","name"),&VisualScript::add_custom_signal); + ClassDB::bind_method(D_METHOD("has_custom_signal","name"),&VisualScript::has_custom_signal); + ClassDB::bind_method(D_METHOD("custom_signal_add_argument","name","type","argname","index"),&VisualScript::custom_signal_add_argument,DEFVAL(-1)); + ClassDB::bind_method(D_METHOD("custom_signal_set_argument_type","name","argidx","type"),&VisualScript::custom_signal_set_argument_type); + ClassDB::bind_method(D_METHOD("custom_signal_get_argument_type","name","argidx"),&VisualScript::custom_signal_get_argument_type); + ClassDB::bind_method(D_METHOD("custom_signal_set_argument_name","name","argidx","argname"),&VisualScript::custom_signal_set_argument_name); + ClassDB::bind_method(D_METHOD("custom_signal_get_argument_name","name","argidx"),&VisualScript::custom_signal_get_argument_name); + ClassDB::bind_method(D_METHOD("custom_signal_remove_argument","argidx"),&VisualScript::custom_signal_remove_argument); + ClassDB::bind_method(D_METHOD("custom_signal_get_argument_count","name"),&VisualScript::custom_signal_get_argument_count); + ClassDB::bind_method(D_METHOD("custom_signal_swap_argument","name","argidx","withidx"),&VisualScript::custom_signal_swap_argument); + ClassDB::bind_method(D_METHOD("remove_custom_signal","name"),&VisualScript::remove_custom_signal); + ClassDB::bind_method(D_METHOD("rename_custom_signal","name","new_name"),&VisualScript::rename_custom_signal); - //ObjectTypeDB::bind_method(_MD("set_variable_info","name","info"),&VScript::set_variable_info); - //ObjectTypeDB::bind_method(_MD("get_variable_info","name"),&VScript::set_variable_info); + //ClassDB::bind_method(D_METHOD("set_variable_info","name","info"),&VScript::set_variable_info); + //ClassDB::bind_method(D_METHOD("get_variable_info","name"),&VScript::set_variable_info); - ObjectTypeDB::bind_method(_MD("set_instance_base_type","type"),&VisualScript::set_instance_base_type); + ClassDB::bind_method(D_METHOD("set_instance_base_type","type"),&VisualScript::set_instance_base_type); - ObjectTypeDB::bind_method(_MD("_set_data","data"),&VisualScript::_set_data); - ObjectTypeDB::bind_method(_MD("_get_data"),&VisualScript::_get_data); + ClassDB::bind_method(D_METHOD("_set_data","data"),&VisualScript::_set_data); + ClassDB::bind_method(D_METHOD("_get_data"),&VisualScript::_get_data); - ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY,"data",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_data"),_SCS("_get_data")); + ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY,"data",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),"_set_data","_get_data"); ADD_SIGNAL(MethodInfo("node_ports_changed",PropertyInfo(Variant::STRING,"function"),PropertyInfo(Variant::INT,"id"))); } @@ -1416,7 +1417,8 @@ bool VisualScriptInstance::get(const StringName& p_name, Variant &r_ret) const { if (!E) return false; - return E->get(); + r_ret=E->get(); + return true; } void VisualScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const{ @@ -1571,7 +1573,7 @@ Variant VisualScriptInstance::_call_internal(const StringName& p_method, void* p p_pass++; //increment pass current_node_id=node->get_id(); - VSDEBUG("==========AT NODE: "+itos(current_node_id)+" base: "+node->get_base_node()->get_type()); + VSDEBUG("==========AT NODE: "+itos(current_node_id)+" base: "+node->get_base_node()->get_class_name()); VSDEBUG("AT STACK POS: "+itos(flow_stack_pos)); @@ -2434,10 +2436,10 @@ Variant VisualScriptFunctionState::resume(Array p_args) { void VisualScriptFunctionState::_bind_methods() { - ObjectTypeDB::bind_method(_MD("connect_to_signal","obj","signals","args"),&VisualScriptFunctionState::connect_to_signal); - ObjectTypeDB::bind_method(_MD("resume:Array","args"),&VisualScriptFunctionState::resume,DEFVAL(Variant())); - ObjectTypeDB::bind_method(_MD("is_valid"),&VisualScriptFunctionState::is_valid); - ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"_signal_callback",&VisualScriptFunctionState::_signal_callback,MethodInfo("_signal_callback")); + ClassDB::bind_method(D_METHOD("connect_to_signal","obj","signals","args"),&VisualScriptFunctionState::connect_to_signal); + ClassDB::bind_method(D_METHOD("resume:Array","args"),&VisualScriptFunctionState::resume,DEFVAL(Variant())); + ClassDB::bind_method(D_METHOD("is_valid"),&VisualScriptFunctionState::is_valid); + ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT,"_signal_callback",&VisualScriptFunctionState::_signal_callback,MethodInfo("_signal_callback")); } VisualScriptFunctionState::VisualScriptFunctionState() { @@ -2523,7 +2525,7 @@ int VisualScriptLanguage::find_function(const String& p_function,const String& p return -1; } -String VisualScriptLanguage::make_function(const String& p_class,const String& p_name,const StringArray& p_args) const { +String VisualScriptLanguage::make_function(const String& p_class,const String& p_name,const PoolStringArray& p_args) const { return String(); } @@ -2629,7 +2631,7 @@ void VisualScriptLanguage::debug_get_stack_level_locals(int p_level,List<String> const StringName *f = _call_stack[l].function; ERR_FAIL_COND(!_call_stack[l].instance->functions.has(*f)); -// VisualScriptInstance::Function *func = &_call_stack[l].instance->functions[*f]; + //VisualScriptInstance::Function *func = &_call_stack[l].instance->functions[*f]; VisualScriptNodeInstance *node =_call_stack[l].instance->instances[*_call_stack[l].current_id]; ERR_FAIL_COND(!node); @@ -2813,7 +2815,7 @@ VisualScriptLanguage::VisualScriptLanguage() { _debug_parse_err_node=-1; _debug_parse_err_file=""; _debug_call_stack_pos=0; - int dmcs=GLOBAL_DEF("debug/script_max_call_stack",1024); + int dmcs=GLOBAL_DEF("debug/script/max_call_stack",1024); if (ScriptDebugger::get_singleton()) { //debugging enabled! _debug_max_call_stack = dmcs; diff --git a/modules/visual_script/visual_script.h b/modules/visual_script/visual_script.h index 794230d694..acd1c3a670 100644 --- a/modules/visual_script/visual_script.h +++ b/modules/visual_script/visual_script.h @@ -9,7 +9,7 @@ class VisualScriptNodeInstance; class VisualScript; class VisualScriptNode : public Resource { - OBJ_TYPE(VisualScriptNode,Resource) + GDCLASS(VisualScriptNode,Resource) friend class VisualScript; @@ -24,8 +24,6 @@ friend class VisualScript; void validate_input_default_values(); protected: - virtual bool _use_builtin_script() const { return false; } - void _notification(int p_what); void ports_changed_notify(); static void _bind_methods(); @@ -64,7 +62,7 @@ public: Variant::Type type; InputEvent::Type ev_type; - StringName obj_type; + StringName GDCLASS; Ref<Script> script; TypeGuess() { type=Variant::NIL; ev_type=InputEvent::NONE; } @@ -143,7 +141,7 @@ public: class VisualScript : public Script { - OBJ_TYPE( VisualScript, Script ) + GDCLASS( VisualScript, Script ) RES_BASE_EXTENSION("vs"); @@ -344,7 +342,9 @@ public: virtual void get_script_property_list(List<PropertyInfo> *p_list) const; +#ifdef TOOLS_ENABLED virtual bool are_subnodes_edited() const; +#endif VisualScript(); ~VisualScript(); @@ -435,7 +435,7 @@ public: class VisualScriptFunctionState : public Reference { - OBJ_TYPE(VisualScriptFunctionState,Reference); + GDCLASS(VisualScriptFunctionState,Reference); friend class VisualScriptInstance; ObjectID instance_id; @@ -560,7 +560,7 @@ public: virtual Script *create_script() const; virtual bool has_named_classes() const; virtual int find_function(const String& p_function,const String& p_code) const; - virtual String make_function(const String& p_class,const String& p_name,const StringArray& p_args) const; + virtual String make_function(const String& p_class,const String& p_name,const PoolStringArray& p_args) const; virtual void auto_indent_code(String& p_code,int p_from_line,int p_to_line) const; virtual void add_global_constant(const StringName& p_variable,const Variant& p_value); diff --git a/modules/visual_script/visual_script_builtin_funcs.cpp b/modules/visual_script/visual_script_builtin_funcs.cpp index 1d0bca0b30..cae0146aac 100644 --- a/modules/visual_script/visual_script_builtin_funcs.cpp +++ b/modules/visual_script/visual_script_builtin_funcs.cpp @@ -1,6 +1,6 @@ #include "visual_script_builtin_funcs.h" #include "math_funcs.h" -#include "object_type_db.h" +#include "class_db.h" #include "reference.h" #include "func_ref.h" #include "os/os.h" @@ -55,6 +55,7 @@ const char* VisualScriptBuiltinFunc::func_name[VisualScriptBuiltinFunc::FUNC_MAX "convert", "typeof", "type_exists", + "char", "str", "print", "printerr", @@ -63,8 +64,24 @@ const char* VisualScriptBuiltinFunc::func_name[VisualScriptBuiltinFunc::FUNC_MAX "str2var", "var2bytes", "bytes2var", + "color_named", }; +VisualScriptBuiltinFunc::BuiltinFunc VisualScriptBuiltinFunc::find_function(const String& p_string) { + + for(int i=0;i<FUNC_MAX;i++) { + if (p_string==func_name[i]) + return BuiltinFunc(i); + } + + return FUNC_MAX; +} + +String VisualScriptBuiltinFunc::get_func_name(BuiltinFunc p_func) { + + ERR_FAIL_INDEX_V(p_func,FUNC_MAX,String()); + return func_name[p_func]; +} int VisualScriptBuiltinFunc::get_output_sequence_port_count() const { @@ -88,10 +105,10 @@ bool VisualScriptBuiltinFunc::has_input_sequence_port() const{ } -int VisualScriptBuiltinFunc::get_input_value_port_count() const{ +int VisualScriptBuiltinFunc::get_func_argument_count(BuiltinFunc p_func) { - switch(func) { + switch(p_func) { case MATH_RANDOMIZE: case MATH_RAND: @@ -126,6 +143,7 @@ int VisualScriptBuiltinFunc::get_input_value_port_count() const{ case LOGIC_NEAREST_PO2: case OBJ_WEAKREF: case TYPE_OF: + case TEXT_CHAR: case TEXT_STR: case TEXT_PRINT: case TEXT_PRINTERR: @@ -147,6 +165,7 @@ int VisualScriptBuiltinFunc::get_input_value_port_count() const{ case LOGIC_MIN: case FUNC_FUNCREF: case TYPE_CONVERT: + case COLORN: return 2; case MATH_LERP: case MATH_DECTIME: @@ -157,6 +176,11 @@ int VisualScriptBuiltinFunc::get_input_value_port_count() const{ } return 0; } + +int VisualScriptBuiltinFunc::get_input_value_port_count() const{ + + return get_func_argument_count(func); +} int VisualScriptBuiltinFunc::get_output_value_port_count() const{ switch(func) { @@ -342,11 +366,15 @@ PropertyInfo VisualScriptBuiltinFunc::get_input_value_port_info(int p_idx) const return PropertyInfo(Variant::STRING,"type"); } break; + case TEXT_CHAR: { + + return PropertyInfo(Variant::INT,"ascii"); + + } break; case TEXT_STR: { return PropertyInfo(Variant::NIL,"value"); - } break; case TEXT_PRINT: { @@ -376,7 +404,15 @@ PropertyInfo VisualScriptBuiltinFunc::get_input_value_port_info(int p_idx) const } break; case BYTES_TO_VAR: { - return PropertyInfo(Variant::RAW_ARRAY,"bytes"); + return PropertyInfo(Variant::POOL_BYTE_ARRAY,"bytes"); + } break; + case COLORN: { + + if (p_idx==0) + return PropertyInfo(Variant::STRING,"name"); + else + return PropertyInfo(Variant::REAL,"alpha"); + } break; case FUNC_MAX:{} } @@ -497,6 +533,7 @@ PropertyInfo VisualScriptBuiltinFunc::get_output_value_port_info(int p_idx) cons t=Variant::BOOL; } break; + case TEXT_CHAR: case TEXT_STR: { t=Variant::STRING; @@ -519,13 +556,16 @@ PropertyInfo VisualScriptBuiltinFunc::get_output_value_port_info(int p_idx) cons } break; case VAR_TO_BYTES: { - t=Variant::RAW_ARRAY; + t=Variant::POOL_BYTE_ARRAY; } break; case BYTES_TO_VAR: { } break; + case COLORN: { + t=Variant::COLOR; + } break; case FUNC_MAX:{} } @@ -560,118 +600,124 @@ VisualScriptBuiltinFunc::BuiltinFunc VisualScriptBuiltinFunc::get_func() { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;\ r_error.argument=m_arg;\ r_error.expected=Variant::REAL;\ - return 0;\ + return;\ } -class VisualScriptNodeInstanceBuiltinFunc : public VisualScriptNodeInstance { -public: - VisualScriptBuiltinFunc *node; - VisualScriptInstance *instance; +void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func,const Variant** p_inputs,Variant* r_return,Variant::CallError& r_error,String& r_error_str) { - VisualScriptBuiltinFunc::BuiltinFunc func; + switch(p_func) { + case VisualScriptBuiltinFunc::MATH_SIN: { + VALIDATE_ARG_NUM(0); + *r_return=Math::sin((double)*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_COS: { - //virtual int get_working_memory_size() const { return 0; } - //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } - //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } + VALIDATE_ARG_NUM(0); + *r_return=Math::cos((double)*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_TAN: { - virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) { + VALIDATE_ARG_NUM(0); + *r_return=Math::tan((double)*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_SINH: { - switch(func) { - case VisualScriptBuiltinFunc::MATH_SIN: { + VALIDATE_ARG_NUM(0); + *r_return=Math::sinh((double)*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_COSH: { - VALIDATE_ARG_NUM(0); - *p_outputs[0]=Math::sin(*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_COS: { + VALIDATE_ARG_NUM(0); + *r_return=Math::cosh((double)*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_TANH: { - VALIDATE_ARG_NUM(0); - *p_outputs[0]=Math::cos(*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_TAN: { + VALIDATE_ARG_NUM(0); + *r_return=Math::tanh((double)*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_ASIN: { - VALIDATE_ARG_NUM(0); - *p_outputs[0]=Math::tan(*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_SINH: { + VALIDATE_ARG_NUM(0); + *r_return=Math::asin((double)*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_ACOS: { - VALIDATE_ARG_NUM(0); - *p_outputs[0]=Math::sinh(*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_COSH: { + VALIDATE_ARG_NUM(0); + *r_return=Math::acos((double)*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_ATAN: { - VALIDATE_ARG_NUM(0); - *p_outputs[0]=Math::cosh(*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_TANH: { + VALIDATE_ARG_NUM(0); + *r_return=Math::atan((double)*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_ATAN2: { - VALIDATE_ARG_NUM(0); - *p_outputs[0]=Math::tanh(*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_ASIN: { + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + *r_return=Math::atan2((double)*p_inputs[0],(double)*p_inputs[1]); + } break; + case VisualScriptBuiltinFunc::MATH_SQRT: { - VALIDATE_ARG_NUM(0); - *p_outputs[0]=Math::asin(*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_ACOS: { + VALIDATE_ARG_NUM(0); + *r_return=Math::sqrt((double)*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_FMOD: { - VALIDATE_ARG_NUM(0); - *p_outputs[0]=Math::acos(*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_ATAN: { + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + *r_return=Math::fmod((double)*p_inputs[0],(double)*p_inputs[1]); + } break; + case VisualScriptBuiltinFunc::MATH_FPOSMOD: { - VALIDATE_ARG_NUM(0); - *p_outputs[0]=Math::atan(*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_ATAN2: { + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + *r_return=Math::fposmod((double)*p_inputs[0],(double)*p_inputs[1]); + } break; + case VisualScriptBuiltinFunc::MATH_FLOOR: { - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); - *p_outputs[0]=Math::atan2(*p_inputs[0],*p_inputs[1]); - } break; - case VisualScriptBuiltinFunc::MATH_SQRT: { + VALIDATE_ARG_NUM(0); + *r_return=Math::floor((double)*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_CEIL: { - VALIDATE_ARG_NUM(0); - *p_outputs[0]=Math::sqrt(*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_FMOD: { + VALIDATE_ARG_NUM(0); + *r_return=Math::ceil((double)*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_ROUND: { - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); - *p_outputs[0]=Math::fmod(*p_inputs[0],*p_inputs[1]); - } break; - case VisualScriptBuiltinFunc::MATH_FPOSMOD: { + VALIDATE_ARG_NUM(0); + *r_return=Math::round((double)*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_ABS: { - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); - *p_outputs[0]=Math::fposmod(*p_inputs[0],*p_inputs[1]); - } break; - case VisualScriptBuiltinFunc::MATH_FLOOR: { + if (p_inputs[0]->get_type()==Variant::INT) { - VALIDATE_ARG_NUM(0); - *p_outputs[0]=Math::floor(*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_CEIL: { + int64_t i = *p_inputs[0]; + *r_return=ABS(i); + } else if (p_inputs[0]->get_type()==Variant::REAL) { - VALIDATE_ARG_NUM(0); - *p_outputs[0]=Math::ceil(*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_ROUND: { + real_t r = *p_inputs[0]; + *r_return=Math::abs(r); + } else { - VALIDATE_ARG_NUM(0); - *p_outputs[0]=Math::round(*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_ABS: { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=0; + r_error.expected=Variant::REAL; + + } + } break; + case VisualScriptBuiltinFunc::MATH_SIGN: { if (p_inputs[0]->get_type()==Variant::INT) { int64_t i = *p_inputs[0]; - *p_outputs[0]=ABS(i); + *r_return= i < 0 ? -1 : ( i > 0 ? +1 : 0); } else if (p_inputs[0]->get_type()==Variant::REAL) { real_t r = *p_inputs[0]; - *p_outputs[0]=Math::abs(r); + *r_return= r < 0.0 ? -1.0 : ( r > 0.0 ? +1.0 : 0.0); } else { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; @@ -679,410 +725,429 @@ public: r_error.expected=Variant::REAL; } - } break; - case VisualScriptBuiltinFunc::MATH_SIGN: { + } break; + case VisualScriptBuiltinFunc::MATH_POW: { - if (p_inputs[0]->get_type()==Variant::INT) { + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + *r_return=Math::pow((double)*p_inputs[0],(double)*p_inputs[1]); + } break; + case VisualScriptBuiltinFunc::MATH_LOG: { - int64_t i = *p_inputs[0]; - *p_outputs[0]= i < 0 ? -1 : ( i > 0 ? +1 : 0); - } else if (p_inputs[0]->get_type()==Variant::REAL) { + VALIDATE_ARG_NUM(0); + *r_return=Math::log((double)*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_EXP: { - real_t r = *p_inputs[0]; - *p_outputs[0]= r < 0.0 ? -1.0 : ( r > 0.0 ? +1.0 : 0.0); - } else { + VALIDATE_ARG_NUM(0); + *r_return=Math::exp((double)*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_ISNAN: { - r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument=0; - r_error.expected=Variant::REAL; + VALIDATE_ARG_NUM(0); + *r_return=Math::is_nan((double)*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_ISINF: { - } - } break; - case VisualScriptBuiltinFunc::MATH_POW: { + VALIDATE_ARG_NUM(0); + *r_return=Math::is_inf((double)*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_EASE: { - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); - *p_outputs[0]=Math::pow(*p_inputs[0],*p_inputs[1]); - } break; - case VisualScriptBuiltinFunc::MATH_LOG: { + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + *r_return=Math::ease((double)*p_inputs[0],(double)*p_inputs[1]); + } break; + case VisualScriptBuiltinFunc::MATH_DECIMALS: { - VALIDATE_ARG_NUM(0); - *p_outputs[0]=Math::log(*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_EXP: { + VALIDATE_ARG_NUM(0); + *r_return=Math::step_decimals((double)*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_STEPIFY: { - VALIDATE_ARG_NUM(0); - *p_outputs[0]=Math::exp(*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_ISNAN: { + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + *r_return=Math::stepify((double)*p_inputs[0],(double)*p_inputs[1]); + } break; + case VisualScriptBuiltinFunc::MATH_LERP: { - VALIDATE_ARG_NUM(0); - *p_outputs[0]=Math::is_nan(*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_ISINF: { + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + VALIDATE_ARG_NUM(2); + *r_return=Math::lerp((double)*p_inputs[0],(double)*p_inputs[1],(double)*p_inputs[2]); + } break; + case VisualScriptBuiltinFunc::MATH_DECTIME: { - VALIDATE_ARG_NUM(0); - *p_outputs[0]=Math::is_inf(*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_EASE: { + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + VALIDATE_ARG_NUM(2); + *r_return=Math::dectime((double)*p_inputs[0],(double)*p_inputs[1],(double)*p_inputs[2]); + } break; + case VisualScriptBuiltinFunc::MATH_RANDOMIZE: { + Math::randomize(); - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); - *p_outputs[0]=Math::ease(*p_inputs[0],*p_inputs[1]); - } break; - case VisualScriptBuiltinFunc::MATH_DECIMALS: { + } break; + case VisualScriptBuiltinFunc::MATH_RAND: { + *r_return=Math::rand(); + } break; + case VisualScriptBuiltinFunc::MATH_RANDF: { + *r_return=Math::randf(); + } break; + case VisualScriptBuiltinFunc::MATH_RANDOM: { - VALIDATE_ARG_NUM(0); - *p_outputs[0]=Math::step_decimals(*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_STEPIFY: { + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + *r_return=Math::random((double)*p_inputs[0],(double)*p_inputs[1]); + } break; + case VisualScriptBuiltinFunc::MATH_SEED: { - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); - *p_outputs[0]=Math::stepify(*p_inputs[0],*p_inputs[1]); - } break; - case VisualScriptBuiltinFunc::MATH_LERP: { + VALIDATE_ARG_NUM(0); + uint64_t seed=*p_inputs[0]; + Math::seed(seed); - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); - VALIDATE_ARG_NUM(2); - *p_outputs[0]=Math::lerp(*p_inputs[0],*p_inputs[1],*p_inputs[2]); - } break; - case VisualScriptBuiltinFunc::MATH_DECTIME: { + } break; + case VisualScriptBuiltinFunc::MATH_RANDSEED: { - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); - VALIDATE_ARG_NUM(2); - *p_outputs[0]=Math::dectime(*p_inputs[0],*p_inputs[1],*p_inputs[2]); - } break; - case VisualScriptBuiltinFunc::MATH_RANDOMIZE: { - Math::randomize(); - - } break; - case VisualScriptBuiltinFunc::MATH_RAND: { - *p_outputs[0]=Math::rand(); - } break; - case VisualScriptBuiltinFunc::MATH_RANDF: { - *p_outputs[0]=Math::randf(); - } break; - case VisualScriptBuiltinFunc::MATH_RANDOM: { + VALIDATE_ARG_NUM(0); + uint64_t seed=*p_inputs[0]; + int ret = Math::rand_from_seed(&seed); + Array reta; + reta.push_back(ret); + reta.push_back(seed); + *r_return=reta; + + } break; + case VisualScriptBuiltinFunc::MATH_DEG2RAD: { + + VALIDATE_ARG_NUM(0); + *r_return=Math::deg2rad((double)*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_RAD2DEG: { + + VALIDATE_ARG_NUM(0); + *r_return=Math::rad2deg((double)*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_LINEAR2DB: { + + VALIDATE_ARG_NUM(0); + *r_return=Math::linear2db((double)*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_DB2LINEAR: { + + VALIDATE_ARG_NUM(0); + *r_return=Math::db2linear((double)*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::LOGIC_MAX: { + + if (p_inputs[0]->get_type()==Variant::INT && p_inputs[1]->get_type()==Variant::INT) { + int64_t a = *p_inputs[0]; + int64_t b = *p_inputs[1]; + *r_return=MAX(a,b); + } else { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); - *p_outputs[0]=Math::random(*p_inputs[0],*p_inputs[1]); - } break; - case VisualScriptBuiltinFunc::MATH_SEED: { - VALIDATE_ARG_NUM(0); - uint32_t seed=*p_inputs[0]; - Math::seed(seed); + real_t a = *p_inputs[0]; + real_t b = *p_inputs[1]; - } break; - case VisualScriptBuiltinFunc::MATH_RANDSEED: { + *r_return=MAX(a,b); + } - VALIDATE_ARG_NUM(0); - uint32_t seed=*p_inputs[0]; - int ret = Math::rand_from_seed(&seed); - Array reta; - reta.push_back(ret); - reta.push_back(seed); - *p_outputs[0]=reta; + } break; + case VisualScriptBuiltinFunc::LOGIC_MIN: { - } break; - case VisualScriptBuiltinFunc::MATH_DEG2RAD: { + if (p_inputs[0]->get_type()==Variant::INT && p_inputs[1]->get_type()==Variant::INT) { + int64_t a = *p_inputs[0]; + int64_t b = *p_inputs[1]; + *r_return=MIN(a,b); + } else { VALIDATE_ARG_NUM(0); - *p_outputs[0]=Math::deg2rad(*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_RAD2DEG: { + VALIDATE_ARG_NUM(1); - VALIDATE_ARG_NUM(0); - *p_outputs[0]=Math::rad2deg(*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_LINEAR2DB: { + real_t a = *p_inputs[0]; + real_t b = *p_inputs[1]; - VALIDATE_ARG_NUM(0); - *p_outputs[0]=Math::linear2db(*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_DB2LINEAR: { + *r_return=MIN(a,b); + } + } break; + case VisualScriptBuiltinFunc::LOGIC_CLAMP: { - VALIDATE_ARG_NUM(0); - *p_outputs[0]=Math::db2linear(*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::LOGIC_MAX: { + if (p_inputs[0]->get_type()==Variant::INT && p_inputs[1]->get_type()==Variant::INT && p_inputs[2]->get_type()==Variant::INT) { - if (p_inputs[0]->get_type()==Variant::INT && p_inputs[1]->get_type()==Variant::INT) { + int64_t a = *p_inputs[0]; + int64_t b = *p_inputs[1]; + int64_t c = *p_inputs[2]; + *r_return=CLAMP(a,b,c); + } else { + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + VALIDATE_ARG_NUM(2); - int64_t a = *p_inputs[0]; - int64_t b = *p_inputs[1]; - *p_outputs[0]=MAX(a,b); - } else { - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); + real_t a = *p_inputs[0]; + real_t b = *p_inputs[1]; + real_t c = *p_inputs[2]; - real_t a = *p_inputs[0]; - real_t b = *p_inputs[1]; + *r_return=CLAMP(a,b,c); + } + } break; + case VisualScriptBuiltinFunc::LOGIC_NEAREST_PO2: { - *p_outputs[0]=MAX(a,b); - } + VALIDATE_ARG_NUM(0); + int64_t num = *p_inputs[0]; + *r_return = nearest_power_of_2(num); + } break; + case VisualScriptBuiltinFunc::OBJ_WEAKREF: { - } break; - case VisualScriptBuiltinFunc::LOGIC_MIN: { + if (p_inputs[0]->get_type()!=Variant::OBJECT) { - if (p_inputs[0]->get_type()==Variant::INT && p_inputs[1]->get_type()==Variant::INT) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=0; + r_error.expected=Variant::OBJECT; - int64_t a = *p_inputs[0]; - int64_t b = *p_inputs[1]; - *p_outputs[0]=MIN(a,b); - } else { - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); + return; - real_t a = *p_inputs[0]; - real_t b = *p_inputs[1]; + } - *p_outputs[0]=MIN(a,b); - } - } break; - case VisualScriptBuiltinFunc::LOGIC_CLAMP: { + if (p_inputs[0]->is_ref()) { - if (p_inputs[0]->get_type()==Variant::INT && p_inputs[1]->get_type()==Variant::INT && p_inputs[2]->get_type()==Variant::INT) { + REF r = *p_inputs[0]; + if (!r.is_valid()) { - int64_t a = *p_inputs[0]; - int64_t b = *p_inputs[1]; - int64_t c = *p_inputs[2]; - *p_outputs[0]=CLAMP(a,b,c); - } else { - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); - VALIDATE_ARG_NUM(2); + return; + } - real_t a = *p_inputs[0]; - real_t b = *p_inputs[1]; - real_t c = *p_inputs[2]; + Ref<WeakRef> wref = memnew( WeakRef ); + wref->set_ref(r); + *r_return=wref; + } else { + Object *obj = *p_inputs[0]; + if (!obj) { - *p_outputs[0]=CLAMP(a,b,c); + return; } - } break; - case VisualScriptBuiltinFunc::LOGIC_NEAREST_PO2: { + Ref<WeakRef> wref = memnew( WeakRef ); + wref->set_obj(obj); + *r_return=wref; + } - VALIDATE_ARG_NUM(0); - int64_t num = *p_inputs[0]; - *p_outputs[0] = nearest_power_of_2(num); - } break; - case VisualScriptBuiltinFunc::OBJ_WEAKREF: { - if (p_inputs[0]->get_type()!=Variant::OBJECT) { - r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument=0; - r_error.expected=Variant::OBJECT; - return 0; + } break; + case VisualScriptBuiltinFunc::FUNC_FUNCREF: { - } + if (p_inputs[0]->get_type()!=Variant::OBJECT) { - if (p_inputs[0]->is_ref()) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=0; + r_error.expected=Variant::OBJECT; - REF r = *p_inputs[0]; - if (!r.is_valid()) { + return; - return 0; - } + } + if (p_inputs[1]->get_type()!=Variant::STRING && p_inputs[1]->get_type()!=Variant::NODE_PATH) { - Ref<WeakRef> wref = memnew( WeakRef ); - wref->set_ref(r); - *p_outputs[0]=wref; - } else { - Object *obj = *p_inputs[0]; - if (!obj) { - - return 0; - } - Ref<WeakRef> wref = memnew( WeakRef ); - wref->set_obj(obj); - *p_outputs[0]=wref; - } + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=1; + r_error.expected=Variant::STRING; + return; + } + Ref<FuncRef> fr = memnew( FuncRef); - } break; - case VisualScriptBuiltinFunc::FUNC_FUNCREF: { + fr->set_instance(*p_inputs[0]); + fr->set_function(*p_inputs[1]); - if (p_inputs[0]->get_type()!=Variant::OBJECT) { + *r_return=fr; - r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument=0; - r_error.expected=Variant::OBJECT; + } break; + case VisualScriptBuiltinFunc::TYPE_CONVERT: { - return 0; + VALIDATE_ARG_NUM(1); + int type=*p_inputs[1]; + if (type<0 || type>=Variant::VARIANT_MAX) { - } - if (p_inputs[1]->get_type()!=Variant::STRING && p_inputs[1]->get_type()!=Variant::NODE_PATH) { + r_error_str=RTR("Invalid type argument to convert(), use TYPE_* constants."); + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=0; + r_error.expected=Variant::INT; + return; - r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument=1; - r_error.expected=Variant::STRING; + } else { - return 0; - } + *r_return=Variant::construct(Variant::Type(type),p_inputs,1,r_error); + } + } break; + case VisualScriptBuiltinFunc::TYPE_OF: { - Ref<FuncRef> fr = memnew( FuncRef); - fr->set_instance(*p_inputs[0]); - fr->set_function(*p_inputs[1]); + *r_return = p_inputs[0]->get_type(); - *p_outputs[0]=fr; + } break; + case VisualScriptBuiltinFunc::TYPE_EXISTS: { - } break; - case VisualScriptBuiltinFunc::TYPE_CONVERT: { - VALIDATE_ARG_NUM(1); - int type=*p_inputs[1]; - if (type<0 || type>=Variant::VARIANT_MAX) { + *r_return = ClassDB::class_exists(*p_inputs[0]); - *p_outputs[0]=RTR("Invalid type argument to convert(), use TYPE_* constants."); - r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument=0; - r_error.expected=Variant::INT; - return 0; + } break; + case VisualScriptBuiltinFunc::TEXT_CHAR: { - } else { + CharType result[2] = {*p_inputs[0], 0}; + + *r_return=String(result); + } break; + case VisualScriptBuiltinFunc::TEXT_STR: { - *p_outputs[0]=Variant::construct(Variant::Type(type),p_inputs,1,r_error); - } - } break; - case VisualScriptBuiltinFunc::TYPE_OF: { + String str = *p_inputs[0]; + + *r_return=str; + } break; + case VisualScriptBuiltinFunc::TEXT_PRINT: { - *p_outputs[0] = p_inputs[0]->get_type(); + String str = *p_inputs[0]; + print_line(str); - } break; - case VisualScriptBuiltinFunc::TYPE_EXISTS: { + } break; - *p_outputs[0] = ObjectTypeDB::type_exists(*p_inputs[0]); + case VisualScriptBuiltinFunc::TEXT_PRINTERR: { - } break; - case VisualScriptBuiltinFunc::TEXT_STR: { + String str = *p_inputs[0]; - String str = *p_inputs[0]; + //str+="\n"; + OS::get_singleton()->printerr("%s\n",str.utf8().get_data()); - *p_outputs[0]=str; - } break; - case VisualScriptBuiltinFunc::TEXT_PRINT: { + } break; + case VisualScriptBuiltinFunc::TEXT_PRINTRAW: { + String str = *p_inputs[0]; - String str = *p_inputs[0]; - print_line(str); + //str+="\n"; + OS::get_singleton()->print("%s",str.utf8().get_data()); - } break; + } break; + case VisualScriptBuiltinFunc::VAR_TO_STR: { - case VisualScriptBuiltinFunc::TEXT_PRINTERR: { + String vars; + VariantWriter::write_to_string(*p_inputs[0],vars); + *r_return=vars; + } break; + case VisualScriptBuiltinFunc::STR_TO_VAR: { - String str = *p_inputs[0]; + if (p_inputs[0]->get_type()!=Variant::STRING) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=0; + r_error.expected=Variant::STRING; - //str+="\n"; - OS::get_singleton()->printerr("%s\n",str.utf8().get_data()); + return; + } + VariantParser::StreamString ss; + ss.s=*p_inputs[0]; - } break; - case VisualScriptBuiltinFunc::TEXT_PRINTRAW: { - String str = *p_inputs[0]; + String errs; + int line; + Error err = VariantParser::parse(&ss,*r_return,errs,line); - //str+="\n"; - OS::get_singleton()->print("%s",str.utf8().get_data()); + if (err!=OK) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=0; + r_error.expected=Variant::STRING; + *r_return="Parse error at line "+itos(line)+": "+errs; + return; + } + } break; + case VisualScriptBuiltinFunc::VAR_TO_BYTES: { - } break; - case VisualScriptBuiltinFunc::VAR_TO_STR: { - String vars; - VariantWriter::write_to_string(*p_inputs[0],vars); - *p_outputs[0]=vars; - } break; - case VisualScriptBuiltinFunc::STR_TO_VAR: { + PoolByteArray barr; + int len; + Error err = encode_variant(*p_inputs[0],NULL,len); + if (err) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=0; + r_error.expected=Variant::NIL; + r_error_str="Unexpected error encoding variable to bytes, likely unserializable type found (Object or RID)."; + return; + } - if (p_inputs[0]->get_type()!=Variant::STRING) { - r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument=0; - r_error.expected=Variant::STRING; + barr.resize(len); + { + PoolByteArray::Write w = barr.write(); + encode_variant(*p_inputs[0],w.ptr(),len); - return 0; - } + } + *r_return=barr; + } break; + case VisualScriptBuiltinFunc::BYTES_TO_VAR: { - VariantParser::StreamString ss; - ss.s=*p_inputs[0]; + if (p_inputs[0]->get_type()!=Variant::POOL_BYTE_ARRAY) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=0; + r_error.expected=Variant::POOL_BYTE_ARRAY; - String errs; - int line; - Error err = VariantParser::parse(&ss,*p_outputs[0],errs,line); + return; + } + PoolByteArray varr=*p_inputs[0]; + Variant ret; + { + PoolByteArray::Read r=varr.read(); + Error err = decode_variant(ret,r.ptr(),varr.size(),NULL); if (err!=OK) { + r_error_str=RTR("Not enough bytes for decoding bytes, or invalid format."); r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; - r_error.expected=Variant::STRING; - *p_outputs[0]="Parse error at line "+itos(line)+": "+errs; - return 0; + r_error.expected=Variant::POOL_BYTE_ARRAY; + return; } - } break; - case VisualScriptBuiltinFunc::VAR_TO_BYTES: { + } + *r_return=ret; - ByteArray barr; - int len; - Error err = encode_variant(*p_inputs[0],NULL,len); - if (err) { - r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument=0; - r_error.expected=Variant::NIL; - *p_outputs[0]="Unexpected error encoding variable to bytes, likely unserializable type found (Object or RID)."; - return 0; - } + } break; + case VisualScriptBuiltinFunc::COLORN: { - barr.resize(len); - { - ByteArray::Write w = barr.write(); - encode_variant(*p_inputs[0],w.ptr(),len); + VALIDATE_ARG_NUM(1); - } - *p_outputs[0]=barr; - } break; - case VisualScriptBuiltinFunc::BYTES_TO_VAR: { + Color color = Color::named(*p_inputs[0]); + color.a=*p_inputs[1]; + + *r_return=String(color); - if (p_inputs[0]->get_type()!=Variant::RAW_ARRAY) { - r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument=0; - r_error.expected=Variant::RAW_ARRAY; + } break; + default: {} + } - return 0; - } +} - ByteArray varr=*p_inputs[0]; - Variant ret; - { - ByteArray::Read r=varr.read(); - Error err = decode_variant(ret,r.ptr(),varr.size(),NULL); - if (err!=OK) { - *p_outputs[0]=RTR("Not enough bytes for decoding bytes, or invalid format."); - r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument=0; - r_error.expected=Variant::RAW_ARRAY; - return 0; - } - } +class VisualScriptNodeInstanceBuiltinFunc : public VisualScriptNodeInstance { +public: - *p_outputs[0]=ret; + VisualScriptBuiltinFunc *node; + VisualScriptInstance *instance; + + VisualScriptBuiltinFunc::BuiltinFunc func; + + + //virtual int get_working_memory_size() const { return 0; } + //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } + //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } + + virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) { - } break; - default: {} - } + VisualScriptBuiltinFunc::exec_func(func,p_inputs,p_outputs[0],r_error,r_error_str); return 0; } @@ -1101,8 +1166,8 @@ VisualScriptNodeInstance* VisualScriptBuiltinFunc::instance(VisualScriptInstance void VisualScriptBuiltinFunc::_bind_methods() { - ObjectTypeDB::bind_method(_MD("set_func","which"),&VisualScriptBuiltinFunc::set_func); - ObjectTypeDB::bind_method(_MD("get_func"),&VisualScriptBuiltinFunc::get_func); + ClassDB::bind_method(D_METHOD("set_func","which"),&VisualScriptBuiltinFunc::set_func); + ClassDB::bind_method(D_METHOD("get_func"),&VisualScriptBuiltinFunc::get_func); String cc; @@ -1112,7 +1177,7 @@ void VisualScriptBuiltinFunc::_bind_methods() { cc+=","; cc+=func_name[i]; } - ADD_PROPERTY(PropertyInfo(Variant::INT,"function",PROPERTY_HINT_ENUM,cc),_SCS("set_func"),_SCS("get_func")); + ADD_PROPERTY(PropertyInfo(Variant::INT,"function",PROPERTY_HINT_ENUM,cc),"set_func","get_func"); } VisualScriptBuiltinFunc::VisualScriptBuiltinFunc() { @@ -1185,6 +1250,7 @@ void register_visual_script_builtin_func_node() { VisualScriptLanguage::singleton->add_register_func("functions/built_in/convert",create_builtin_func_node<VisualScriptBuiltinFunc::TYPE_CONVERT>); VisualScriptLanguage::singleton->add_register_func("functions/built_in/typeof",create_builtin_func_node<VisualScriptBuiltinFunc::TYPE_OF>); VisualScriptLanguage::singleton->add_register_func("functions/built_in/type_exists",create_builtin_func_node<VisualScriptBuiltinFunc::TYPE_EXISTS>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/char",create_builtin_func_node<VisualScriptBuiltinFunc::TEXT_CHAR>); VisualScriptLanguage::singleton->add_register_func("functions/built_in/str",create_builtin_func_node<VisualScriptBuiltinFunc::TEXT_STR>); VisualScriptLanguage::singleton->add_register_func("functions/built_in/print",create_builtin_func_node<VisualScriptBuiltinFunc::TEXT_PRINT>); VisualScriptLanguage::singleton->add_register_func("functions/built_in/printerr",create_builtin_func_node<VisualScriptBuiltinFunc::TEXT_PRINTERR>); @@ -1193,5 +1259,6 @@ void register_visual_script_builtin_func_node() { VisualScriptLanguage::singleton->add_register_func("functions/built_in/str2var",create_builtin_func_node<VisualScriptBuiltinFunc::STR_TO_VAR>); VisualScriptLanguage::singleton->add_register_func("functions/built_in/var2bytes",create_builtin_func_node<VisualScriptBuiltinFunc::VAR_TO_BYTES>); VisualScriptLanguage::singleton->add_register_func("functions/built_in/bytes2var",create_builtin_func_node<VisualScriptBuiltinFunc::BYTES_TO_VAR>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/color_named",create_builtin_func_node<VisualScriptBuiltinFunc::COLORN>); } diff --git a/modules/visual_script/visual_script_builtin_funcs.h b/modules/visual_script/visual_script_builtin_funcs.h index ebf227a192..a285517c7e 100644 --- a/modules/visual_script/visual_script_builtin_funcs.h +++ b/modules/visual_script/visual_script_builtin_funcs.h @@ -6,7 +6,7 @@ class VisualScriptBuiltinFunc : public VisualScriptNode { - OBJ_TYPE(VisualScriptBuiltinFunc,VisualScriptNode) + GDCLASS(VisualScriptBuiltinFunc,VisualScriptNode) public: enum BuiltinFunc { @@ -57,6 +57,7 @@ public: TYPE_CONVERT, TYPE_OF, TYPE_EXISTS, + TEXT_CHAR, TEXT_STR, TEXT_PRINT, TEXT_PRINTERR, @@ -65,9 +66,15 @@ public: STR_TO_VAR, VAR_TO_BYTES, BYTES_TO_VAR, + COLORN, FUNC_MAX }; + static int get_func_argument_count(BuiltinFunc p_func); + static String get_func_name(BuiltinFunc p_func); + static void exec_func(BuiltinFunc p_func, const Variant** p_inputs, Variant* r_return, Variant::CallError& r_error, String& r_error_str); + static BuiltinFunc find_function(const String& p_string); + private: static const char* func_name[FUNC_MAX]; BuiltinFunc func; diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp index 14708799af..eadc9a8892 100644 --- a/modules/visual_script/visual_script_editor.cpp +++ b/modules/visual_script/visual_script_editor.cpp @@ -11,7 +11,7 @@ #ifdef TOOLS_ENABLED class VisualScriptEditorSignalEdit : public Object { - OBJ_TYPE(VisualScriptEditorSignalEdit,Object) + GDCLASS(VisualScriptEditorSignalEdit,Object) StringName sig; public: @@ -22,7 +22,7 @@ public: protected: static void _bind_methods() { - ObjectTypeDB::bind_method("_sig_changed",&VisualScriptEditorSignalEdit::_sig_changed); + ClassDB::bind_method("_sig_changed",&VisualScriptEditorSignalEdit::_sig_changed); } void _sig_changed() { @@ -160,7 +160,7 @@ public: class VisualScriptEditorVariableEdit : public Object { - OBJ_TYPE(VisualScriptEditorVariableEdit,Object) + GDCLASS(VisualScriptEditorVariableEdit,Object) StringName var; public: @@ -171,8 +171,8 @@ public: protected: static void _bind_methods() { - ObjectTypeDB::bind_method("_var_changed",&VisualScriptEditorVariableEdit::_var_changed); - ObjectTypeDB::bind_method("_var_value_changed",&VisualScriptEditorVariableEdit::_var_value_changed); + ClassDB::bind_method("_var_changed",&VisualScriptEditorVariableEdit::_var_changed); + ClassDB::bind_method("_var_value_changed",&VisualScriptEditorVariableEdit::_var_value_changed); } void _var_changed() { @@ -326,12 +326,12 @@ static Color _color_from_type(Variant::Type p_type) { case Variant::VECTOR2: color = Color::html("bd91f1"); break; case Variant::RECT2: color = Color::html("f191a5"); break; case Variant::VECTOR3: color = Color::html("d67dee"); break; - case Variant::MATRIX32: color = Color::html("c4ec69"); break; + case Variant::TRANSFORM2D: color = Color::html("c4ec69"); break; case Variant::PLANE: color = Color::html("f77070"); break; case Variant::QUAT: color = Color::html("ec69a3"); break; - case Variant::_AABB: color = Color::html("ee7991"); break; - case Variant::MATRIX3: color = Color::html("e3ec69"); break; - case Variant::TRANSFORM: color = Color::html("ecd669"); break; + case Variant::RECT3: color = Color::html("ee7991"); break; + case Variant::BASIS: color = Color::html("e3ec69"); break; + case Variant::TRANSFORM: color = Color::html("f6a86e"); break; case Variant::COLOR: color = Color::html("9dff70"); break; case Variant::IMAGE: color = Color::html("93f1b9"); break; @@ -342,13 +342,13 @@ static Color _color_from_type(Variant::Type p_type) { case Variant::DICTIONARY: color = Color::html("77edb1"); break; case Variant::ARRAY: color = Color::html("e0e0e0"); break; - case Variant::RAW_ARRAY: color = Color::html("aaf4c8"); break; - case Variant::INT_ARRAY: color = Color::html("afdcf5"); break; - case Variant::REAL_ARRAY: color = Color::html("97e7f8"); break; - case Variant::STRING_ARRAY: color = Color::html("9dc4f2"); break; - case Variant::VECTOR2_ARRAY: color = Color::html("d1b3f5"); break; - case Variant::VECTOR3_ARRAY: color = Color::html("df9bf2"); break; - case Variant::COLOR_ARRAY: color = Color::html("e9ff97"); break; + case Variant::POOL_BYTE_ARRAY: color = Color::html("aaf4c8"); break; + case Variant::POOL_INT_ARRAY: color = Color::html("afdcf5"); break; + case Variant::POOL_REAL_ARRAY: color = Color::html("97e7f8"); break; + case Variant::POOL_STRING_ARRAY: color = Color::html("9dc4f2"); break; + case Variant::POOL_VECTOR2_ARRAY: color = Color::html("d1b3f5"); break; + case Variant::POOL_VECTOR3_ARRAY: color = Color::html("df9bf2"); break; + case Variant::POOL_COLOR_ARRAY: color = Color::html("e9ff97"); break; default: color.set_hsv(p_type/float(Variant::VARIANT_MAX),0.7,0.7); @@ -438,11 +438,11 @@ void VisualScriptEditor::_update_graph(int p_only_id) { Control::get_icon("MiniVector2","EditorIcons"), Control::get_icon("MiniRect2","EditorIcons"), Control::get_icon("MiniVector3","EditorIcons"), - Control::get_icon("MiniMatrix32","EditorIcons"), + Control::get_icon("MiniTransform2D","EditorIcons"), Control::get_icon("MiniPlane","EditorIcons"), Control::get_icon("MiniQuat","EditorIcons"), Control::get_icon("MiniAabb","EditorIcons"), - Control::get_icon("MiniMatrix3","EditorIcons"), + Control::get_icon("MiniBasis","EditorIcons"), Control::get_icon("MiniTransform","EditorIcons"), Control::get_icon("MiniColor","EditorIcons"), Control::get_icon("MiniImage","EditorIcons"), @@ -485,8 +485,8 @@ void VisualScriptEditor::_update_graph(int p_only_id) { gnode->set_overlay(GraphNode::OVERLAY_BREAKPOINT); } - if (EditorSettings::get_singleton()->has("visual_script_editor/color_"+node->get_category())) { - gnode->set_modulate(EditorSettings::get_singleton()->get("visual_script_editor/color_"+node->get_category())); + if (EditorSettings::get_singleton()->has("editors/visual_script/color_"+node->get_category())) { + gnode->set_modulate(EditorSettings::get_singleton()->get("editors/visual_script/color_"+node->get_category())); } @@ -503,13 +503,21 @@ void VisualScriptEditor::_update_graph(int p_only_id) { } - Label *text = memnew( Label ); - text->set_text(node->get_text()); - gnode->add_child(text); if (node->cast_to<VisualScriptExpression>()) { - text->add_font_override("font",get_font("source","EditorFonts")); + + LineEdit *line_edit = memnew( LineEdit ); + line_edit->set_text(node->get_text()); + line_edit->set_expand_to_text_length(true); + line_edit->add_font_override("font",get_font("source","EditorFonts")); + gnode->add_child(line_edit); + line_edit->connect("text_changed",this,"_expression_text_changed",varray(E->get())); + } else { + Label *text = memnew( Label ); + text->set_text(node->get_text()); + gnode->add_child(text); } + if (node->cast_to<VisualScriptComment>()) { Ref<VisualScriptComment> vsc=node; gnode->set_comment(true); @@ -582,9 +590,9 @@ void VisualScriptEditor::_update_graph(int p_only_id) { t=type_icons[left_type]; } if (t.is_valid()) { - TextureFrame *tf = memnew(TextureFrame); + TextureRect *tf = memnew(TextureRect); tf->set_texture(t); - tf->set_stretch_mode(TextureFrame::STRETCH_KEEP_CENTERED); + tf->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED); hbc->add_child(tf); } @@ -649,9 +657,9 @@ void VisualScriptEditor::_update_graph(int p_only_id) { t=type_icons[right_type]; } if (t.is_valid()) { - TextureFrame *tf = memnew(TextureFrame); + TextureRect *tf = memnew(TextureRect); tf->set_texture(t); - tf->set_stretch_mode(TextureFrame::STRETCH_KEEP_CENTERED); + tf->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED); hbc->add_child(tf); } @@ -814,7 +822,7 @@ void VisualScriptEditor::_member_selected() { selected=ti->get_metadata(0); -// print_line("selected: "+String(selected)); + //print_line("selected: "+String(selected)); if (ti->get_parent()==members->get_root()->get_children()) { @@ -982,7 +990,7 @@ void VisualScriptEditor::_member_button(Object *p_item, int p_column, int p_butt virtuals_in_menu.clear(); List<MethodInfo> mi; - ObjectTypeDB::get_method_list(script->get_instance_base_type(),&mi); + ClassDB::get_method_list(script->get_instance_base_type(),&mi); for (List<MethodInfo>::Element *E=mi.front();E;E=E->next()) { MethodInfo mi=E->get(); if (mi.flags&METHOD_FLAG_VIRTUAL) { @@ -1128,9 +1136,11 @@ void VisualScriptEditor::_member_button(Object *p_item, int p_column, int p_butt undo_redo->add_undo_method(script.ptr(),"data_connect",name,E->get().from_node,E->get().from_port,E->get().to_node,E->get().to_port); } - //for(int i=0;i<script->function_get_argument_count(name);i++) { - //// undo_redo->add_undo_method(script.ptr(),"function_add_argument",name,script->function_get_argument_name(name,i),script->function_get_argument_type(name,i)); - //} + /* + for(int i=0;i<script->function_get_argument_count(name);i++) { + undo_redo->add_undo_method(script.ptr(),"function_add_argument",name,script->function_get_argument_name(name,i),script->function_get_argument_type(name,i)); + } + */ undo_redo->add_do_method(this,"_update_members"); undo_redo->add_undo_method(this,"_update_members"); undo_redo->add_do_method(this,"_update_graph"); @@ -1201,6 +1211,30 @@ void VisualScriptEditor::_member_button(Object *p_item, int p_column, int p_butt } } +void VisualScriptEditor::_expression_text_changed(const String& p_text,int p_id) { + + Ref<VisualScriptExpression> vse = script->get_node(edited_func,p_id); + if (!vse.is_valid()) + return; + + + updating_graph=true; + + undo_redo->create_action(TTR("Change Expression"),UndoRedo::MERGE_ENDS); + undo_redo->add_do_property(vse.ptr(),"expression",p_text); + undo_redo->add_undo_property(vse.ptr(),"expression",vse->get("expression")); + undo_redo->add_do_method(this,"_update_graph",p_id); + undo_redo->add_undo_method(this,"_update_graph",p_id); + undo_redo->commit_action(); + + Node *node = graph->get_node(itos(p_id)); + if (node->cast_to<Control>()) + node->cast_to<Control>()->set_size(Vector2(1,1)); //shrink if text is smaller + + updating_graph=false; + +} + void VisualScriptEditor::_available_node_doubleclicked() { TreeItem *item = nodes->get_selected(); @@ -1744,7 +1778,7 @@ void VisualScriptEditor::drop_data_fw(const Point2& p_point,const Variant& p_dat if (node) { graph->set_selected(node); _node_selected(node); - } + } } if (d.has("type") && String(d["type"])=="resource") { @@ -1884,8 +1918,8 @@ void VisualScriptEditor::drop_data_fw(const Point2& p_point,const Variant& p_dat Ref<VisualScriptFunctionCall> call; call.instance(); call->set_call_mode(VisualScriptFunctionCall::CALL_MODE_NODE_PATH); - call->set_base_path(sn->get_path_to(node));; - call->set_base_type(node->get_type()); + call->set_base_path(sn->get_path_to(node)); + call->set_base_type(node->get_class()); n=call; method_select->select_method_from_instance(node); @@ -1954,7 +1988,7 @@ void VisualScriptEditor::drop_data_fw(const Point2& p_point,const Variant& p_dat Ref<VisualScriptPropertySet> pset; pset.instance(); pset->set_call_mode(VisualScriptPropertySet::CALL_MODE_INSTANCE); - pset->set_base_type(obj->get_type()); + pset->set_base_type(obj->get_class()); /*if (use_value) { pset->set_use_builtin_value(true); pset->set_builtin_value(d["value"]); @@ -1965,7 +1999,7 @@ void VisualScriptEditor::drop_data_fw(const Point2& p_point,const Variant& p_dat Ref<VisualScriptPropertyGet> pget; pget.instance(); pget->set_call_mode(VisualScriptPropertyGet::CALL_MODE_INSTANCE); - pget->set_base_type(obj->get_type()); + pget->set_base_type(obj->get_class()); vnode=pget; @@ -2108,6 +2142,7 @@ Vector<String> VisualScriptEditor::get_functions(){ void VisualScriptEditor::set_edited_script(const Ref<Script>& p_script){ + script=p_script; signal_editor->script=p_script; signal_editor->undo_redo=undo_redo; @@ -2138,7 +2173,7 @@ String VisualScriptEditor::get_name(){ } else if (script->get_name()!="") name=script->get_name(); else - name=script->get_type()+"("+itos(script->get_instance_ID())+")"; + name=script->get_class()+"("+itos(script->get_instance_ID())+")"; return name; @@ -2288,7 +2323,7 @@ bool VisualScriptEditor::goto_method(const String& p_method){ return true; } -void VisualScriptEditor::add_callback(const String& p_function,StringArray p_args){ +void VisualScriptEditor::add_callback(const String& p_function,PoolStringArray p_args){ if (script->has_function(p_function)) { edited_func=p_function; @@ -2671,7 +2706,7 @@ VisualScriptNode::TypeGuess VisualScriptEditor::_guess_output_type(int p_node,i if (obj) { g.type=Variant::OBJECT; - g.obj_type=obj->get_type(); + g.GDCLASS=obj->get_class(); g.script=obj->get_script(); } } @@ -2712,8 +2747,8 @@ void VisualScriptEditor::_port_action_menu(int p_option) { if (tg.type==Variant::OBJECT) { n->set_call_mode(VisualScriptFunctionCall::CALL_MODE_INSTANCE); - if (tg.obj_type!=StringName()) { - n->set_base_type(tg.obj_type); + if (tg.GDCLASS!=StringName()) { + n->set_base_type(tg.GDCLASS); } else { n->set_base_type("Object"); } @@ -2747,8 +2782,8 @@ void VisualScriptEditor::_port_action_menu(int p_option) { if (tg.type==Variant::OBJECT) { n->set_call_mode(VisualScriptPropertySet::CALL_MODE_INSTANCE); - if (tg.obj_type!=StringName()) { - n->set_base_type(tg.obj_type); + if (tg.GDCLASS!=StringName()) { + n->set_base_type(tg.GDCLASS); } else { n->set_base_type("Object"); } @@ -2778,8 +2813,8 @@ void VisualScriptEditor::_port_action_menu(int p_option) { if (tg.type==Variant::OBJECT) { n->set_call_mode(VisualScriptPropertyGet::CALL_MODE_INSTANCE); - if (tg.obj_type!=StringName()) { - n->set_base_type(tg.obj_type); + if (tg.GDCLASS!=StringName()) { + n->set_base_type(tg.GDCLASS); } else { n->set_base_type("Object"); } @@ -3049,7 +3084,7 @@ void VisualScriptEditor::_menu_option(int p_what) { //popup disappearing grabs focus to owner, so use call deferred node_filter->call_deferred("grab_focus"); node_filter->call_deferred("select_all"); - } break; + } break; case EDIT_COPY_NODES: case EDIT_CUT_NODES: { @@ -3199,54 +3234,55 @@ void VisualScriptEditor::_menu_option(int p_what) { void VisualScriptEditor::_bind_methods() { - ObjectTypeDB::bind_method("_member_button",&VisualScriptEditor::_member_button); - ObjectTypeDB::bind_method("_member_edited",&VisualScriptEditor::_member_edited); - ObjectTypeDB::bind_method("_member_selected",&VisualScriptEditor::_member_selected); - ObjectTypeDB::bind_method("_update_members",&VisualScriptEditor::_update_members); - ObjectTypeDB::bind_method("_change_base_type",&VisualScriptEditor::_change_base_type); - ObjectTypeDB::bind_method("_change_base_type_callback",&VisualScriptEditor::_change_base_type_callback); - ObjectTypeDB::bind_method("_override_pressed",&VisualScriptEditor::_override_pressed); - ObjectTypeDB::bind_method("_node_selected",&VisualScriptEditor::_node_selected); - ObjectTypeDB::bind_method("_node_moved",&VisualScriptEditor::_node_moved); - ObjectTypeDB::bind_method("_move_node",&VisualScriptEditor::_move_node); - ObjectTypeDB::bind_method("_begin_node_move",&VisualScriptEditor::_begin_node_move); - ObjectTypeDB::bind_method("_end_node_move",&VisualScriptEditor::_end_node_move); - ObjectTypeDB::bind_method("_remove_node",&VisualScriptEditor::_remove_node); - ObjectTypeDB::bind_method("_update_graph",&VisualScriptEditor::_update_graph,DEFVAL(-1)); - ObjectTypeDB::bind_method("_node_ports_changed",&VisualScriptEditor::_node_ports_changed); - ObjectTypeDB::bind_method("_available_node_doubleclicked",&VisualScriptEditor::_available_node_doubleclicked); - ObjectTypeDB::bind_method("_default_value_edited",&VisualScriptEditor::_default_value_edited); - ObjectTypeDB::bind_method("_default_value_changed",&VisualScriptEditor::_default_value_changed); - ObjectTypeDB::bind_method("_menu_option",&VisualScriptEditor::_menu_option); - ObjectTypeDB::bind_method("_graph_ofs_changed",&VisualScriptEditor::_graph_ofs_changed); - ObjectTypeDB::bind_method("_center_on_node",&VisualScriptEditor::_center_on_node); - ObjectTypeDB::bind_method("_comment_node_resized",&VisualScriptEditor::_comment_node_resized); - ObjectTypeDB::bind_method("_button_resource_previewed",&VisualScriptEditor::_button_resource_previewed); - ObjectTypeDB::bind_method("_port_action_menu",&VisualScriptEditor::_port_action_menu); - ObjectTypeDB::bind_method("_selected_connect_node_method_or_setget",&VisualScriptEditor::_selected_connect_node_method_or_setget); + ClassDB::bind_method("_member_button",&VisualScriptEditor::_member_button); + ClassDB::bind_method("_member_edited",&VisualScriptEditor::_member_edited); + ClassDB::bind_method("_member_selected",&VisualScriptEditor::_member_selected); + ClassDB::bind_method("_update_members",&VisualScriptEditor::_update_members); + ClassDB::bind_method("_change_base_type",&VisualScriptEditor::_change_base_type); + ClassDB::bind_method("_change_base_type_callback",&VisualScriptEditor::_change_base_type_callback); + ClassDB::bind_method("_override_pressed",&VisualScriptEditor::_override_pressed); + ClassDB::bind_method("_node_selected",&VisualScriptEditor::_node_selected); + ClassDB::bind_method("_node_moved",&VisualScriptEditor::_node_moved); + ClassDB::bind_method("_move_node",&VisualScriptEditor::_move_node); + ClassDB::bind_method("_begin_node_move",&VisualScriptEditor::_begin_node_move); + ClassDB::bind_method("_end_node_move",&VisualScriptEditor::_end_node_move); + ClassDB::bind_method("_remove_node",&VisualScriptEditor::_remove_node); + ClassDB::bind_method("_update_graph",&VisualScriptEditor::_update_graph,DEFVAL(-1)); + ClassDB::bind_method("_node_ports_changed",&VisualScriptEditor::_node_ports_changed); + ClassDB::bind_method("_available_node_doubleclicked",&VisualScriptEditor::_available_node_doubleclicked); + ClassDB::bind_method("_default_value_edited",&VisualScriptEditor::_default_value_edited); + ClassDB::bind_method("_default_value_changed",&VisualScriptEditor::_default_value_changed); + ClassDB::bind_method("_menu_option",&VisualScriptEditor::_menu_option); + ClassDB::bind_method("_graph_ofs_changed",&VisualScriptEditor::_graph_ofs_changed); + ClassDB::bind_method("_center_on_node",&VisualScriptEditor::_center_on_node); + ClassDB::bind_method("_comment_node_resized",&VisualScriptEditor::_comment_node_resized); + ClassDB::bind_method("_button_resource_previewed",&VisualScriptEditor::_button_resource_previewed); + ClassDB::bind_method("_port_action_menu",&VisualScriptEditor::_port_action_menu); + ClassDB::bind_method("_selected_connect_node_method_or_setget",&VisualScriptEditor::_selected_connect_node_method_or_setget); + ClassDB::bind_method("_expression_text_changed",&VisualScriptEditor::_expression_text_changed); - ObjectTypeDB::bind_method("get_drag_data_fw",&VisualScriptEditor::get_drag_data_fw); - ObjectTypeDB::bind_method("can_drop_data_fw",&VisualScriptEditor::can_drop_data_fw); - ObjectTypeDB::bind_method("drop_data_fw",&VisualScriptEditor::drop_data_fw); + ClassDB::bind_method("get_drag_data_fw",&VisualScriptEditor::get_drag_data_fw); + ClassDB::bind_method("can_drop_data_fw",&VisualScriptEditor::can_drop_data_fw); + ClassDB::bind_method("drop_data_fw",&VisualScriptEditor::drop_data_fw); - ObjectTypeDB::bind_method("_input",&VisualScriptEditor::_input); - ObjectTypeDB::bind_method("_on_nodes_delete",&VisualScriptEditor::_on_nodes_delete); - ObjectTypeDB::bind_method("_on_nodes_duplicate",&VisualScriptEditor::_on_nodes_duplicate); + ClassDB::bind_method("_input",&VisualScriptEditor::_input); + ClassDB::bind_method("_on_nodes_delete",&VisualScriptEditor::_on_nodes_delete); + ClassDB::bind_method("_on_nodes_duplicate",&VisualScriptEditor::_on_nodes_duplicate); - ObjectTypeDB::bind_method("_hide_timer",&VisualScriptEditor::_hide_timer); + ClassDB::bind_method("_hide_timer",&VisualScriptEditor::_hide_timer); - ObjectTypeDB::bind_method("_graph_connected",&VisualScriptEditor::_graph_connected); - ObjectTypeDB::bind_method("_graph_disconnected",&VisualScriptEditor::_graph_disconnected); - ObjectTypeDB::bind_method("_graph_connect_to_empty",&VisualScriptEditor::_graph_connect_to_empty); + ClassDB::bind_method("_graph_connected",&VisualScriptEditor::_graph_connected); + ClassDB::bind_method("_graph_disconnected",&VisualScriptEditor::_graph_disconnected); + ClassDB::bind_method("_graph_connect_to_empty",&VisualScriptEditor::_graph_connect_to_empty); - ObjectTypeDB::bind_method("_update_graph_connections",&VisualScriptEditor::_update_graph_connections); - ObjectTypeDB::bind_method("_node_filter_changed",&VisualScriptEditor::_node_filter_changed); + ClassDB::bind_method("_update_graph_connections",&VisualScriptEditor::_update_graph_connections); + ClassDB::bind_method("_node_filter_changed",&VisualScriptEditor::_node_filter_changed); - ObjectTypeDB::bind_method("_selected_method",&VisualScriptEditor::_selected_method); - ObjectTypeDB::bind_method("_draw_color_over_button",&VisualScriptEditor::_draw_color_over_button); + ClassDB::bind_method("_selected_method",&VisualScriptEditor::_selected_method); + ClassDB::bind_method("_draw_color_over_button",&VisualScriptEditor::_draw_color_over_button); @@ -3272,7 +3308,7 @@ VisualScriptEditor::VisualScriptEditor() { edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/cut_nodes"), EDIT_CUT_NODES); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/paste_nodes"), EDIT_PASTE_NODES); - edit_menu->get_popup()->connect("item_pressed",this,"_menu_option"); + edit_menu->get_popup()->connect("id_pressed",this,"_menu_option"); main_hsplit = memnew( HSplitContainer ); add_child(main_hsplit); @@ -3312,8 +3348,8 @@ VisualScriptEditor::VisualScriptEditor() { node_filter->connect("text_changed",this,"_node_filter_changed"); hbc_nodes->add_child(node_filter); node_filter->set_h_size_flags(SIZE_EXPAND_FILL); - node_filter_icon = memnew( TextureFrame ); - node_filter_icon->set_stretch_mode(TextureFrame::STRETCH_KEEP_CENTERED); + node_filter_icon = memnew( TextureRect ); + node_filter_icon->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED); hbc_nodes->add_child(node_filter_icon); vbc_nodes->add_child(hbc_nodes); @@ -3388,7 +3424,7 @@ VisualScriptEditor::VisualScriptEditor() { edit_signal_edit = memnew( PropertyEditor ); edit_signal_edit->hide_top_label(); edit_signal_dialog->add_child(edit_signal_edit); - edit_signal_dialog->set_child_rect(edit_signal_edit); + edit_signal_edit->edit(signal_editor); edit_variable_dialog = memnew( AcceptDialog ); @@ -3400,7 +3436,7 @@ VisualScriptEditor::VisualScriptEditor() { edit_variable_edit = memnew( PropertyEditor ); edit_variable_edit->hide_top_label(); edit_variable_dialog->add_child(edit_variable_edit); - edit_variable_dialog->set_child_rect(edit_variable_edit); + edit_variable_edit->edit(variable_editor); select_base_type=memnew(CreateDialog); @@ -3412,7 +3448,7 @@ VisualScriptEditor::VisualScriptEditor() { undo_redo = EditorNode::get_singleton()->get_undo_redo(); new_function_menu = memnew( PopupMenu ); - new_function_menu->connect("item_pressed",this,"_override_pressed"); + new_function_menu->connect("id_pressed",this,"_override_pressed"); add_child(new_function_menu); updating_members=false; @@ -3434,7 +3470,7 @@ VisualScriptEditor::VisualScriptEditor() { port_action_popup = memnew( PopupMenu ); add_child(port_action_popup); - port_action_popup->connect("item_pressed",this,"_port_action_menu"); + port_action_popup->connect("id_pressed",this,"_port_action_menu"); } @@ -3466,12 +3502,12 @@ void VisualScriptEditor::free_clipboard() { static void register_editor_callback() { ScriptEditor::register_create_script_editor_function(create_editor); - EditorSettings::get_singleton()->set("visual_script_editor/color_functions",Color(1,0.9,0.9)); - EditorSettings::get_singleton()->set("visual_script_editor/color_data",Color(0.9,1.0,0.9)); - EditorSettings::get_singleton()->set("visual_script_editor/color_operators",Color(0.9,0.9,1.0)); - EditorSettings::get_singleton()->set("visual_script_editor/color_flow_control",Color(1.0,1.0,0.8)); - EditorSettings::get_singleton()->set("visual_script_editor/color_custom",Color(0.8,1.0,1.0)); - EditorSettings::get_singleton()->set("visual_script_editor/color_constants",Color(1.0,0.8,1.0)); + EditorSettings::get_singleton()->set("editors/visual_script/color_functions",Color(1,0.9,0.9)); + EditorSettings::get_singleton()->set("editors/visual_script/color_data",Color(0.9,1.0,0.9)); + EditorSettings::get_singleton()->set("editors/visual_script/color_operators",Color(0.9,0.9,1.0)); + EditorSettings::get_singleton()->set("editors/visual_script/color_flow_control",Color(1.0,1.0,0.8)); + EditorSettings::get_singleton()->set("editors/visual_script/color_custom",Color(0.8,1.0,1.0)); + EditorSettings::get_singleton()->set("editors/visual_script/color_constants",Color(1.0,0.8,1.0)); ED_SHORTCUT("visual_script_editor/delete_selected", TTR("Delete Selected")); diff --git a/modules/visual_script/visual_script_editor.h b/modules/visual_script/visual_script_editor.h index 5191ed540a..1dc62b3e69 100644 --- a/modules/visual_script/visual_script_editor.h +++ b/modules/visual_script/visual_script_editor.h @@ -15,7 +15,7 @@ class VisualScriptEditorVariableEdit; class VisualScriptEditor : public ScriptEditorBase { - OBJ_TYPE(VisualScriptEditor,ScriptEditorBase) + GDCLASS(VisualScriptEditor,ScriptEditorBase) enum { TYPE_SEQUENCE=1000, @@ -58,7 +58,7 @@ class VisualScriptEditor : public ScriptEditorBase { GraphEdit *graph; LineEdit *node_filter; - TextureFrame *node_filter_icon; + TextureRect *node_filter_icon; VisualScriptEditorSignalEdit *signal_editor; @@ -168,6 +168,7 @@ class VisualScriptEditor : public ScriptEditorBase { void _member_button(Object *p_item, int p_column, int p_button); + void _expression_text_changed(const String& p_text,int p_id); String revert_on_drag; @@ -224,7 +225,7 @@ public: virtual void reload(bool p_soft); virtual void get_breakpoints(List<int> *p_breakpoints); virtual bool goto_method(const String& p_method); - virtual void add_callback(const String& p_function,StringArray p_args); + virtual void add_callback(const String& p_function,PoolStringArray p_args); virtual void update_settings(); virtual void set_debugger_active(bool p_active); virtual void set_tooltip_request_func(String p_method,Object* p_obj); diff --git a/modules/visual_script/visual_script_expression.cpp b/modules/visual_script/visual_script_expression.cpp index 3cfb1c154e..cc3b5f2174 100644 --- a/modules/visual_script/visual_script_expression.cpp +++ b/modules/visual_script/visual_script_expression.cpp @@ -120,7 +120,7 @@ void VisualScriptExpression::_get_property_list( List<PropertyInfo> *p_list) con argt+=","+Variant::get_type_name(Variant::Type(i)); } - p_list->push_back(PropertyInfo(Variant::STRING,"expression")); + p_list->push_back(PropertyInfo(Variant::STRING,"expression",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR)); p_list->push_back(PropertyInfo(Variant::INT,"out_type",PROPERTY_HINT_ENUM,argt)); p_list->push_back(PropertyInfo(Variant::INT,"input_count",PROPERTY_HINT_RANGE,"0,64,1")); p_list->push_back(PropertyInfo(Variant::BOOL,"sequenced")); @@ -577,6 +577,13 @@ Error VisualScriptExpression::_get_token(Token& r_token) { } } + VisualScriptBuiltinFunc::BuiltinFunc bifunc = VisualScriptBuiltinFunc::find_function(id); + if (bifunc!=VisualScriptBuiltinFunc::FUNC_MAX) { + r_token.type=TK_BUILTIN_FUNC; + r_token.value=bifunc; + return OK; + } + r_token.type=TK_IDENTIFIER; r_token.value=id; } @@ -603,6 +610,7 @@ const char* VisualScriptExpression::token_name[TK_MAX]={ "PARENTHESIS OPEN", "PARENTHESIS CLOSE", "IDENTIFIER", +"BUILTIN FUNC", "SELF", "CONSTANT", "BASIC TYPE", @@ -814,6 +822,53 @@ VisualScriptExpression::ENode* VisualScriptExpression::_parse_expression() { expr=constructor; } break; + case TK_BUILTIN_FUNC: { + //builtin function + + Variant::Type bt = Variant::Type(int(tk.value)); + _get_token(tk); + if (tk.type!=TK_PARENTHESIS_OPEN) { + _set_error("Expected '('"); + return NULL; + } + + BuiltinFuncNode *bifunc = alloc_node<BuiltinFuncNode>(); + bifunc->func=VisualScriptBuiltinFunc::BuiltinFunc(int(tk.value)); + + while(true) { + + int cofs=str_ofs; + _get_token(tk); + if (tk.type==TK_PARENTHESIS_CLOSE) { + break; + } + str_ofs=cofs; //revert + //parse an expression + ENode* expr=_parse_expression(); + if (!expr) + return NULL; + + bifunc->arguments.push_back(expr); + + cofs=str_ofs; + _get_token(tk); + if (tk.type==TK_COMMA) { + //all good + } else if (tk.type==TK_PARENTHESIS_CLOSE) { + str_ofs=cofs; + } else { + _set_error("Expected ',' or ')'"); + } + } + + int expected_args = VisualScriptBuiltinFunc::get_func_argument_count(bifunc->func); + if (bifunc->arguments.size() != expected_args) { + _set_error("Builtin func '"+VisualScriptBuiltinFunc::get_func_name(bifunc->func)+"' expects "+itos(expected_args)+" arguments."); + } + + expr=bifunc; + + } break; case TK_OP_SUB: { Expression e; @@ -1338,6 +1393,34 @@ public: } break; + case VisualScriptExpression::ENode::TYPE_BUILTIN_FUNC: { + + const VisualScriptExpression::BuiltinFuncNode *bifunc = static_cast<const VisualScriptExpression::BuiltinFuncNode*>(p_node); + + Vector<Variant> arr; + Vector<const Variant*> argp; + arr.resize(bifunc->arguments.size()); + argp.resize(bifunc->arguments.size()); + + for (int i=0;i<bifunc->arguments.size();i++) { + + Variant value; + bool ret = _execute(p_inputs,bifunc->arguments[i],value,r_error_str,ce); + if (ret) + return true; + arr[i]=value; + argp[i]=&arr[i]; + } + + + VisualScriptBuiltinFunc::exec_func(bifunc->func,argp.ptr(),&r_ret,ce,r_error_str); + + if (ce.error!=Variant::CallError::CALL_OK) { + r_error_str="Builtin Call Failed. "+r_error_str; + return true; + } + + } break; case VisualScriptExpression::ENode::TYPE_CALL: { const VisualScriptExpression::CallNode *call = static_cast<const VisualScriptExpression::CallNode*>(p_node); @@ -1396,8 +1479,8 @@ public: r_error_str+="Can't convert expression result from "+Variant::get_type_name(p_outputs[0]->get_type())+" to "+Variant::get_type_name(expression->output_type)+"."; r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; -#endif } +#endif return 0; } diff --git a/modules/visual_script/visual_script_expression.h b/modules/visual_script/visual_script_expression.h index 90b955b5da..a67656a4b1 100644 --- a/modules/visual_script/visual_script_expression.h +++ b/modules/visual_script/visual_script_expression.h @@ -2,10 +2,11 @@ #define VISUALSCRIPTEXPRESSION_H #include "visual_script.h" +#include "visual_script_builtin_funcs.h" class VisualScriptExpression : public VisualScriptNode { - OBJ_TYPE(VisualScriptExpression,VisualScriptNode) + GDCLASS(VisualScriptExpression,VisualScriptNode) friend class VisualScriptNodeInstanceExpression; struct Input { @@ -35,6 +36,7 @@ friend class VisualScriptNodeInstanceExpression; TK_PARENTHESIS_OPEN, TK_PARENTHESIS_CLOSE, TK_IDENTIFIER, + TK_BUILTIN_FUNC, TK_SELF, TK_CONSTANT, TK_BASIC_TYPE, @@ -101,6 +103,7 @@ friend class VisualScriptNodeInstanceExpression; TYPE_ARRAY, TYPE_DICTIONARY, TYPE_CONSTRUCTOR, + TYPE_BUILTIN_FUNC, TYPE_CALL }; @@ -214,6 +217,14 @@ friend class VisualScriptNodeInstanceExpression; }; + struct BuiltinFuncNode : public ENode { + VisualScriptBuiltinFunc::BuiltinFunc func; + Vector<ENode*> arguments; + BuiltinFuncNode() { + type=TYPE_BUILTIN_FUNC; + } + }; + template<class T> T* alloc_node() { T* node = memnew(T); diff --git a/modules/visual_script/visual_script_flow_control.cpp b/modules/visual_script/visual_script_flow_control.cpp index 97338da187..93e395f0f2 100644 --- a/modules/visual_script/visual_script_flow_control.cpp +++ b/modules/visual_script/visual_script_flow_control.cpp @@ -1,6 +1,6 @@ #include "visual_script_flow_control.h" #include "os/keyboard.h" -#include "globals.h" +#include "global_config.h" ////////////////////////////////////////// @@ -81,18 +81,18 @@ bool VisualScriptReturn::is_return_value_enabled() const { void VisualScriptReturn::_bind_methods() { - ObjectTypeDB::bind_method(_MD("set_return_type","type"),&VisualScriptReturn::set_return_type); - ObjectTypeDB::bind_method(_MD("get_return_type"),&VisualScriptReturn::get_return_type); - ObjectTypeDB::bind_method(_MD("set_enable_return_value","enable"),&VisualScriptReturn::set_enable_return_value); - ObjectTypeDB::bind_method(_MD("is_return_value_enabled"),&VisualScriptReturn::is_return_value_enabled); + ClassDB::bind_method(D_METHOD("set_return_type","type"),&VisualScriptReturn::set_return_type); + ClassDB::bind_method(D_METHOD("get_return_type"),&VisualScriptReturn::get_return_type); + ClassDB::bind_method(D_METHOD("set_enable_return_value","enable"),&VisualScriptReturn::set_enable_return_value); + ClassDB::bind_method(D_METHOD("is_return_value_enabled"),&VisualScriptReturn::is_return_value_enabled); String argt="Any"; for(int i=1;i<Variant::VARIANT_MAX;i++) { argt+=","+Variant::get_type_name(Variant::Type(i)); } - ADD_PROPERTY(PropertyInfo(Variant::BOOL,"return_value/enabled"),_SCS("set_enable_return_value"),_SCS("is_return_value_enabled")); - ADD_PROPERTY(PropertyInfo(Variant::INT,"return_value/type",PROPERTY_HINT_ENUM,argt),_SCS("set_return_type"),_SCS("get_return_type")); + ADD_PROPERTY(PropertyInfo(Variant::BOOL,"return_value/enabled"),"set_enable_return_value","is_return_value_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::INT,"return_value/type",PROPERTY_HINT_ENUM,argt),"set_return_type","get_return_type"); } @@ -544,10 +544,10 @@ int VisualScriptSequence::get_steps() const { void VisualScriptSequence::_bind_methods() { - ObjectTypeDB::bind_method(_MD("set_steps","steps"),&VisualScriptSequence::set_steps); - ObjectTypeDB::bind_method(_MD("get_steps"),&VisualScriptSequence::get_steps); + ClassDB::bind_method(D_METHOD("set_steps","steps"),&VisualScriptSequence::set_steps); + ClassDB::bind_method(D_METHOD("get_steps"),&VisualScriptSequence::get_steps); - ADD_PROPERTY(PropertyInfo(Variant::INT,"steps",PROPERTY_HINT_RANGE,"1,64,1"),_SCS("set_steps"),_SCS("get_steps")); + ADD_PROPERTY(PropertyInfo(Variant::INT,"steps",PROPERTY_HINT_RANGE,"1,64,1"),"set_steps","get_steps"); } @@ -871,9 +871,9 @@ String VisualScriptInputFilter::get_output_sequence_port_text(int p_port) const } break; - case InputEvent::JOYSTICK_MOTION: { + case InputEvent::JOYPAD_MOTION: { - InputEventJoystickMotion jm = filters[p_port].joy_motion; + InputEventJoypadMotion jm = filters[p_port].joy_motion; text="JoyMotion Axis "+itos(jm.axis>>1); if (jm.axis&1) @@ -882,8 +882,8 @@ String VisualScriptInputFilter::get_output_sequence_port_text(int p_port) const text+=" < "+rtos(-jm.axis_value); } break; - case InputEvent::JOYSTICK_BUTTON: { - InputEventJoystickButton jb = filters[p_port].joy_button; + case InputEvent::JOYPAD_BUTTON: { + InputEventJoypadButton jb = filters[p_port].joy_button; text="JoyButton "+itos(jb.button_index); if (jb.pressed) @@ -908,7 +908,7 @@ String VisualScriptInputFilter::get_output_sequence_port_text(int p_port) const List<PropertyInfo> pinfo; - Globals::get_singleton()->get_property_list(&pinfo); + GlobalConfig::get_singleton()->get_property_list(&pinfo); int index=1; text="No Action"; @@ -985,13 +985,13 @@ bool VisualScriptInputFilter::_set(const StringName& p_name, const Variant& p_va if (what=="type") { filters[idx]=InputEvent(); filters[idx].type=InputEvent::Type(int(p_value)); - if (filters[idx].type==InputEvent::JOYSTICK_MOTION) { + if (filters[idx].type==InputEvent::JOYPAD_MOTION) { filters[idx].joy_motion.axis_value=0.5; //for treshold } else if (filters[idx].type==InputEvent::KEY) { filters[idx].key.pressed=true; //put these as true to make it more user friendly } else if (filters[idx].type==InputEvent::MOUSE_BUTTON) { filters[idx].mouse_button.pressed=true; - } else if (filters[idx].type==InputEvent::JOYSTICK_BUTTON) { + } else if (filters[idx].type==InputEvent::JOYPAD_BUTTON) { filters[idx].joy_button.pressed=true; } else if (filters[idx].type==InputEvent::SCREEN_TOUCH) { filters[idx].screen_touch.pressed=true; @@ -1108,7 +1108,7 @@ bool VisualScriptInputFilter::_set(const StringName& p_name, const Variant& p_va return true; } break; - case InputEvent::JOYSTICK_MOTION: { + case InputEvent::JOYPAD_MOTION: { if (what=="axis") { filters[idx].joy_motion.axis=int(p_value)<<1|filters[idx].joy_motion.axis; @@ -1124,7 +1124,7 @@ bool VisualScriptInputFilter::_set(const StringName& p_name, const Variant& p_va } break; - case InputEvent::JOYSTICK_BUTTON: { + case InputEvent::JOYPAD_BUTTON: { if (what=="button_index") { filters[idx].joy_button.button_index=p_value; @@ -1164,7 +1164,7 @@ bool VisualScriptInputFilter::_set(const StringName& p_name, const Variant& p_va if (what=="action_name") { List<PropertyInfo> pinfo; - Globals::get_singleton()->get_property_list(&pinfo); + GlobalConfig::get_singleton()->get_property_list(&pinfo); int index=1; for(List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) { @@ -1326,7 +1326,7 @@ bool VisualScriptInputFilter::_get(const StringName& p_name,Variant &r_ret) cons return true; } break; - case InputEvent::JOYSTICK_MOTION: { + case InputEvent::JOYPAD_MOTION: { if (what=="axis_index") { r_ret=filters[idx].joy_motion.axis>>1; @@ -1341,7 +1341,7 @@ bool VisualScriptInputFilter::_get(const StringName& p_name,Variant &r_ret) cons } break; - case InputEvent::JOYSTICK_BUTTON: { + case InputEvent::JOYPAD_BUTTON: { if (what=="button_index") { r_ret=filters[idx].joy_button.button_index; @@ -1378,7 +1378,7 @@ bool VisualScriptInputFilter::_get(const StringName& p_name,Variant &r_ret) cons if (what=="action_name") { List<PropertyInfo> pinfo; - Globals::get_singleton()->get_property_list(&pinfo); + GlobalConfig::get_singleton()->get_property_list(&pinfo); int index=1; for(List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) { @@ -1417,8 +1417,8 @@ static const char* event_type_names[InputEvent::TYPE_MAX]={ "Key", "MouseMotion", "MouseButton", - "JoystickMotion", - "JoystickButton", + "JoypadMotion", + "JoypadButton", "ScreenTouch", "ScreenDrag", "Action" @@ -1489,13 +1489,13 @@ void VisualScriptInputFilter::_get_property_list( List<PropertyInfo> *p_list) co p_list->push_back(PropertyInfo(Variant::BOOL,base+"mod_meta")); } break; - case InputEvent::JOYSTICK_MOTION: { + case InputEvent::JOYPAD_MOTION: { p_list->push_back(PropertyInfo(Variant::INT,base+"axis_index")); p_list->push_back(PropertyInfo(Variant::INT,base+"mode",PROPERTY_HINT_ENUM,"Min,Max")); p_list->push_back(PropertyInfo(Variant::REAL,base+"treshold",PROPERTY_HINT_RANGE,"0,1,0.01")); } break; - case InputEvent::JOYSTICK_BUTTON: { + case InputEvent::JOYPAD_BUTTON: { p_list->push_back(PropertyInfo(Variant::INT,base+"button_index")); p_list->push_back(PropertyInfo(Variant::BOOL,base+"pressed")); @@ -1517,7 +1517,7 @@ void VisualScriptInputFilter::_get_property_list( List<PropertyInfo> *p_list) co actions="None"; List<PropertyInfo> pinfo; - Globals::get_singleton()->get_property_list(&pinfo); + GlobalConfig::get_singleton()->get_property_list(&pinfo); Vector<String> al; for(List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) { @@ -1632,10 +1632,10 @@ public: } break; - case InputEvent::JOYSTICK_MOTION: { + case InputEvent::JOYPAD_MOTION: { - InputEventJoystickMotion jm = ie.joy_motion; - InputEventJoystickMotion jm2 = event.joy_motion; + InputEventJoypadMotion jm = ie.joy_motion; + InputEventJoypadMotion jm2 = event.joy_motion; int axis = jm.axis>>1; @@ -1656,9 +1656,9 @@ public: } break; - case InputEvent::JOYSTICK_BUTTON: { - InputEventJoystickButton jb = ie.joy_button; - InputEventJoystickButton jb2 = event.joy_button; + case InputEvent::JOYPAD_BUTTON: { + InputEventJoypadButton jb = ie.joy_button; + InputEventJoypadButton jb2 = event.joy_button; if ( jb.button_index==jb2.button_index && jb.pressed == jb2.pressed @@ -1869,7 +1869,7 @@ public: return 1; //not found sorry } - if (ObjectTypeDB::is_type(obj->get_type_name(),base_type)) { + if (ClassDB::is_parent_class(obj->get_class_name(),base_type)) { *p_outputs[0]=*p_inputs[0]; //copy return 0; } else @@ -1893,11 +1893,11 @@ VisualScriptNodeInstance* VisualScriptTypeCast::instance(VisualScriptInstance* p void VisualScriptTypeCast::_bind_methods() { - ObjectTypeDB::bind_method(_MD("set_base_type","type"),&VisualScriptTypeCast::set_base_type); - ObjectTypeDB::bind_method(_MD("get_base_type"),&VisualScriptTypeCast::get_base_type); + ClassDB::bind_method(D_METHOD("set_base_type","type"),&VisualScriptTypeCast::set_base_type); + ClassDB::bind_method(D_METHOD("get_base_type"),&VisualScriptTypeCast::get_base_type); - ObjectTypeDB::bind_method(_MD("set_base_script","path"),&VisualScriptTypeCast::set_base_script); - ObjectTypeDB::bind_method(_MD("get_base_script"),&VisualScriptTypeCast::get_base_script); + ClassDB::bind_method(D_METHOD("set_base_script","path"),&VisualScriptTypeCast::set_base_script); + ClassDB::bind_method(D_METHOD("get_base_script"),&VisualScriptTypeCast::get_base_script); List<String> script_extensions; @@ -1912,8 +1912,8 @@ void VisualScriptTypeCast::_bind_methods() { script_ext_hint+="*."+E->get(); } - ADD_PROPERTY(PropertyInfo(Variant::STRING,"function/base_type",PROPERTY_HINT_TYPE_STRING,"Object"),_SCS("set_base_type"),_SCS("get_base_type")); - ADD_PROPERTY(PropertyInfo(Variant::STRING,"property/base_script",PROPERTY_HINT_FILE,script_ext_hint),_SCS("set_base_script"),_SCS("get_base_script")); + ADD_PROPERTY(PropertyInfo(Variant::STRING,"function/base_type",PROPERTY_HINT_TYPE_STRING,"Object"),"set_base_type","get_base_type"); + ADD_PROPERTY(PropertyInfo(Variant::STRING,"property/base_script",PROPERTY_HINT_FILE,script_ext_hint),"set_base_script","get_base_script"); } diff --git a/modules/visual_script/visual_script_flow_control.h b/modules/visual_script/visual_script_flow_control.h index e0da84a534..26e981cb1e 100644 --- a/modules/visual_script/visual_script_flow_control.h +++ b/modules/visual_script/visual_script_flow_control.h @@ -5,7 +5,7 @@ class VisualScriptReturn : public VisualScriptNode { - OBJ_TYPE(VisualScriptReturn,VisualScriptNode) + GDCLASS(VisualScriptReturn,VisualScriptNode) Variant::Type type; @@ -48,7 +48,7 @@ public: class VisualScriptCondition : public VisualScriptNode { - OBJ_TYPE(VisualScriptCondition,VisualScriptNode) + GDCLASS(VisualScriptCondition,VisualScriptNode) @@ -84,7 +84,7 @@ public: class VisualScriptWhile : public VisualScriptNode { - OBJ_TYPE(VisualScriptWhile,VisualScriptNode) + GDCLASS(VisualScriptWhile,VisualScriptNode) @@ -121,7 +121,7 @@ public: class VisualScriptIterator : public VisualScriptNode { - OBJ_TYPE(VisualScriptIterator,VisualScriptNode) + GDCLASS(VisualScriptIterator,VisualScriptNode) @@ -158,7 +158,7 @@ public: class VisualScriptSequence : public VisualScriptNode { - OBJ_TYPE(VisualScriptSequence,VisualScriptNode) + GDCLASS(VisualScriptSequence,VisualScriptNode) int steps; @@ -199,7 +199,7 @@ public: class VisualScriptSwitch : public VisualScriptNode { - OBJ_TYPE(VisualScriptSwitch,VisualScriptNode) + GDCLASS(VisualScriptSwitch,VisualScriptNode) struct Case { Variant::Type type; @@ -248,7 +248,7 @@ public: class VisualScriptInputFilter : public VisualScriptNode { - OBJ_TYPE(VisualScriptInputFilter,VisualScriptNode) + GDCLASS(VisualScriptInputFilter,VisualScriptNode) Vector<InputEvent> filters; @@ -290,7 +290,7 @@ public: class VisualScriptTypeCast : public VisualScriptNode { - OBJ_TYPE(VisualScriptTypeCast,VisualScriptNode) + GDCLASS(VisualScriptTypeCast,VisualScriptNode) StringName base_type; diff --git a/modules/visual_script/visual_script_func_nodes.cpp b/modules/visual_script/visual_script_func_nodes.cpp index de99beacaf..fd91385f9c 100644 --- a/modules/visual_script/visual_script_func_nodes.cpp +++ b/modules/visual_script/visual_script_func_nodes.cpp @@ -4,7 +4,7 @@ #include "scene/main/node.h" #include "visual_script_nodes.h" #include "io/resource_loader.h" -#include "globals.h" +#include "global_config.h" ////////////////////////////////////////// ////////////////CALL////////////////////// @@ -92,7 +92,7 @@ StringName VisualScriptFunctionCall::_get_base_type() const { else if (call_mode==CALL_MODE_NODE_PATH && get_visual_script().is_valid()) { Node *path = _get_base_node(); if (path) - return path->get_type(); + return path->get_class(); } @@ -110,7 +110,7 @@ int VisualScriptFunctionCall::get_input_value_port_count() const{ } else { - MethodBind *mb = ObjectTypeDB::get_method(_get_base_type(),function); + MethodBind *mb = ClassDB::get_method(_get_base_type(),function); if (mb) { return mb->get_argument_count() + (call_mode==CALL_MODE_INSTANCE?1:0) + (rpc_call_mode>=RPC_RELIABLE_TO_ID?1:0) - use_default_args; } @@ -129,7 +129,7 @@ int VisualScriptFunctionCall::get_output_value_port_count() const{ } else { int ret; - MethodBind *mb = ObjectTypeDB::get_method(_get_base_type(),function); + MethodBind *mb = ClassDB::get_method(_get_base_type(),function); if (mb) { ret = mb->has_return() ? 1 : 0; } else @@ -182,7 +182,7 @@ PropertyInfo VisualScriptFunctionCall::get_input_value_port_info(int p_idx) cons } else { - MethodBind *mb = ObjectTypeDB::get_method(_get_base_type(),function); + MethodBind *mb = ClassDB::get_method(_get_base_type(),function); if (mb) { return mb->get_argument_info(p_idx); } @@ -220,7 +220,7 @@ PropertyInfo VisualScriptFunctionCall::get_output_value_port_info(int p_idx) con PropertyInfo ret; - /*MethodBind *mb = ObjectTypeDB::get_method(_get_base_type(),function); + /*MethodBind *mb = ClassDB::get_method(_get_base_type(),function); if (mb) { ret = mb->get_argument_info(-1); @@ -332,9 +332,9 @@ void VisualScriptFunctionCall::set_singleton(const StringName& p_path) { return; singleton=p_path; - Object *obj = Globals::get_singleton()->get_singleton_object(singleton); + Object *obj = GlobalConfig::get_singleton()->get_singleton_object(singleton); if (obj) { - base_type=obj->get_type(); + base_type=obj->get_class(); } _change_notify(); @@ -356,7 +356,7 @@ void VisualScriptFunctionCall::_update_method_cache() { Node* node=_get_base_node(); if (node) { - type=node->get_type(); + type=node->get_class(); base_type=type; //cache, too script = node->get_script(); } @@ -370,9 +370,9 @@ void VisualScriptFunctionCall::_update_method_cache() { } else if (call_mode==CALL_MODE_SINGLETON) { - Object *obj = Globals::get_singleton()->get_singleton_object(singleton); + Object *obj = GlobalConfig::get_singleton()->get_singleton_object(singleton); if (obj) { - type=obj->get_type(); + type=obj->get_class(); script=obj->get_script(); } @@ -396,8 +396,8 @@ void VisualScriptFunctionCall::_update_method_cache() { } -// print_line("BASE: "+String(type)+" FUNC: "+String(function)); - MethodBind *mb = ObjectTypeDB::get_method(type,function); + //print_line("BASE: "+String(type)+" FUNC: "+String(function)); + MethodBind *mb = ClassDB::get_method(type,function); if (mb) { use_default_args=mb->get_default_argument_count(); method_cache = MethodInfo(); @@ -417,6 +417,14 @@ void VisualScriptFunctionCall::_update_method_cache() { method_cache.return_val = mb->get_argument_info(-1); #endif + + if (mb->is_vararg()) { + //for vararg just give it 10 arguments (should be enough for most use cases) + for(int i=0;i<10;i++) { + method_cache.arguments.push_back(PropertyInfo(Variant::NIL,"arg"+itos(i))); + use_default_args++; + } + } } else if (script.is_valid() && script->has_method(function)) { method_cache = script->get_method_info(function); @@ -559,11 +567,11 @@ void VisualScriptFunctionCall::_validate_property(PropertyInfo& property) const if (call_mode!=CALL_MODE_SINGLETON) { property.usage=0; } else { - List<Globals::Singleton> names; - Globals::get_singleton()->get_singletons(&names); + List<GlobalConfig::Singleton> names; + GlobalConfig::get_singleton()->get_singletons(&names); property.hint=PROPERTY_HINT_ENUM; String sl; - for (List<Globals::Singleton>::Element *E=names.front();E;E=E->next()) { + for (List<GlobalConfig::Singleton>::Element *E=names.front();E;E=E->next()) { if (sl!=String()) sl+=","; sl+=E->get().name; @@ -599,7 +607,7 @@ void VisualScriptFunctionCall::_validate_property(PropertyInfo& property) const property.hint_string=itos(get_visual_script()->get_instance_ID()); } else if (call_mode==CALL_MODE_SINGLETON) { - Object *obj = Globals::get_singleton()->get_singleton_object(singleton); + Object *obj = GlobalConfig::get_singleton()->get_singleton_object(singleton); if (obj) { property.hint=PROPERTY_HINT_METHOD_OF_INSTANCE; property.hint_string=itos(obj->get_instance_ID()); @@ -653,7 +661,7 @@ void VisualScriptFunctionCall::_validate_property(PropertyInfo& property) const mc = Variant::get_method_default_arguments(basic_type,function).size(); } else { - MethodBind *mb = ObjectTypeDB::get_method(_get_base_type(),function); + MethodBind *mb = ClassDB::get_method(_get_base_type(),function); if (mb) { mc=mb->get_default_argument_count(); @@ -679,38 +687,38 @@ void VisualScriptFunctionCall::_validate_property(PropertyInfo& property) const void VisualScriptFunctionCall::_bind_methods() { - ObjectTypeDB::bind_method(_MD("set_base_type","base_type"),&VisualScriptFunctionCall::set_base_type); - ObjectTypeDB::bind_method(_MD("get_base_type"),&VisualScriptFunctionCall::get_base_type); + ClassDB::bind_method(D_METHOD("set_base_type","base_type"),&VisualScriptFunctionCall::set_base_type); + ClassDB::bind_method(D_METHOD("get_base_type"),&VisualScriptFunctionCall::get_base_type); - ObjectTypeDB::bind_method(_MD("set_base_script","base_script"),&VisualScriptFunctionCall::set_base_script); - ObjectTypeDB::bind_method(_MD("get_base_script"),&VisualScriptFunctionCall::get_base_script); + ClassDB::bind_method(D_METHOD("set_base_script","base_script"),&VisualScriptFunctionCall::set_base_script); + ClassDB::bind_method(D_METHOD("get_base_script"),&VisualScriptFunctionCall::get_base_script); - ObjectTypeDB::bind_method(_MD("set_basic_type","basic_type"),&VisualScriptFunctionCall::set_basic_type); - ObjectTypeDB::bind_method(_MD("get_basic_type"),&VisualScriptFunctionCall::get_basic_type); + ClassDB::bind_method(D_METHOD("set_basic_type","basic_type"),&VisualScriptFunctionCall::set_basic_type); + ClassDB::bind_method(D_METHOD("get_basic_type"),&VisualScriptFunctionCall::get_basic_type); - ObjectTypeDB::bind_method(_MD("set_singleton","singleton"),&VisualScriptFunctionCall::set_singleton); - ObjectTypeDB::bind_method(_MD("get_singleton"),&VisualScriptFunctionCall::get_singleton); + ClassDB::bind_method(D_METHOD("set_singleton","singleton"),&VisualScriptFunctionCall::set_singleton); + ClassDB::bind_method(D_METHOD("get_singleton"),&VisualScriptFunctionCall::get_singleton); - ObjectTypeDB::bind_method(_MD("set_function","function"),&VisualScriptFunctionCall::set_function); - ObjectTypeDB::bind_method(_MD("get_function"),&VisualScriptFunctionCall::get_function); + ClassDB::bind_method(D_METHOD("set_function","function"),&VisualScriptFunctionCall::set_function); + ClassDB::bind_method(D_METHOD("get_function"),&VisualScriptFunctionCall::get_function); - ObjectTypeDB::bind_method(_MD("set_call_mode","mode"),&VisualScriptFunctionCall::set_call_mode); - ObjectTypeDB::bind_method(_MD("get_call_mode"),&VisualScriptFunctionCall::get_call_mode); + ClassDB::bind_method(D_METHOD("set_call_mode","mode"),&VisualScriptFunctionCall::set_call_mode); + ClassDB::bind_method(D_METHOD("get_call_mode"),&VisualScriptFunctionCall::get_call_mode); - ObjectTypeDB::bind_method(_MD("set_base_path","base_path"),&VisualScriptFunctionCall::set_base_path); - ObjectTypeDB::bind_method(_MD("get_base_path"),&VisualScriptFunctionCall::get_base_path); + ClassDB::bind_method(D_METHOD("set_base_path","base_path"),&VisualScriptFunctionCall::set_base_path); + ClassDB::bind_method(D_METHOD("get_base_path"),&VisualScriptFunctionCall::get_base_path); - ObjectTypeDB::bind_method(_MD("set_use_default_args","amount"),&VisualScriptFunctionCall::set_use_default_args); - ObjectTypeDB::bind_method(_MD("get_use_default_args"),&VisualScriptFunctionCall::get_use_default_args); + ClassDB::bind_method(D_METHOD("set_use_default_args","amount"),&VisualScriptFunctionCall::set_use_default_args); + ClassDB::bind_method(D_METHOD("get_use_default_args"),&VisualScriptFunctionCall::get_use_default_args); - ObjectTypeDB::bind_method(_MD("_set_argument_cache","argument_cache"),&VisualScriptFunctionCall::_set_argument_cache); - ObjectTypeDB::bind_method(_MD("_get_argument_cache"),&VisualScriptFunctionCall::_get_argument_cache); + ClassDB::bind_method(D_METHOD("_set_argument_cache","argument_cache"),&VisualScriptFunctionCall::_set_argument_cache); + ClassDB::bind_method(D_METHOD("_get_argument_cache"),&VisualScriptFunctionCall::_get_argument_cache); - ObjectTypeDB::bind_method(_MD("set_rpc_call_mode","mode"),&VisualScriptFunctionCall::set_rpc_call_mode); - ObjectTypeDB::bind_method(_MD("get_rpc_call_mode"),&VisualScriptFunctionCall::get_rpc_call_mode); + ClassDB::bind_method(D_METHOD("set_rpc_call_mode","mode"),&VisualScriptFunctionCall::set_rpc_call_mode); + ClassDB::bind_method(D_METHOD("get_rpc_call_mode"),&VisualScriptFunctionCall::get_rpc_call_mode); - ObjectTypeDB::bind_method(_MD("set_validate","enable"),&VisualScriptFunctionCall::set_validate); - ObjectTypeDB::bind_method(_MD("get_validate"),&VisualScriptFunctionCall::get_validate); + ClassDB::bind_method(D_METHOD("set_validate","enable"),&VisualScriptFunctionCall::set_validate); + ClassDB::bind_method(D_METHOD("get_validate"),&VisualScriptFunctionCall::get_validate); String bt; for(int i=0;i<Variant::VARIANT_MAX;i++) { @@ -735,17 +743,17 @@ void VisualScriptFunctionCall::_bind_methods() { - ADD_PROPERTY(PropertyInfo(Variant::INT,"function/call_mode",PROPERTY_HINT_ENUM,"Self,Node Path,Instance,Basic Type,Singleton"),_SCS("set_call_mode"),_SCS("get_call_mode")); - ADD_PROPERTY(PropertyInfo(Variant::STRING,"function/base_type",PROPERTY_HINT_TYPE_STRING,"Object"),_SCS("set_base_type"),_SCS("get_base_type")); - ADD_PROPERTY(PropertyInfo(Variant::STRING,"function/base_script",PROPERTY_HINT_FILE,script_ext_hint),_SCS("set_base_script"),_SCS("get_base_script")); - ADD_PROPERTY(PropertyInfo(Variant::STRING,"function/singleton"),_SCS("set_singleton"),_SCS("get_singleton")); - ADD_PROPERTY(PropertyInfo(Variant::INT,"function/basic_type",PROPERTY_HINT_ENUM,bt),_SCS("set_basic_type"),_SCS("get_basic_type")); - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH,"function/node_path",PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE),_SCS("set_base_path"),_SCS("get_base_path")); - ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY,"function/argument_cache",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_argument_cache"),_SCS("_get_argument_cache")); - ADD_PROPERTY(PropertyInfo(Variant::STRING,"function/function"),_SCS("set_function"),_SCS("get_function")); //when set, if loaded properly, will override argument count. - ADD_PROPERTY(PropertyInfo(Variant::INT,"function/use_default_args"),_SCS("set_use_default_args"),_SCS("get_use_default_args")); - ADD_PROPERTY(PropertyInfo(Variant::BOOL,"function/validate"),_SCS("set_validate"),_SCS("get_validate")); - ADD_PROPERTY(PropertyInfo(Variant::INT,"rpc/call_mode",PROPERTY_HINT_ENUM,"Disabled,Reliable,Unreliable,ReliableToID,UnreliableToID"),_SCS("set_rpc_call_mode"),_SCS("get_rpc_call_mode")); //when set, if loaded properly, will override argument count. + ADD_PROPERTY(PropertyInfo(Variant::INT,"function/call_mode",PROPERTY_HINT_ENUM,"Self,Node Path,Instance,Basic Type,Singleton"),"set_call_mode","get_call_mode"); + ADD_PROPERTY(PropertyInfo(Variant::STRING,"function/base_type",PROPERTY_HINT_TYPE_STRING,"Object"),"set_base_type","get_base_type"); + ADD_PROPERTY(PropertyInfo(Variant::STRING,"function/base_script",PROPERTY_HINT_FILE,script_ext_hint),"set_base_script","get_base_script"); + ADD_PROPERTY(PropertyInfo(Variant::STRING,"function/singleton"),"set_singleton","get_singleton"); + ADD_PROPERTY(PropertyInfo(Variant::INT,"function/basic_type",PROPERTY_HINT_ENUM,bt),"set_basic_type","get_basic_type"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH,"function/node_path",PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE),"set_base_path","get_base_path"); + ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY,"function/argument_cache",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),"_set_argument_cache","_get_argument_cache"); + ADD_PROPERTY(PropertyInfo(Variant::STRING,"function/function"),"set_function","get_function"); //when set, if loaded properly, will override argument count. + ADD_PROPERTY(PropertyInfo(Variant::INT,"function/use_default_args"),"set_use_default_args","get_use_default_args"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL,"function/validate"),"set_validate","get_validate"); + ADD_PROPERTY(PropertyInfo(Variant::INT,"rpc/call_mode",PROPERTY_HINT_ENUM,"Disabled,Reliable,Unreliable,ReliableToID,UnreliableToID"),"set_rpc_call_mode","get_rpc_call_mode"); //when set, if loaded properly, will override argument count. BIND_CONSTANT( CALL_MODE_SELF ); BIND_CONSTANT( CALL_MODE_NODE_PATH); @@ -873,7 +881,7 @@ public: } break; case VisualScriptFunctionCall::CALL_MODE_SINGLETON: { - Object *object=Globals::get_singleton()->get_singleton_object(singleton); + Object *object=GlobalConfig::get_singleton()->get_singleton_object(singleton); if (!object) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; r_error_str="Invalid singleton name: '"+String(singleton)+"'"; @@ -963,8 +971,8 @@ static const char* event_type_names[InputEvent::TYPE_MAX]={ "Key", "MouseMotion", "MouseButton", - "JoystickMotion", - "JoystickButton", + "JoypadMotion", + "JoypadButton", "ScreenTouch", "ScreenDrag", "Action" @@ -1026,7 +1034,7 @@ StringName VisualScriptPropertySet::_get_base_type() const { else if (call_mode==CALL_MODE_NODE_PATH && get_visual_script().is_valid()) { Node *path = _get_base_node(); if (path) - return path->get_type(); + return path->get_class(); } @@ -1114,7 +1122,7 @@ void VisualScriptPropertySet::_update_base_type() { Node* node=_get_base_node(); if (node) { - base_type=node->get_type(); + base_type=node->get_class(); } } else if (call_mode==CALL_MODE_SELF) { @@ -1239,7 +1247,7 @@ void VisualScriptPropertySet::_update_cache() { node=_get_base_node(); if (node) { - type=node->get_type(); + type=node->get_class(); base_type=type; //cache, too script = node->get_script(); } @@ -1276,7 +1284,7 @@ void VisualScriptPropertySet::_update_cache() { node->get_property_list(&pinfo); } else { - ObjectTypeDB::get_property_list(type,&pinfo); + ClassDB::get_property_list(type,&pinfo); } if (script.is_valid()) { @@ -1445,29 +1453,29 @@ void VisualScriptPropertySet::_validate_property(PropertyInfo& property) const { void VisualScriptPropertySet::_bind_methods() { - ObjectTypeDB::bind_method(_MD("set_base_type","base_type"),&VisualScriptPropertySet::set_base_type); - ObjectTypeDB::bind_method(_MD("get_base_type"),&VisualScriptPropertySet::get_base_type); + ClassDB::bind_method(D_METHOD("set_base_type","base_type"),&VisualScriptPropertySet::set_base_type); + ClassDB::bind_method(D_METHOD("get_base_type"),&VisualScriptPropertySet::get_base_type); - ObjectTypeDB::bind_method(_MD("set_base_script","base_script"),&VisualScriptPropertySet::set_base_script); - ObjectTypeDB::bind_method(_MD("get_base_script"),&VisualScriptPropertySet::get_base_script); + ClassDB::bind_method(D_METHOD("set_base_script","base_script"),&VisualScriptPropertySet::set_base_script); + ClassDB::bind_method(D_METHOD("get_base_script"),&VisualScriptPropertySet::get_base_script); - ObjectTypeDB::bind_method(_MD("set_basic_type","basic_type"),&VisualScriptPropertySet::set_basic_type); - ObjectTypeDB::bind_method(_MD("get_basic_type"),&VisualScriptPropertySet::get_basic_type); + ClassDB::bind_method(D_METHOD("set_basic_type","basic_type"),&VisualScriptPropertySet::set_basic_type); + ClassDB::bind_method(D_METHOD("get_basic_type"),&VisualScriptPropertySet::get_basic_type); - ObjectTypeDB::bind_method(_MD("_set_type_cache","type_cache"),&VisualScriptPropertySet::_set_type_cache); - ObjectTypeDB::bind_method(_MD("_get_type_cache"),&VisualScriptPropertySet::_get_type_cache); + ClassDB::bind_method(D_METHOD("_set_type_cache","type_cache"),&VisualScriptPropertySet::_set_type_cache); + ClassDB::bind_method(D_METHOD("_get_type_cache"),&VisualScriptPropertySet::_get_type_cache); - ObjectTypeDB::bind_method(_MD("set_event_type","event_type"),&VisualScriptPropertySet::set_event_type); - ObjectTypeDB::bind_method(_MD("get_event_type"),&VisualScriptPropertySet::get_event_type); + ClassDB::bind_method(D_METHOD("set_event_type","event_type"),&VisualScriptPropertySet::set_event_type); + ClassDB::bind_method(D_METHOD("get_event_type"),&VisualScriptPropertySet::get_event_type); - ObjectTypeDB::bind_method(_MD("set_property","property"),&VisualScriptPropertySet::set_property); - ObjectTypeDB::bind_method(_MD("get_property"),&VisualScriptPropertySet::get_property); + ClassDB::bind_method(D_METHOD("set_property","property"),&VisualScriptPropertySet::set_property); + ClassDB::bind_method(D_METHOD("get_property"),&VisualScriptPropertySet::get_property); - ObjectTypeDB::bind_method(_MD("set_call_mode","mode"),&VisualScriptPropertySet::set_call_mode); - ObjectTypeDB::bind_method(_MD("get_call_mode"),&VisualScriptPropertySet::get_call_mode); + ClassDB::bind_method(D_METHOD("set_call_mode","mode"),&VisualScriptPropertySet::set_call_mode); + ClassDB::bind_method(D_METHOD("get_call_mode"),&VisualScriptPropertySet::get_call_mode); - ObjectTypeDB::bind_method(_MD("set_base_path","base_path"),&VisualScriptPropertySet::set_base_path); - ObjectTypeDB::bind_method(_MD("get_base_path"),&VisualScriptPropertySet::get_base_path); + ClassDB::bind_method(D_METHOD("set_base_path","base_path"),&VisualScriptPropertySet::set_base_path); + ClassDB::bind_method(D_METHOD("get_base_path"),&VisualScriptPropertySet::get_base_path); @@ -1499,14 +1507,14 @@ void VisualScriptPropertySet::_bind_methods() { script_ext_hint+="*."+E->get(); } - ADD_PROPERTY(PropertyInfo(Variant::INT,"property/set_mode",PROPERTY_HINT_ENUM,"Self,Node Path,Instance,Basic Type"),_SCS("set_call_mode"),_SCS("get_call_mode")); - ADD_PROPERTY(PropertyInfo(Variant::STRING,"property/base_type",PROPERTY_HINT_TYPE_STRING,"Object"),_SCS("set_base_type"),_SCS("get_base_type")); - ADD_PROPERTY(PropertyInfo(Variant::STRING,"property/base_script",PROPERTY_HINT_FILE,script_ext_hint),_SCS("set_base_script"),_SCS("get_base_script")); - ADD_PROPERTY(PropertyInfo(Variant::INT,"property/type_cache",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_type_cache"),_SCS("_get_type_cache")); - ADD_PROPERTY(PropertyInfo(Variant::INT,"property/basic_type",PROPERTY_HINT_ENUM,bt),_SCS("set_basic_type"),_SCS("get_basic_type")); - ADD_PROPERTY(PropertyInfo(Variant::INT,"property/event_type",PROPERTY_HINT_ENUM,et),_SCS("set_event_type"),_SCS("get_event_type")); - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH,"property/node_path",PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE),_SCS("set_base_path"),_SCS("get_base_path")); - ADD_PROPERTY(PropertyInfo(Variant::STRING,"property/property"),_SCS("set_property"),_SCS("get_property")); + ADD_PROPERTY(PropertyInfo(Variant::INT,"property/set_mode",PROPERTY_HINT_ENUM,"Self,Node Path,Instance,Basic Type"),"set_call_mode","get_call_mode"); + ADD_PROPERTY(PropertyInfo(Variant::STRING,"property/base_type",PROPERTY_HINT_TYPE_STRING,"Object"),"set_base_type","get_base_type"); + ADD_PROPERTY(PropertyInfo(Variant::STRING,"property/base_script",PROPERTY_HINT_FILE,script_ext_hint),"set_base_script","get_base_script"); + ADD_PROPERTY(PropertyInfo(Variant::INT,"property/type_cache",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),"_set_type_cache","_get_type_cache"); + ADD_PROPERTY(PropertyInfo(Variant::INT,"property/basic_type",PROPERTY_HINT_ENUM,bt),"set_basic_type","get_basic_type"); + ADD_PROPERTY(PropertyInfo(Variant::INT,"property/event_type",PROPERTY_HINT_ENUM,et),"set_event_type","get_event_type"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH,"property/node_path",PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE),"set_base_path","get_base_path"); + ADD_PROPERTY(PropertyInfo(Variant::STRING,"property/property"),"set_property","get_property"); BIND_CONSTANT( CALL_MODE_SELF ); BIND_CONSTANT( CALL_MODE_NODE_PATH); @@ -1546,7 +1554,7 @@ public: if (!valid) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; - r_error_str="Invalid set value '"+String(*p_inputs[0])+"' on property '"+String(property)+"' of type "+object->get_type(); + r_error_str="Invalid set value '"+String(*p_inputs[0])+"' on property '"+String(property)+"' of type "+object->get_class(); } } break; case VisualScriptPropertySet::CALL_MODE_NODE_PATH: { @@ -1571,7 +1579,7 @@ public: if (!valid) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; - r_error_str="Invalid set value '"+String(*p_inputs[0])+"' on property '"+String(property)+"' of type "+another->get_type(); + r_error_str="Invalid set value '"+String(*p_inputs[0])+"' on property '"+String(property)+"' of type "+another->get_class(); } } break; @@ -1661,7 +1669,7 @@ void VisualScriptPropertyGet::_update_base_type() { Node* node=_get_base_node(); if (node) { - base_type=node->get_type(); + base_type=node->get_class(); } } else if (call_mode==CALL_MODE_SELF) { @@ -1716,7 +1724,7 @@ StringName VisualScriptPropertyGet::_get_base_type() const { else if (call_mode==CALL_MODE_NODE_PATH && get_visual_script().is_valid()) { Node *path = _get_base_node(); if (path) - return path->get_type(); + return path->get_class(); } @@ -1860,7 +1868,7 @@ void VisualScriptPropertyGet::_update_cache() { node=_get_base_node(); if (node) { - type=node->get_type(); + type=node->get_class(); base_type=type; //cache, too script = node->get_script(); } @@ -1895,7 +1903,7 @@ void VisualScriptPropertyGet::_update_cache() { Variant::Type type_ret; - type_ret=ObjectTypeDB::get_property_type(base_type,property,&valid); + type_ret=ClassDB::get_property_type(base_type,property,&valid); if (valid) { type_cache=type_ret; @@ -2109,30 +2117,30 @@ void VisualScriptPropertyGet::_validate_property(PropertyInfo& property) const { void VisualScriptPropertyGet::_bind_methods() { - ObjectTypeDB::bind_method(_MD("set_base_type","base_type"),&VisualScriptPropertyGet::set_base_type); - ObjectTypeDB::bind_method(_MD("get_base_type"),&VisualScriptPropertyGet::get_base_type); + ClassDB::bind_method(D_METHOD("set_base_type","base_type"),&VisualScriptPropertyGet::set_base_type); + ClassDB::bind_method(D_METHOD("get_base_type"),&VisualScriptPropertyGet::get_base_type); - ObjectTypeDB::bind_method(_MD("set_base_script","base_script"),&VisualScriptPropertyGet::set_base_script); - ObjectTypeDB::bind_method(_MD("get_base_script"),&VisualScriptPropertyGet::get_base_script); + ClassDB::bind_method(D_METHOD("set_base_script","base_script"),&VisualScriptPropertyGet::set_base_script); + ClassDB::bind_method(D_METHOD("get_base_script"),&VisualScriptPropertyGet::get_base_script); - ObjectTypeDB::bind_method(_MD("set_basic_type","basic_type"),&VisualScriptPropertyGet::set_basic_type); - ObjectTypeDB::bind_method(_MD("get_basic_type"),&VisualScriptPropertyGet::get_basic_type); + ClassDB::bind_method(D_METHOD("set_basic_type","basic_type"),&VisualScriptPropertyGet::set_basic_type); + ClassDB::bind_method(D_METHOD("get_basic_type"),&VisualScriptPropertyGet::get_basic_type); - ObjectTypeDB::bind_method(_MD("_set_type_cache","type_cache"),&VisualScriptPropertyGet::_set_type_cache); - ObjectTypeDB::bind_method(_MD("_get_type_cache"),&VisualScriptPropertyGet::_get_type_cache); + ClassDB::bind_method(D_METHOD("_set_type_cache","type_cache"),&VisualScriptPropertyGet::_set_type_cache); + ClassDB::bind_method(D_METHOD("_get_type_cache"),&VisualScriptPropertyGet::_get_type_cache); - ObjectTypeDB::bind_method(_MD("set_event_type","event_type"),&VisualScriptPropertyGet::set_event_type); - ObjectTypeDB::bind_method(_MD("get_event_type"),&VisualScriptPropertyGet::get_event_type); + ClassDB::bind_method(D_METHOD("set_event_type","event_type"),&VisualScriptPropertyGet::set_event_type); + ClassDB::bind_method(D_METHOD("get_event_type"),&VisualScriptPropertyGet::get_event_type); - ObjectTypeDB::bind_method(_MD("set_property","property"),&VisualScriptPropertyGet::set_property); - ObjectTypeDB::bind_method(_MD("get_property"),&VisualScriptPropertyGet::get_property); + ClassDB::bind_method(D_METHOD("set_property","property"),&VisualScriptPropertyGet::set_property); + ClassDB::bind_method(D_METHOD("get_property"),&VisualScriptPropertyGet::get_property); - ObjectTypeDB::bind_method(_MD("set_call_mode","mode"),&VisualScriptPropertyGet::set_call_mode); - ObjectTypeDB::bind_method(_MD("get_call_mode"),&VisualScriptPropertyGet::get_call_mode); + ClassDB::bind_method(D_METHOD("set_call_mode","mode"),&VisualScriptPropertyGet::set_call_mode); + ClassDB::bind_method(D_METHOD("get_call_mode"),&VisualScriptPropertyGet::get_call_mode); - ObjectTypeDB::bind_method(_MD("set_base_path","base_path"),&VisualScriptPropertyGet::set_base_path); - ObjectTypeDB::bind_method(_MD("get_base_path"),&VisualScriptPropertyGet::get_base_path); + ClassDB::bind_method(D_METHOD("set_base_path","base_path"),&VisualScriptPropertyGet::set_base_path); + ClassDB::bind_method(D_METHOD("get_base_path"),&VisualScriptPropertyGet::get_base_path); String bt; for(int i=0;i<Variant::VARIANT_MAX;i++) { @@ -2162,14 +2170,14 @@ void VisualScriptPropertyGet::_bind_methods() { script_ext_hint+="."+E->get(); } - ADD_PROPERTY(PropertyInfo(Variant::INT,"property/set_mode",PROPERTY_HINT_ENUM,"Self,Node Path,Instance,Basic Type"),_SCS("set_call_mode"),_SCS("get_call_mode")); - ADD_PROPERTY(PropertyInfo(Variant::STRING,"property/base_type",PROPERTY_HINT_TYPE_STRING,"Object"),_SCS("set_base_type"),_SCS("get_base_type")); - ADD_PROPERTY(PropertyInfo(Variant::STRING,"property/base_script",PROPERTY_HINT_FILE,script_ext_hint),_SCS("set_base_script"),_SCS("get_base_script")); - ADD_PROPERTY(PropertyInfo(Variant::INT,"property/type_cache",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_type_cache"),_SCS("_get_type_cache")); - ADD_PROPERTY(PropertyInfo(Variant::INT,"property/basic_type",PROPERTY_HINT_ENUM,bt),_SCS("set_basic_type"),_SCS("get_basic_type")); - ADD_PROPERTY(PropertyInfo(Variant::INT,"property/event_type",PROPERTY_HINT_ENUM,et),_SCS("set_event_type"),_SCS("get_event_type")); - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH,"property/node_path",PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE),_SCS("set_base_path"),_SCS("get_base_path")); - ADD_PROPERTY(PropertyInfo(Variant::STRING,"property/property"),_SCS("set_property"),_SCS("get_property")); + ADD_PROPERTY(PropertyInfo(Variant::INT,"property/set_mode",PROPERTY_HINT_ENUM,"Self,Node Path,Instance,Basic Type"),"set_call_mode","get_call_mode"); + ADD_PROPERTY(PropertyInfo(Variant::STRING,"property/base_type",PROPERTY_HINT_TYPE_STRING,"Object"),"set_base_type","get_base_type"); + ADD_PROPERTY(PropertyInfo(Variant::STRING,"property/base_script",PROPERTY_HINT_FILE,script_ext_hint),"set_base_script","get_base_script"); + ADD_PROPERTY(PropertyInfo(Variant::INT,"property/type_cache",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),"_set_type_cache","_get_type_cache"); + ADD_PROPERTY(PropertyInfo(Variant::INT,"property/basic_type",PROPERTY_HINT_ENUM,bt),"set_basic_type","get_basic_type"); + ADD_PROPERTY(PropertyInfo(Variant::INT,"property/event_type",PROPERTY_HINT_ENUM,et),"set_event_type","get_event_type"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH,"property/node_path",PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE),"set_base_path","get_base_path"); + ADD_PROPERTY(PropertyInfo(Variant::STRING,"property/property"),"set_property","get_property"); BIND_CONSTANT( CALL_MODE_SELF ); BIND_CONSTANT( CALL_MODE_NODE_PATH); @@ -2412,11 +2420,11 @@ void VisualScriptEmitSignal::_validate_property(PropertyInfo& property) const { void VisualScriptEmitSignal::_bind_methods() { - ObjectTypeDB::bind_method(_MD("set_signal","name"),&VisualScriptEmitSignal::set_signal); - ObjectTypeDB::bind_method(_MD("get_signal"),&VisualScriptEmitSignal::get_signal); + ClassDB::bind_method(D_METHOD("set_signal","name"),&VisualScriptEmitSignal::set_signal); + ClassDB::bind_method(D_METHOD("get_signal"),&VisualScriptEmitSignal::get_signal); - ADD_PROPERTY(PropertyInfo(Variant::STRING,"signal/signal"),_SCS("set_signal"),_SCS("get_signal")); + ADD_PROPERTY(PropertyInfo(Variant::STRING,"signal/signal"),"set_signal","get_signal"); } @@ -2500,7 +2508,7 @@ void register_visual_script_func_nodes() { VisualScriptLanguage::singleton->add_register_func("functions/get",create_node_generic<VisualScriptPropertyGet>); //VisualScriptLanguage::singleton->add_register_func("functions/call_script/call_self",create_script_call_node<VisualScriptScriptCall::CALL_MODE_SELF>); -// VisualScriptLanguage::singleton->add_register_func("functions/call_script/call_node",create_script_call_node<VisualScriptScriptCall::CALL_MODE_NODE_PATH>); + //VisualScriptLanguage::singleton->add_register_func("functions/call_script/call_node",create_script_call_node<VisualScriptScriptCall::CALL_MODE_NODE_PATH>); VisualScriptLanguage::singleton->add_register_func("functions/emit_signal",create_node_generic<VisualScriptEmitSignal>); diff --git a/modules/visual_script/visual_script_func_nodes.h b/modules/visual_script/visual_script_func_nodes.h index 43ef276cf4..7d33549e21 100644 --- a/modules/visual_script/visual_script_func_nodes.h +++ b/modules/visual_script/visual_script_func_nodes.h @@ -6,7 +6,7 @@ class VisualScriptFunctionCall : public VisualScriptNode { - OBJ_TYPE(VisualScriptFunctionCall,VisualScriptNode) + GDCLASS(VisualScriptFunctionCall,VisualScriptNode) public: enum CallMode { CALL_MODE_SELF, @@ -117,7 +117,7 @@ VARIANT_ENUM_CAST(VisualScriptFunctionCall::RPCCallMode ); class VisualScriptPropertySet : public VisualScriptNode { - OBJ_TYPE(VisualScriptPropertySet,VisualScriptNode) + GDCLASS(VisualScriptPropertySet,VisualScriptNode) public: enum CallMode { CALL_MODE_SELF, @@ -208,7 +208,7 @@ VARIANT_ENUM_CAST(VisualScriptPropertySet::CallMode ); class VisualScriptPropertyGet : public VisualScriptNode { - OBJ_TYPE(VisualScriptPropertyGet,VisualScriptNode) + GDCLASS(VisualScriptPropertyGet,VisualScriptNode) public: enum CallMode { CALL_MODE_SELF, @@ -299,7 +299,7 @@ VARIANT_ENUM_CAST(VisualScriptPropertyGet::CallMode ); class VisualScriptEmitSignal : public VisualScriptNode { - OBJ_TYPE(VisualScriptEmitSignal,VisualScriptNode) + GDCLASS(VisualScriptEmitSignal,VisualScriptNode) private: diff --git a/modules/visual_script/visual_script_nodes.cpp b/modules/visual_script/visual_script_nodes.cpp index 7ada292b13..d1ee5be378 100644 --- a/modules/visual_script/visual_script_nodes.cpp +++ b/modules/visual_script/visual_script_nodes.cpp @@ -1,6 +1,6 @@ #include "visual_script_nodes.h" #include "global_constants.h" -#include "globals.h" +#include "global_config.h" #include "scene/main/scene_main_loop.h" #include "os/os.h" #include "scene/main/node.h" @@ -334,7 +334,7 @@ bool VisualScriptOperator::has_input_sequence_port() const{ int VisualScriptOperator::get_input_value_port_count() const{ - return (op==Variant::OP_BIT_NEGATE || op==Variant::OP_NOT || op==Variant::OP_NEGATE) ? 1 : 2; + return (op==Variant::OP_BIT_NEGATE || op==Variant::OP_NOT || op==Variant::OP_NEGATE || op==Variant::OP_POSITIVE) ? 1 : 2; } int VisualScriptOperator::get_output_value_port_count() const{ @@ -361,6 +361,7 @@ PropertyInfo VisualScriptOperator::get_input_value_port_info(int p_idx) const{ {Variant::NIL,Variant::NIL}, //OP_MULTIPLY, {Variant::NIL,Variant::NIL}, //OP_DIVIDE, {Variant::NIL,Variant::NIL}, //OP_NEGATE, + {Variant::NIL,Variant::NIL}, //OP_POSITIVE, {Variant::INT,Variant::INT}, //OP_MODULE, {Variant::STRING,Variant::STRING}, //OP_STRING_CONCAT, //bitwise @@ -403,6 +404,7 @@ PropertyInfo VisualScriptOperator::get_output_value_port_info(int p_idx) const{ Variant::NIL, //OP_MULTIPLY, Variant::NIL, //OP_DIVIDE, Variant::NIL, //OP_NEGATE, + Variant::NIL, //OP_POSITIVE, Variant::INT, //OP_MODULE, Variant::STRING, //OP_STRING_CONCAT, //bitwise @@ -444,6 +446,7 @@ static const char* op_names[]={ "Multiply", //OP_MULTIPLY, "Divide", //OP_DIVIDE, "Negate", //OP_NEGATE, + "Positive", //OP_POSITIVE, "Remainder", //OP_MODULE, "Concat", //OP_STRING_CONCAT, //bitwise @@ -485,6 +488,7 @@ String VisualScriptOperator::get_text() const { L"A x B", //OP_MULTIPLY, L"A \u00F7 B", //OP_DIVIDE, L"\u00AC A", //OP_NEGATE, + L"+ A", //OP_POSITIVE, L"A mod B", //OP_MODULE, L"A .. B", //OP_STRING_CONCAT, //bitwise @@ -535,11 +539,11 @@ Variant::Type VisualScriptOperator::get_typed() const { void VisualScriptOperator::_bind_methods() { - ObjectTypeDB::bind_method(_MD("set_operator","op"),&VisualScriptOperator::set_operator); - ObjectTypeDB::bind_method(_MD("get_operator"),&VisualScriptOperator::get_operator); + ClassDB::bind_method(D_METHOD("set_operator","op"),&VisualScriptOperator::set_operator); + ClassDB::bind_method(D_METHOD("get_operator"),&VisualScriptOperator::get_operator); - ObjectTypeDB::bind_method(_MD("set_typed","type"),&VisualScriptOperator::set_typed); - ObjectTypeDB::bind_method(_MD("get_typed"),&VisualScriptOperator::get_typed); + ClassDB::bind_method(D_METHOD("set_typed","type"),&VisualScriptOperator::set_typed); + ClassDB::bind_method(D_METHOD("get_typed"),&VisualScriptOperator::get_typed); String types; for(int i=0;i<Variant::OP_MAX;i++) { @@ -553,8 +557,8 @@ void VisualScriptOperator::_bind_methods() { argt+=","+Variant::get_type_name(Variant::Type(i)); } - ADD_PROPERTY(PropertyInfo(Variant::INT,"operator_value/type",PROPERTY_HINT_ENUM,types),_SCS("set_operator"),_SCS("get_operator")); - ADD_PROPERTY(PropertyInfo(Variant::INT,"typed_value/typed",PROPERTY_HINT_ENUM,argt),_SCS("set_typed"),_SCS("get_typed")); + ADD_PROPERTY(PropertyInfo(Variant::INT,"operator_value/type",PROPERTY_HINT_ENUM,types),"set_operator","get_operator"); + ADD_PROPERTY(PropertyInfo(Variant::INT,"typed_value/typed",PROPERTY_HINT_ENUM,argt),"set_typed","get_typed"); } @@ -713,11 +717,11 @@ void VisualScriptVariableGet::_validate_property(PropertyInfo& property) const { void VisualScriptVariableGet::_bind_methods() { - ObjectTypeDB::bind_method(_MD("set_variable","name"),&VisualScriptVariableGet::set_variable); - ObjectTypeDB::bind_method(_MD("get_variable"),&VisualScriptVariableGet::get_variable); + ClassDB::bind_method(D_METHOD("set_variable","name"),&VisualScriptVariableGet::set_variable); + ClassDB::bind_method(D_METHOD("get_variable"),&VisualScriptVariableGet::get_variable); - ADD_PROPERTY(PropertyInfo(Variant::STRING,"variable/name"),_SCS("set_variable"),_SCS("get_variable")); + ADD_PROPERTY(PropertyInfo(Variant::STRING,"variable/name"),"set_variable","get_variable"); } @@ -849,11 +853,11 @@ void VisualScriptVariableSet::_validate_property(PropertyInfo& property) const { void VisualScriptVariableSet::_bind_methods() { - ObjectTypeDB::bind_method(_MD("set_variable","name"),&VisualScriptVariableSet::set_variable); - ObjectTypeDB::bind_method(_MD("get_variable"),&VisualScriptVariableSet::get_variable); + ClassDB::bind_method(D_METHOD("set_variable","name"),&VisualScriptVariableSet::set_variable); + ClassDB::bind_method(D_METHOD("get_variable"),&VisualScriptVariableSet::get_variable); - ADD_PROPERTY(PropertyInfo(Variant::STRING,"variable/name"),_SCS("set_variable"),_SCS("get_variable")); + ADD_PROPERTY(PropertyInfo(Variant::STRING,"variable/name"),"set_variable","get_variable"); } @@ -991,11 +995,11 @@ void VisualScriptConstant::_validate_property(PropertyInfo& property) const { void VisualScriptConstant::_bind_methods() { - ObjectTypeDB::bind_method(_MD("set_constant_type","type"),&VisualScriptConstant::set_constant_type); - ObjectTypeDB::bind_method(_MD("get_constant_type"),&VisualScriptConstant::get_constant_type); + ClassDB::bind_method(D_METHOD("set_constant_type","type"),&VisualScriptConstant::set_constant_type); + ClassDB::bind_method(D_METHOD("get_constant_type"),&VisualScriptConstant::get_constant_type); - ObjectTypeDB::bind_method(_MD("set_constant_value","value"),&VisualScriptConstant::set_constant_value); - ObjectTypeDB::bind_method(_MD("get_constant_value"),&VisualScriptConstant::get_constant_value); + ClassDB::bind_method(D_METHOD("set_constant_value","value"),&VisualScriptConstant::set_constant_value); + ClassDB::bind_method(D_METHOD("get_constant_value"),&VisualScriptConstant::get_constant_value); String argt="Null"; for(int i=1;i<Variant::VARIANT_MAX;i++) { @@ -1003,8 +1007,8 @@ void VisualScriptConstant::_bind_methods() { } - ADD_PROPERTY(PropertyInfo(Variant::INT,"constant/type",PROPERTY_HINT_ENUM,argt),_SCS("set_constant_type"),_SCS("get_constant_type")); - ADD_PROPERTY(PropertyInfo(Variant::NIL,"constant/value"),_SCS("set_constant_value"),_SCS("get_constant_value")); + ADD_PROPERTY(PropertyInfo(Variant::INT,"constant/type",PROPERTY_HINT_ENUM,argt),"set_constant_type","get_constant_type"); + ADD_PROPERTY(PropertyInfo(Variant::NIL,"constant/value"),"set_constant_value","get_constant_value"); } @@ -1074,7 +1078,7 @@ PropertyInfo VisualScriptPreload::get_output_value_port_info(int p_idx) const{ PropertyInfo pinfo=PropertyInfo(Variant::OBJECT,"res"); if (preload.is_valid()) { pinfo.hint=PROPERTY_HINT_RESOURCE_TYPE; - pinfo.hint_string=preload->get_type(); + pinfo.hint_string=preload->get_class(); } return pinfo; @@ -1094,7 +1098,7 @@ String VisualScriptPreload::get_text() const { } else if (preload->get_name()!=String()) { return preload->get_name(); } else { - return preload->get_type(); + return preload->get_class(); } } else { return "<empty>"; @@ -1119,11 +1123,11 @@ Ref<Resource> VisualScriptPreload::get_preload() const{ void VisualScriptPreload::_bind_methods() { - ObjectTypeDB::bind_method(_MD("set_preload","resource"),&VisualScriptPreload::set_preload); - ObjectTypeDB::bind_method(_MD("get_preload"),&VisualScriptPreload::get_preload); + ClassDB::bind_method(D_METHOD("set_preload","resource"),&VisualScriptPreload::set_preload); + ClassDB::bind_method(D_METHOD("get_preload"),&VisualScriptPreload::get_preload); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"resource",PROPERTY_HINT_RESOURCE_TYPE,"Resource"),_SCS("set_preload"),_SCS("get_preload")); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"resource",PROPERTY_HINT_RESOURCE_TYPE,"Resource"),"set_preload","get_preload"); } @@ -1421,8 +1425,8 @@ VisualScriptNodeInstance* VisualScriptGlobalConstant::instance(VisualScriptInsta void VisualScriptGlobalConstant::_bind_methods() { - ObjectTypeDB::bind_method(_MD("set_global_constant","index"),&VisualScriptGlobalConstant::set_global_constant); - ObjectTypeDB::bind_method(_MD("get_global_constant"),&VisualScriptGlobalConstant::get_global_constant); + ClassDB::bind_method(D_METHOD("set_global_constant","index"),&VisualScriptGlobalConstant::set_global_constant); + ClassDB::bind_method(D_METHOD("get_global_constant"),&VisualScriptGlobalConstant::get_global_constant); String cc; @@ -1432,7 +1436,7 @@ void VisualScriptGlobalConstant::_bind_methods() { cc+=","; cc+=GlobalConstants::get_global_constant_name(i); } - ADD_PROPERTY(PropertyInfo(Variant::INT,"constant",PROPERTY_HINT_ENUM,cc),_SCS("set_global_constant"),_SCS("get_global_constant")); + ADD_PROPERTY(PropertyInfo(Variant::INT,"constant",PROPERTY_HINT_ENUM,cc),"set_global_constant","get_global_constant"); } VisualScriptGlobalConstant::VisualScriptGlobalConstant() { @@ -1536,7 +1540,7 @@ public: VisualScriptNodeInstance* VisualScriptClassConstant::instance(VisualScriptInstance* p_instance) { VisualScriptNodeInstanceClassConstant * instance = memnew(VisualScriptNodeInstanceClassConstant ); - instance->value=ObjectTypeDB::get_integer_constant(base_type,name,&instance->valid); + instance->value=ClassDB::get_integer_constant(base_type,name,&instance->valid); return instance; } @@ -1545,7 +1549,7 @@ void VisualScriptClassConstant::_validate_property(PropertyInfo& property) const if (property.name=="constant") { List<String> constants; - ObjectTypeDB::get_integer_constant_list(base_type,&constants,true); + ClassDB::get_integer_constant_list(base_type,&constants,true); property.hint_string=""; for(List<String>::Element *E=constants.front();E;E=E->next()) { @@ -1559,14 +1563,14 @@ void VisualScriptClassConstant::_validate_property(PropertyInfo& property) const void VisualScriptClassConstant::_bind_methods() { - ObjectTypeDB::bind_method(_MD("set_class_constant","name"),&VisualScriptClassConstant::set_class_constant); - ObjectTypeDB::bind_method(_MD("get_class_constant"),&VisualScriptClassConstant::get_class_constant); + ClassDB::bind_method(D_METHOD("set_class_constant","name"),&VisualScriptClassConstant::set_class_constant); + ClassDB::bind_method(D_METHOD("get_class_constant"),&VisualScriptClassConstant::get_class_constant); - ObjectTypeDB::bind_method(_MD("set_base_type","name"),&VisualScriptClassConstant::set_base_type); - ObjectTypeDB::bind_method(_MD("get_base_type"),&VisualScriptClassConstant::get_base_type); + ClassDB::bind_method(D_METHOD("set_base_type","name"),&VisualScriptClassConstant::set_base_type); + ClassDB::bind_method(D_METHOD("get_base_type"),&VisualScriptClassConstant::get_base_type); - ADD_PROPERTY(PropertyInfo(Variant::STRING,"base_type",PROPERTY_HINT_TYPE_STRING,"Object"),_SCS("set_base_type"),_SCS("get_base_type")); - ADD_PROPERTY(PropertyInfo(Variant::STRING,"constant",PROPERTY_HINT_ENUM,""),_SCS("set_class_constant"),_SCS("get_class_constant")); + ADD_PROPERTY(PropertyInfo(Variant::STRING,"base_type",PROPERTY_HINT_TYPE_STRING,"Object"),"set_base_type","get_base_type"); + ADD_PROPERTY(PropertyInfo(Variant::STRING,"constant",PROPERTY_HINT_ENUM,""),"set_class_constant","get_class_constant"); } VisualScriptClassConstant::VisualScriptClassConstant() { @@ -1699,11 +1703,11 @@ void VisualScriptBasicTypeConstant::_validate_property(PropertyInfo& property) c void VisualScriptBasicTypeConstant::_bind_methods() { - ObjectTypeDB::bind_method(_MD("set_basic_type","name"),&VisualScriptBasicTypeConstant::set_basic_type); - ObjectTypeDB::bind_method(_MD("get_basic_type"),&VisualScriptBasicTypeConstant::get_basic_type); + ClassDB::bind_method(D_METHOD("set_basic_type","name"),&VisualScriptBasicTypeConstant::set_basic_type); + ClassDB::bind_method(D_METHOD("get_basic_type"),&VisualScriptBasicTypeConstant::get_basic_type); - ObjectTypeDB::bind_method(_MD("set_basic_type_constant","name"),&VisualScriptBasicTypeConstant::set_basic_type_constant); - ObjectTypeDB::bind_method(_MD("get_basic_type_constant"),&VisualScriptBasicTypeConstant::get_basic_type_constant); + ClassDB::bind_method(D_METHOD("set_basic_type_constant","name"),&VisualScriptBasicTypeConstant::set_basic_type_constant); + ClassDB::bind_method(D_METHOD("get_basic_type_constant"),&VisualScriptBasicTypeConstant::get_basic_type_constant); String argt="Null"; @@ -1711,8 +1715,8 @@ void VisualScriptBasicTypeConstant::_bind_methods() { argt+=","+Variant::get_type_name(Variant::Type(i)); } - ADD_PROPERTY(PropertyInfo(Variant::INT,"basic_type",PROPERTY_HINT_ENUM,argt),_SCS("set_basic_type"),_SCS("get_basic_type")); - ADD_PROPERTY(PropertyInfo(Variant::STRING,"constant",PROPERTY_HINT_ENUM,""),_SCS("set_basic_type_constant"),_SCS("get_basic_type_constant")); + ADD_PROPERTY(PropertyInfo(Variant::INT,"basic_type",PROPERTY_HINT_ENUM,argt),"set_basic_type","get_basic_type"); + ADD_PROPERTY(PropertyInfo(Variant::STRING,"constant",PROPERTY_HINT_ENUM,""),"set_basic_type_constant","get_basic_type_constant"); } VisualScriptBasicTypeConstant::VisualScriptBasicTypeConstant() { @@ -1827,8 +1831,8 @@ VisualScriptNodeInstance* VisualScriptMathConstant::instance(VisualScriptInstanc void VisualScriptMathConstant::_bind_methods() { - ObjectTypeDB::bind_method(_MD("set_math_constant","which"),&VisualScriptMathConstant::set_math_constant); - ObjectTypeDB::bind_method(_MD("get_math_constant"),&VisualScriptMathConstant::get_math_constant); + ClassDB::bind_method(D_METHOD("set_math_constant","which"),&VisualScriptMathConstant::set_math_constant); + ClassDB::bind_method(D_METHOD("get_math_constant"),&VisualScriptMathConstant::get_math_constant); String cc; @@ -1838,7 +1842,7 @@ void VisualScriptMathConstant::_bind_methods() { cc+=","; cc+=const_name[i]; } - ADD_PROPERTY(PropertyInfo(Variant::INT,"constant",PROPERTY_HINT_ENUM,cc),_SCS("set_math_constant"),_SCS("get_math_constant")); + ADD_PROPERTY(PropertyInfo(Variant::INT,"constant",PROPERTY_HINT_ENUM,cc),"set_math_constant","get_math_constant"); } VisualScriptMathConstant::VisualScriptMathConstant() { @@ -1929,17 +1933,17 @@ public: VisualScriptNodeInstance* VisualScriptEngineSingleton::instance(VisualScriptInstance* p_instance) { VisualScriptNodeInstanceEngineSingleton * instance = memnew(VisualScriptNodeInstanceEngineSingleton ); - instance->singleton=Globals::get_singleton()->get_singleton_object(singleton); + instance->singleton=GlobalConfig::get_singleton()->get_singleton_object(singleton); return instance; } VisualScriptEngineSingleton::TypeGuess VisualScriptEngineSingleton::guess_output_type(TypeGuess* p_inputs, int p_output) const { - Object *obj=Globals::get_singleton()->get_singleton_object(singleton); + Object *obj=GlobalConfig::get_singleton()->get_singleton_object(singleton); TypeGuess tg; tg.type=Variant::OBJECT; if (obj) { - tg.obj_type=obj->get_type(); + tg.GDCLASS=obj->get_class(); tg.script=obj->get_script(); } @@ -1949,16 +1953,16 @@ VisualScriptEngineSingleton::TypeGuess VisualScriptEngineSingleton::guess_output void VisualScriptEngineSingleton::_bind_methods() { - ObjectTypeDB::bind_method(_MD("set_singleton","name"),&VisualScriptEngineSingleton::set_singleton); - ObjectTypeDB::bind_method(_MD("get_singleton"),&VisualScriptEngineSingleton::get_singleton); + ClassDB::bind_method(D_METHOD("set_singleton","name"),&VisualScriptEngineSingleton::set_singleton); + ClassDB::bind_method(D_METHOD("get_singleton"),&VisualScriptEngineSingleton::get_singleton); String cc; - List<Globals::Singleton> singletons; + List<GlobalConfig::Singleton> singletons; - Globals::get_singleton()->get_singletons(&singletons); + GlobalConfig::get_singleton()->get_singletons(&singletons); - for (List<Globals::Singleton>::Element *E=singletons.front();E;E=E->next()) { + for (List<GlobalConfig::Singleton>::Element *E=singletons.front();E;E=E->next()) { if (E->get().name=="VS" || E->get().name=="PS" || E->get().name=="PS2D" || E->get().name=="AS" || E->get().name=="TS" || E->get().name=="SS" || E->get().name=="SS2D") continue; //skip these, too simple named @@ -1967,7 +1971,7 @@ void VisualScriptEngineSingleton::_bind_methods() { cc+=E->get().name; } - ADD_PROPERTY(PropertyInfo(Variant::STRING,"constant",PROPERTY_HINT_ENUM,cc),_SCS("set_singleton"),_SCS("get_singleton")); + ADD_PROPERTY(PropertyInfo(Variant::STRING,"constant",PROPERTY_HINT_ENUM,cc),"set_singleton","get_singleton"); } VisualScriptEngineSingleton::VisualScriptEngineSingleton() { @@ -2113,7 +2117,7 @@ VisualScriptSceneNode::TypeGuess VisualScriptSceneNode::guess_output_type(TypeGu VisualScriptSceneNode::TypeGuess tg; tg.type=Variant::OBJECT; - tg.obj_type="Node"; + tg.GDCLASS="Node"; #ifdef TOOLS_ENABLED Ref<Script> script = get_visual_script(); @@ -2142,7 +2146,7 @@ VisualScriptSceneNode::TypeGuess VisualScriptSceneNode::guess_output_type(TypeGu Node* another = script_node->get_node(path); if (another) { - tg.obj_type=another->get_type(); + tg.GDCLASS=another->get_class(); tg.script=another->get_script(); } #endif @@ -2186,10 +2190,10 @@ void VisualScriptSceneNode::_validate_property(PropertyInfo& property) const { void VisualScriptSceneNode::_bind_methods() { - ObjectTypeDB::bind_method(_MD("set_node_path","path"),&VisualScriptSceneNode::set_node_path); - ObjectTypeDB::bind_method(_MD("get_node_path"),&VisualScriptSceneNode::get_node_path); + ClassDB::bind_method(D_METHOD("set_node_path","path"),&VisualScriptSceneNode::set_node_path); + ClassDB::bind_method(D_METHOD("get_node_path"),&VisualScriptSceneNode::get_node_path); - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH,"node_path",PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE),_SCS("set_node_path"),_SCS("get_node_path")); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH,"node_path",PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE),"set_node_path","get_node_path"); } VisualScriptSceneNode::VisualScriptSceneNode() { @@ -2292,7 +2296,7 @@ VisualScriptSceneTree::TypeGuess VisualScriptSceneTree::guess_output_type(TypeGu TypeGuess tg; tg.type=Variant::OBJECT; - tg.obj_type="SceneTree"; + tg.GDCLASS="SceneTree"; return tg; } @@ -2397,10 +2401,10 @@ VisualScriptNodeInstance* VisualScriptResourcePath::instance(VisualScriptInstanc void VisualScriptResourcePath::_bind_methods() { - ObjectTypeDB::bind_method(_MD("set_resource_path","path"),&VisualScriptResourcePath::set_resource_path); - ObjectTypeDB::bind_method(_MD("get_resource_path"),&VisualScriptResourcePath::get_resource_path); + ClassDB::bind_method(D_METHOD("set_resource_path","path"),&VisualScriptResourcePath::set_resource_path); + ClassDB::bind_method(D_METHOD("get_resource_path"),&VisualScriptResourcePath::get_resource_path); - ADD_PROPERTY(PropertyInfo(Variant::STRING,"path",PROPERTY_HINT_FILE),_SCS("set_resource_path"),_SCS("get_resource_path")); + ADD_PROPERTY(PropertyInfo(Variant::STRING,"path",PROPERTY_HINT_FILE),"set_resource_path","get_resource_path"); } VisualScriptResourcePath::VisualScriptResourcePath() { @@ -2490,13 +2494,13 @@ VisualScriptSelf::TypeGuess VisualScriptSelf::guess_output_type(TypeGuess* p_inp VisualScriptSceneNode::TypeGuess tg; tg.type=Variant::OBJECT; - tg.obj_type="Object"; + tg.GDCLASS="Object"; Ref<Script> script = get_visual_script(); if (!script.is_valid()) return tg; - tg.obj_type=script->get_instance_base_type(); + tg.GDCLASS=script->get_instance_base_type(); tg.script=script; return tg; @@ -2627,9 +2631,9 @@ public: return 0; } #endif - Array in_values(true); - Array out_values(true); - Array work_mem(true); + Array in_values; + Array out_values; + Array work_mem; in_values.resize(in_count); @@ -2813,7 +2817,7 @@ String VisualScriptSubCall::get_text() const { return script->get_name(); if (script->get_path().is_resource_file()) return script->get_path().get_file(); - return script->get_type(); + return script->get_class(); } return ""; } @@ -2997,18 +3001,18 @@ VisualScriptNodeInstance* VisualScriptComment::instance(VisualScriptInstance* p_ void VisualScriptComment::_bind_methods() { - ObjectTypeDB::bind_method(_MD("set_title","title"),&VisualScriptComment::set_title); - ObjectTypeDB::bind_method(_MD("get_title"),&VisualScriptComment::get_title); + ClassDB::bind_method(D_METHOD("set_title","title"),&VisualScriptComment::set_title); + ClassDB::bind_method(D_METHOD("get_title"),&VisualScriptComment::get_title); - ObjectTypeDB::bind_method(_MD("set_description","description"),&VisualScriptComment::set_description); - ObjectTypeDB::bind_method(_MD("get_description"),&VisualScriptComment::get_description); + ClassDB::bind_method(D_METHOD("set_description","description"),&VisualScriptComment::set_description); + ClassDB::bind_method(D_METHOD("get_description"),&VisualScriptComment::get_description); - ObjectTypeDB::bind_method(_MD("set_size","size"),&VisualScriptComment::set_size); - ObjectTypeDB::bind_method(_MD("get_size"),&VisualScriptComment::get_size); + ClassDB::bind_method(D_METHOD("set_size","size"),&VisualScriptComment::set_size); + ClassDB::bind_method(D_METHOD("get_size"),&VisualScriptComment::get_size); - ADD_PROPERTY( PropertyInfo(Variant::STRING,"title"),_SCS("set_title"),_SCS("get_title")); - ADD_PROPERTY( PropertyInfo(Variant::STRING,"description",PROPERTY_HINT_MULTILINE_TEXT),_SCS("set_description"),_SCS("get_description")); - ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"size"),_SCS("set_size"),_SCS("get_size")); + ADD_PROPERTY( PropertyInfo(Variant::STRING,"title"),"set_title","get_title"); + ADD_PROPERTY( PropertyInfo(Variant::STRING,"description",PROPERTY_HINT_MULTILINE_TEXT),"set_description","get_description"); + ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"size"),"set_size","get_size"); } @@ -3136,14 +3140,14 @@ VisualScriptNodeInstance* VisualScriptConstructor::instance(VisualScriptInstance void VisualScriptConstructor::_bind_methods() { - ObjectTypeDB::bind_method(_MD("set_constructor_type","type"),&VisualScriptConstructor::set_constructor_type); - ObjectTypeDB::bind_method(_MD("get_constructor_type"),&VisualScriptConstructor::get_constructor_type); + ClassDB::bind_method(D_METHOD("set_constructor_type","type"),&VisualScriptConstructor::set_constructor_type); + ClassDB::bind_method(D_METHOD("get_constructor_type"),&VisualScriptConstructor::get_constructor_type); - ObjectTypeDB::bind_method(_MD("set_constructor","constructor"),&VisualScriptConstructor::set_constructor); - ObjectTypeDB::bind_method(_MD("get_constructor"),&VisualScriptConstructor::get_constructor); + ClassDB::bind_method(D_METHOD("set_constructor","constructor"),&VisualScriptConstructor::set_constructor); + ClassDB::bind_method(D_METHOD("get_constructor"),&VisualScriptConstructor::get_constructor); - ADD_PROPERTY( PropertyInfo(Variant::INT,"type",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_constructor_type"),_SCS("get_constructor_type")); - ADD_PROPERTY( PropertyInfo(Variant::DICTIONARY,"constructor",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_constructor"),_SCS("get_constructor")); + ADD_PROPERTY( PropertyInfo(Variant::INT,"type",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),"set_constructor_type","get_constructor_type"); + ADD_PROPERTY( PropertyInfo(Variant::DICTIONARY,"constructor",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),"set_constructor","get_constructor"); } @@ -3279,19 +3283,19 @@ VisualScriptNodeInstance* VisualScriptLocalVar::instance(VisualScriptInstance* p void VisualScriptLocalVar::_bind_methods() { - ObjectTypeDB::bind_method(_MD("set_var_name","name"),&VisualScriptLocalVar::set_var_name); - ObjectTypeDB::bind_method(_MD("get_var_name"),&VisualScriptLocalVar::get_var_name); + ClassDB::bind_method(D_METHOD("set_var_name","name"),&VisualScriptLocalVar::set_var_name); + ClassDB::bind_method(D_METHOD("get_var_name"),&VisualScriptLocalVar::get_var_name); - ObjectTypeDB::bind_method(_MD("set_var_type","type"),&VisualScriptLocalVar::set_var_type); - ObjectTypeDB::bind_method(_MD("get_var_type"),&VisualScriptLocalVar::get_var_type); + ClassDB::bind_method(D_METHOD("set_var_type","type"),&VisualScriptLocalVar::set_var_type); + ClassDB::bind_method(D_METHOD("get_var_type"),&VisualScriptLocalVar::get_var_type); String argt="Any"; for(int i=1;i<Variant::VARIANT_MAX;i++) { argt+=","+Variant::get_type_name(Variant::Type(i)); } - ADD_PROPERTY( PropertyInfo(Variant::STRING,"variable/name"),_SCS("set_var_name"),_SCS("get_var_name")); - ADD_PROPERTY( PropertyInfo(Variant::INT,"variable/type",PROPERTY_HINT_ENUM,argt),_SCS("set_var_type"),_SCS("get_var_type")); + ADD_PROPERTY( PropertyInfo(Variant::STRING,"variable/name"),"set_var_name","get_var_name"); + ADD_PROPERTY( PropertyInfo(Variant::INT,"variable/type",PROPERTY_HINT_ENUM,argt),"set_var_type","get_var_type"); } @@ -3416,19 +3420,19 @@ VisualScriptNodeInstance* VisualScriptLocalVarSet::instance(VisualScriptInstance void VisualScriptLocalVarSet::_bind_methods() { - ObjectTypeDB::bind_method(_MD("set_var_name","name"),&VisualScriptLocalVarSet::set_var_name); - ObjectTypeDB::bind_method(_MD("get_var_name"),&VisualScriptLocalVarSet::get_var_name); + ClassDB::bind_method(D_METHOD("set_var_name","name"),&VisualScriptLocalVarSet::set_var_name); + ClassDB::bind_method(D_METHOD("get_var_name"),&VisualScriptLocalVarSet::get_var_name); - ObjectTypeDB::bind_method(_MD("set_var_type","type"),&VisualScriptLocalVarSet::set_var_type); - ObjectTypeDB::bind_method(_MD("get_var_type"),&VisualScriptLocalVarSet::get_var_type); + ClassDB::bind_method(D_METHOD("set_var_type","type"),&VisualScriptLocalVarSet::set_var_type); + ClassDB::bind_method(D_METHOD("get_var_type"),&VisualScriptLocalVarSet::get_var_type); String argt="Any"; for(int i=1;i<Variant::VARIANT_MAX;i++) { argt+=","+Variant::get_type_name(Variant::Type(i)); } - ADD_PROPERTY( PropertyInfo(Variant::STRING,"variable/name"),_SCS("set_var_name"),_SCS("get_var_name")); - ADD_PROPERTY( PropertyInfo(Variant::INT,"variable/type",PROPERTY_HINT_ENUM,argt),_SCS("set_var_type"),_SCS("get_var_type")); + ADD_PROPERTY( PropertyInfo(Variant::STRING,"variable/name"),"set_var_name","get_var_name"); + ADD_PROPERTY( PropertyInfo(Variant::INT,"variable/type",PROPERTY_HINT_ENUM,argt),"set_var_type","get_var_type"); } @@ -3596,7 +3600,7 @@ void VisualScriptInputAction::_validate_property(PropertyInfo& property) const { String actions; List<PropertyInfo> pinfo; - Globals::get_singleton()->get_property_list(&pinfo); + GlobalConfig::get_singleton()->get_property_list(&pinfo); Vector<String> al; for(List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) { @@ -3611,7 +3615,7 @@ void VisualScriptInputAction::_validate_property(PropertyInfo& property) const { al.push_back(name); } - al.sort();; + al.sort(); for(int i=0;i<al.size();i++) { if (actions!=String()) @@ -3626,14 +3630,14 @@ void VisualScriptInputAction::_validate_property(PropertyInfo& property) const { void VisualScriptInputAction::_bind_methods() { - ObjectTypeDB::bind_method(_MD("set_action_name","name"),&VisualScriptInputAction::set_action_name); - ObjectTypeDB::bind_method(_MD("get_action_name"),&VisualScriptInputAction::get_action_name); + ClassDB::bind_method(D_METHOD("set_action_name","name"),&VisualScriptInputAction::set_action_name); + ClassDB::bind_method(D_METHOD("get_action_name"),&VisualScriptInputAction::get_action_name); - ObjectTypeDB::bind_method(_MD("set_action_mode","mode"),&VisualScriptInputAction::set_action_mode); - ObjectTypeDB::bind_method(_MD("get_action_mode"),&VisualScriptInputAction::get_action_mode); + ClassDB::bind_method(D_METHOD("set_action_mode","mode"),&VisualScriptInputAction::set_action_mode); + ClassDB::bind_method(D_METHOD("get_action_mode"),&VisualScriptInputAction::get_action_mode); - ADD_PROPERTY( PropertyInfo(Variant::STRING,"action"),_SCS("set_action_name"),_SCS("get_action_name")); - ADD_PROPERTY( PropertyInfo(Variant::INT,"mode",PROPERTY_HINT_ENUM,"Pressed,Released,JustPressed,JustReleased"),_SCS("set_action_mode"),_SCS("get_action_mode")); + ADD_PROPERTY( PropertyInfo(Variant::STRING,"action"),"set_action_name","get_action_name"); + ADD_PROPERTY( PropertyInfo(Variant::INT,"mode",PROPERTY_HINT_ENUM,"Pressed,Released,JustPressed,JustReleased"),"set_action_mode","get_action_mode"); } @@ -3701,7 +3705,7 @@ String VisualScriptDeconstruct::get_category() const { void VisualScriptDeconstruct::_update_elements() { - elements.clear();; + elements.clear(); Variant v; if (type==Variant::INPUT_EVENT) { InputEvent ie; @@ -3830,25 +3834,25 @@ void VisualScriptDeconstruct::_validate_property(PropertyInfo& property) const { void VisualScriptDeconstruct::_bind_methods() { - ObjectTypeDB::bind_method(_MD("set_deconstruct_type","type"),&VisualScriptDeconstruct::set_deconstruct_type); - ObjectTypeDB::bind_method(_MD("get_deconstruct_type"),&VisualScriptDeconstruct::get_deconstruct_type); + ClassDB::bind_method(D_METHOD("set_deconstruct_type","type"),&VisualScriptDeconstruct::set_deconstruct_type); + ClassDB::bind_method(D_METHOD("get_deconstruct_type"),&VisualScriptDeconstruct::get_deconstruct_type); - ObjectTypeDB::bind_method(_MD("set_deconstruct_input_type","input_type"),&VisualScriptDeconstruct::set_deconstruct_input_type); - ObjectTypeDB::bind_method(_MD("get_deconstruct_input_type"),&VisualScriptDeconstruct::get_deconstruct_input_type); + ClassDB::bind_method(D_METHOD("set_deconstruct_input_type","input_type"),&VisualScriptDeconstruct::set_deconstruct_input_type); + ClassDB::bind_method(D_METHOD("get_deconstruct_input_type"),&VisualScriptDeconstruct::get_deconstruct_input_type); - ObjectTypeDB::bind_method(_MD("_set_elem_cache","_cache"),&VisualScriptDeconstruct::_set_elem_cache); - ObjectTypeDB::bind_method(_MD("_get_elem_cache"),&VisualScriptDeconstruct::_get_elem_cache); + ClassDB::bind_method(D_METHOD("_set_elem_cache","_cache"),&VisualScriptDeconstruct::_set_elem_cache); + ClassDB::bind_method(D_METHOD("_get_elem_cache"),&VisualScriptDeconstruct::_get_elem_cache); String argt="Any"; for(int i=1;i<Variant::VARIANT_MAX;i++) { argt+=","+Variant::get_type_name(Variant::Type(i)); } - String iet="None,Key,MouseMotion,MouseButton,JoystickMotion,JoystickButton,ScreenTouch,ScreenDrag,Action"; + String iet="None,Key,MouseMotion,MouseButton,JoypadMotion,JoypadButton,ScreenTouch,ScreenDrag,Action"; - ADD_PROPERTY( PropertyInfo(Variant::INT,"type",PROPERTY_HINT_ENUM,argt),_SCS("set_deconstruct_type"),_SCS("get_deconstruct_type")); - ADD_PROPERTY( PropertyInfo(Variant::INT,"input_type",PROPERTY_HINT_ENUM,iet),_SCS("set_deconstruct_input_type"),_SCS("get_deconstruct_input_type")); - ADD_PROPERTY( PropertyInfo(Variant::ARRAY,"elem_cache",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_elem_cache"),_SCS("_get_elem_cache")); + ADD_PROPERTY( PropertyInfo(Variant::INT,"type",PROPERTY_HINT_ENUM,argt),"set_deconstruct_type","get_deconstruct_type"); + ADD_PROPERTY( PropertyInfo(Variant::INT,"input_type",PROPERTY_HINT_ENUM,iet),"set_deconstruct_input_type","get_deconstruct_input_type"); + ADD_PROPERTY( PropertyInfo(Variant::ARRAY,"elem_cache",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),"_set_elem_cache","_get_elem_cache"); } @@ -3900,6 +3904,7 @@ void register_visual_script_nodes() { VisualScriptLanguage::singleton->add_register_func("operators/math/multiply",create_op_node<Variant::OP_MULTIPLY>); VisualScriptLanguage::singleton->add_register_func("operators/math/divide",create_op_node<Variant::OP_DIVIDE>); VisualScriptLanguage::singleton->add_register_func("operators/math/negate",create_op_node<Variant::OP_NEGATE>); + VisualScriptLanguage::singleton->add_register_func("operators/math/positive",create_op_node<Variant::OP_POSITIVE>); VisualScriptLanguage::singleton->add_register_func("operators/math/remainder",create_op_node<Variant::OP_MODULE>); VisualScriptLanguage::singleton->add_register_func("operators/math/string_concat",create_op_node<Variant::OP_STRING_CONCAT>); //bitwise diff --git a/modules/visual_script/visual_script_nodes.h b/modules/visual_script/visual_script_nodes.h index 94eeadca57..7a06fbf5e8 100644 --- a/modules/visual_script/visual_script_nodes.h +++ b/modules/visual_script/visual_script_nodes.h @@ -5,7 +5,7 @@ class VisualScriptFunction : public VisualScriptNode { - OBJ_TYPE(VisualScriptFunction,VisualScriptNode) + GDCLASS(VisualScriptFunction,VisualScriptNode) struct Argument { @@ -72,7 +72,7 @@ public: class VisualScriptOperator : public VisualScriptNode { - OBJ_TYPE(VisualScriptOperator,VisualScriptNode) + GDCLASS(VisualScriptOperator,VisualScriptNode) Variant::Type typed; @@ -114,7 +114,7 @@ public: class VisualScriptVariableGet : public VisualScriptNode { - OBJ_TYPE(VisualScriptVariableGet,VisualScriptNode) + GDCLASS(VisualScriptVariableGet,VisualScriptNode) StringName variable; @@ -153,7 +153,7 @@ public: class VisualScriptVariableSet : public VisualScriptNode { - OBJ_TYPE(VisualScriptVariableSet,VisualScriptNode) + GDCLASS(VisualScriptVariableSet,VisualScriptNode) StringName variable; @@ -192,7 +192,7 @@ public: class VisualScriptConstant : public VisualScriptNode { - OBJ_TYPE(VisualScriptConstant,VisualScriptNode) + GDCLASS(VisualScriptConstant,VisualScriptNode) Variant::Type type; @@ -236,7 +236,7 @@ public: class VisualScriptPreload : public VisualScriptNode { - OBJ_TYPE(VisualScriptPreload,VisualScriptNode) + GDCLASS(VisualScriptPreload,VisualScriptNode) Ref<Resource> preload; @@ -274,7 +274,7 @@ public: class VisualScriptIndexGet : public VisualScriptNode { - OBJ_TYPE(VisualScriptIndexGet,VisualScriptNode) + GDCLASS(VisualScriptIndexGet,VisualScriptNode) public: @@ -305,7 +305,7 @@ public: class VisualScriptIndexSet : public VisualScriptNode { - OBJ_TYPE(VisualScriptIndexSet,VisualScriptNode) + GDCLASS(VisualScriptIndexSet,VisualScriptNode) public: @@ -337,7 +337,7 @@ public: class VisualScriptGlobalConstant : public VisualScriptNode { - OBJ_TYPE(VisualScriptGlobalConstant,VisualScriptNode) + GDCLASS(VisualScriptGlobalConstant,VisualScriptNode) int index; @@ -373,7 +373,7 @@ public: class VisualScriptClassConstant : public VisualScriptNode { - OBJ_TYPE(VisualScriptClassConstant,VisualScriptNode) + GDCLASS(VisualScriptClassConstant,VisualScriptNode) StringName base_type; StringName name; @@ -414,7 +414,7 @@ public: class VisualScriptBasicTypeConstant : public VisualScriptNode { - OBJ_TYPE(VisualScriptBasicTypeConstant,VisualScriptNode) + GDCLASS(VisualScriptBasicTypeConstant,VisualScriptNode) Variant::Type type; StringName name; @@ -457,7 +457,7 @@ public: class VisualScriptMathConstant : public VisualScriptNode { - OBJ_TYPE(VisualScriptMathConstant,VisualScriptNode) + GDCLASS(VisualScriptMathConstant,VisualScriptNode) public: enum MathConstant { @@ -508,7 +508,7 @@ VARIANT_ENUM_CAST( VisualScriptMathConstant::MathConstant ) class VisualScriptEngineSingleton : public VisualScriptNode { - OBJ_TYPE(VisualScriptEngineSingleton,VisualScriptNode) + GDCLASS(VisualScriptEngineSingleton,VisualScriptNode) String singleton; @@ -549,7 +549,7 @@ public: class VisualScriptSceneNode : public VisualScriptNode { - OBJ_TYPE(VisualScriptSceneNode,VisualScriptNode) + GDCLASS(VisualScriptSceneNode,VisualScriptNode) NodePath path; protected: @@ -590,7 +590,7 @@ public: class VisualScriptSceneTree : public VisualScriptNode { - OBJ_TYPE(VisualScriptSceneTree,VisualScriptNode) + GDCLASS(VisualScriptSceneTree,VisualScriptNode) protected: @@ -627,7 +627,7 @@ public: class VisualScriptResourcePath : public VisualScriptNode { - OBJ_TYPE(VisualScriptResourcePath,VisualScriptNode) + GDCLASS(VisualScriptResourcePath,VisualScriptNode) String path; protected: @@ -664,7 +664,7 @@ public: class VisualScriptSelf : public VisualScriptNode { - OBJ_TYPE(VisualScriptSelf,VisualScriptNode) + GDCLASS(VisualScriptSelf,VisualScriptNode) protected: @@ -701,13 +701,11 @@ public: class VisualScriptCustomNode: public VisualScriptNode { - OBJ_TYPE(VisualScriptCustomNode,VisualScriptNode) + GDCLASS(VisualScriptCustomNode,VisualScriptNode) protected: - virtual bool _use_builtin_script() const { return true; } - static void _bind_methods(); public: @@ -752,7 +750,7 @@ public: class VisualScriptSubCall: public VisualScriptNode { - OBJ_TYPE(VisualScriptSubCall,VisualScriptNode) + GDCLASS(VisualScriptSubCall,VisualScriptNode) protected: @@ -785,7 +783,7 @@ public: class VisualScriptComment: public VisualScriptNode { - OBJ_TYPE(VisualScriptComment,VisualScriptNode) + GDCLASS(VisualScriptComment,VisualScriptNode) String title; @@ -829,7 +827,7 @@ public: class VisualScriptConstructor: public VisualScriptNode { - OBJ_TYPE(VisualScriptConstructor,VisualScriptNode) + GDCLASS(VisualScriptConstructor,VisualScriptNode) Variant::Type type; @@ -874,7 +872,7 @@ public: class VisualScriptLocalVar: public VisualScriptNode { - OBJ_TYPE(VisualScriptLocalVar,VisualScriptNode) + GDCLASS(VisualScriptLocalVar,VisualScriptNode) StringName name; Variant::Type type; @@ -914,7 +912,7 @@ public: class VisualScriptLocalVarSet: public VisualScriptNode { - OBJ_TYPE(VisualScriptLocalVarSet,VisualScriptNode) + GDCLASS(VisualScriptLocalVarSet,VisualScriptNode) StringName name; Variant::Type type; @@ -956,7 +954,7 @@ public: class VisualScriptInputAction: public VisualScriptNode { - OBJ_TYPE(VisualScriptInputAction,VisualScriptNode) + GDCLASS(VisualScriptInputAction,VisualScriptNode) public: enum Mode { MODE_PRESSED, @@ -1007,7 +1005,7 @@ VARIANT_ENUM_CAST( VisualScriptInputAction::Mode ) class VisualScriptDeconstruct: public VisualScriptNode { - OBJ_TYPE(VisualScriptDeconstruct,VisualScriptNode) + GDCLASS(VisualScriptDeconstruct,VisualScriptNode) struct Element { diff --git a/modules/visual_script/visual_script_yield_nodes.cpp b/modules/visual_script/visual_script_yield_nodes.cpp index 221c46b6fd..c079606674 100644 --- a/modules/visual_script/visual_script_yield_nodes.cpp +++ b/modules/visual_script/visual_script_yield_nodes.cpp @@ -157,14 +157,14 @@ void VisualScriptYield::_validate_property(PropertyInfo& property) const { void VisualScriptYield::_bind_methods() { - ObjectTypeDB::bind_method(_MD("set_yield_mode","mode"),&VisualScriptYield::set_yield_mode); - ObjectTypeDB::bind_method(_MD("get_yield_mode"),&VisualScriptYield::get_yield_mode); + ClassDB::bind_method(D_METHOD("set_yield_mode","mode"),&VisualScriptYield::set_yield_mode); + ClassDB::bind_method(D_METHOD("get_yield_mode"),&VisualScriptYield::get_yield_mode); - ObjectTypeDB::bind_method(_MD("set_wait_time","sec"),&VisualScriptYield::set_wait_time); - ObjectTypeDB::bind_method(_MD("get_wait_time"),&VisualScriptYield::get_wait_time); + ClassDB::bind_method(D_METHOD("set_wait_time","sec"),&VisualScriptYield::set_wait_time); + ClassDB::bind_method(D_METHOD("get_wait_time"),&VisualScriptYield::get_wait_time); - ADD_PROPERTY(PropertyInfo(Variant::INT,"mode",PROPERTY_HINT_ENUM,"Frame,FixedFrame,Time",PROPERTY_USAGE_NOEDITOR),_SCS("set_yield_mode"),_SCS("get_yield_mode")); - ADD_PROPERTY(PropertyInfo(Variant::REAL,"wait_time"),_SCS("set_wait_time"),_SCS("get_wait_time")); + ADD_PROPERTY(PropertyInfo(Variant::INT,"mode",PROPERTY_HINT_ENUM,"Frame,FixedFrame,Time",PROPERTY_USAGE_NOEDITOR),"set_yield_mode","get_yield_mode"); + ADD_PROPERTY(PropertyInfo(Variant::REAL,"wait_time"),"set_wait_time","get_wait_time"); BIND_CONSTANT( YIELD_FRAME ); @@ -270,7 +270,7 @@ StringName VisualScriptYieldSignal::_get_base_type() const { else if (call_mode==CALL_MODE_NODE_PATH && get_visual_script().is_valid()) { Node *path = _get_base_node(); if (path) - return path->get_type(); + return path->get_class(); } @@ -290,7 +290,7 @@ int VisualScriptYieldSignal::get_output_value_port_count() const{ MethodInfo sr; - if (!ObjectTypeDB::get_signal(_get_base_type(),signal,&sr)) + if (!ClassDB::get_signal(_get_base_type(),signal,&sr)) return 0; return sr.arguments.size(); @@ -315,7 +315,7 @@ PropertyInfo VisualScriptYieldSignal::get_output_value_port_info(int p_idx) cons MethodInfo sr; - if (!ObjectTypeDB::get_signal(_get_base_type(),signal,&sr)) + if (!ClassDB::get_signal(_get_base_type(),signal,&sr)) return PropertyInfo(); //no signal ERR_FAIL_INDEX_V(p_idx,sr.arguments.size(),PropertyInfo()); return sr.arguments[p_idx]; @@ -440,7 +440,7 @@ void VisualScriptYieldSignal::_validate_property(PropertyInfo& property) const { List<MethodInfo> methods; - ObjectTypeDB::get_signal_list(_get_base_type(),&methods); + ClassDB::get_signal_list(_get_base_type(),&methods); List<String> mstring; for (List<MethodInfo>::Element *E=methods.front();E;E=E->next()) { @@ -468,17 +468,17 @@ void VisualScriptYieldSignal::_validate_property(PropertyInfo& property) const { void VisualScriptYieldSignal::_bind_methods() { - ObjectTypeDB::bind_method(_MD("set_base_type","base_type"),&VisualScriptYieldSignal::set_base_type); - ObjectTypeDB::bind_method(_MD("get_base_type"),&VisualScriptYieldSignal::get_base_type); + ClassDB::bind_method(D_METHOD("set_base_type","base_type"),&VisualScriptYieldSignal::set_base_type); + ClassDB::bind_method(D_METHOD("get_base_type"),&VisualScriptYieldSignal::get_base_type); - ObjectTypeDB::bind_method(_MD("set_signal","signal"),&VisualScriptYieldSignal::set_signal); - ObjectTypeDB::bind_method(_MD("get_signal"),&VisualScriptYieldSignal::get_signal); + ClassDB::bind_method(D_METHOD("set_signal","signal"),&VisualScriptYieldSignal::set_signal); + ClassDB::bind_method(D_METHOD("get_signal"),&VisualScriptYieldSignal::get_signal); - ObjectTypeDB::bind_method(_MD("set_call_mode","mode"),&VisualScriptYieldSignal::set_call_mode); - ObjectTypeDB::bind_method(_MD("get_call_mode"),&VisualScriptYieldSignal::get_call_mode); + ClassDB::bind_method(D_METHOD("set_call_mode","mode"),&VisualScriptYieldSignal::set_call_mode); + ClassDB::bind_method(D_METHOD("get_call_mode"),&VisualScriptYieldSignal::get_call_mode); - ObjectTypeDB::bind_method(_MD("set_base_path","base_path"),&VisualScriptYieldSignal::set_base_path); - ObjectTypeDB::bind_method(_MD("get_base_path"),&VisualScriptYieldSignal::get_base_path); + ClassDB::bind_method(D_METHOD("set_base_path","base_path"),&VisualScriptYieldSignal::set_base_path); + ClassDB::bind_method(D_METHOD("get_base_path"),&VisualScriptYieldSignal::get_base_path); @@ -490,10 +490,10 @@ void VisualScriptYieldSignal::_bind_methods() { bt+=Variant::get_type_name(Variant::Type(i)); } - ADD_PROPERTY(PropertyInfo(Variant::INT,"signal/call_mode",PROPERTY_HINT_ENUM,"Self,Node Path,Instance"),_SCS("set_call_mode"),_SCS("get_call_mode")); - ADD_PROPERTY(PropertyInfo(Variant::STRING,"signal/base_type",PROPERTY_HINT_TYPE_STRING,"Object"),_SCS("set_base_type"),_SCS("get_base_type")); - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH,"signal/node_path",PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE),_SCS("set_base_path"),_SCS("get_base_path")); - ADD_PROPERTY(PropertyInfo(Variant::STRING,"signal/signal"),_SCS("set_signal"),_SCS("get_signal")); + ADD_PROPERTY(PropertyInfo(Variant::INT,"signal/call_mode",PROPERTY_HINT_ENUM,"Self,Node Path,Instance"),"set_call_mode","get_call_mode"); + ADD_PROPERTY(PropertyInfo(Variant::STRING,"signal/base_type",PROPERTY_HINT_TYPE_STRING,"Object"),"set_base_type","get_base_type"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH,"signal/node_path",PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE),"set_base_path","get_base_path"); + ADD_PROPERTY(PropertyInfo(Variant::STRING,"signal/signal"),"set_signal","get_signal"); BIND_CONSTANT( CALL_MODE_SELF ); diff --git a/modules/visual_script/visual_script_yield_nodes.h b/modules/visual_script/visual_script_yield_nodes.h index ae7f8c15c1..210d6ec995 100644 --- a/modules/visual_script/visual_script_yield_nodes.h +++ b/modules/visual_script/visual_script_yield_nodes.h @@ -5,7 +5,7 @@ class VisualScriptYield : public VisualScriptNode { - OBJ_TYPE(VisualScriptYield,VisualScriptNode) + GDCLASS(VisualScriptYield,VisualScriptNode) public: enum YieldMode { @@ -60,7 +60,7 @@ VARIANT_ENUM_CAST( VisualScriptYield::YieldMode ) class VisualScriptYieldSignal : public VisualScriptNode { - OBJ_TYPE(VisualScriptYieldSignal,VisualScriptNode) + GDCLASS(VisualScriptYieldSignal,VisualScriptNode) public: enum CallMode { CALL_MODE_SELF, diff --git a/modules/vorbis/SCsub b/modules/vorbis/SCsub new file mode 100644 index 0000000000..d3e4f7e15a --- /dev/null +++ b/modules/vorbis/SCsub @@ -0,0 +1,49 @@ +#!/usr/bin/env python + +Import('env') +Import('env_modules') + +env_vorbis = env_modules.Clone() + +# Thirdparty source files +if (env['builtin_libvorbis'] != 'no'): + thirdparty_dir = "#thirdparty/libvorbis/" + thirdparty_sources = [ + #"analysis.c", + #"barkmel.c", + "bitrate.c", + "block.c", + "codebook.c", + "envelope.c", + "floor0.c", + "floor1.c", + "info.c", + "lookup.c", + "lpc.c", + "lsp.c", + "mapping0.c", + "mdct.c", + "psy.c", + #"psytune.c", + "registry.c", + "res0.c", + "sharedbook.c", + "smallft.c", + "synthesis.c", + #"tone.c", + #"vorbisenc.c", + "vorbisfile.c", + "window.c", + ] + + thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] + + env_vorbis.add_source_files(env.modules_sources, thirdparty_sources) + env_vorbis.Append(CPPPATH=[thirdparty_dir]) + + # also requires libogg + if (env['builtin_libogg'] != 'no'): + env_vorbis.Append(CPPPATH=["#thirdparty/libogg"]) + +# Godot source files +env_vorbis.add_source_files(env.modules_sources, "*.cpp") diff --git a/modules/vorbis/audio_stream_ogg_vorbis.cpp b/modules/vorbis/audio_stream_ogg_vorbis.cpp new file mode 100644 index 0000000000..98920954a4 --- /dev/null +++ b/modules/vorbis/audio_stream_ogg_vorbis.cpp @@ -0,0 +1,430 @@ +/*************************************************************************/ +/* audio_stream_ogg_vorbis.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#include "audio_stream_ogg_vorbis.h" + + + +size_t AudioStreamPlaybackOGGVorbis::_ov_read_func(void *p_dst,size_t p_data, size_t p_count, void *_f) { + + //printf("read to %p, %i bytes, %i nmemb, %p\n",p_dst,p_data,p_count,_f); + FileAccess *fa=(FileAccess*)_f; + size_t read_total = p_data*p_count; + + if (fa->eof_reached()) + return 0; + + uint8_t *dst=(uint8_t*)p_dst; + + int read = fa->get_buffer(dst, read_total); + + return read; +} + +int AudioStreamPlaybackOGGVorbis::_ov_seek_func(void *_f,ogg_int64_t offs, int whence) { + + //printf("seek to %p, offs %i, whence %i\n",_f,(int)offs,whence); + +#ifdef SEEK_SET + //printf("seek set defined\n"); + FileAccess *fa=(FileAccess*)_f; + + if (whence==SEEK_SET) { + + fa->seek(offs); + } else if (whence==SEEK_CUR) { + + fa->seek(fa->get_pos()+offs); + } else if (whence==SEEK_END) { + + fa->seek_end(offs); + } else { + + ERR_PRINT("BUG, wtf was whence set to?\n"); + } + int ret=fa->eof_reached()?-1:0; + //printf("returning %i\n",ret); + return ret; + +#else + return -1; // no seeking +#endif + +} +int AudioStreamPlaybackOGGVorbis::_ov_close_func(void *_f) { + + //printf("close %p\n",_f); + if (!_f) + return 0; + FileAccess *fa=(FileAccess*)_f; + if (fa->is_open()) + fa->close(); + return 0; +} +long AudioStreamPlaybackOGGVorbis::_ov_tell_func(void *_f) { + + //printf("close %p\n",_f); + + FileAccess *fa=(FileAccess*)_f; + return fa->get_pos(); +} + + + +int AudioStreamPlaybackOGGVorbis::mix(int16_t* p_bufer,int p_frames) { + + if (!playing) + return 0; + + int total=p_frames; + while (true) { + + int todo = p_frames; + + if (todo==0 || todo<MIN_MIX) { + break; + } + + //printf("to mix %i - mix me %i bytes\n",to_mix,to_mix*stream_channels*sizeof(int16_t)); + + #ifdef BIG_ENDIAN_ENABLED + long ret=ov_read(&vf,(char*)p_bufer,todo*stream_channels*sizeof(int16_t), 1, 2, 1, ¤t_section); + #else + long ret=ov_read(&vf,(char*)p_bufer,todo*stream_channels*sizeof(int16_t), 0, 2, 1, ¤t_section); + #endif + + if (ret<0) { + + playing = false; + ERR_EXPLAIN("Error reading OGG Vorbis File: "+file); + ERR_BREAK(ret<0); + } else if (ret==0) { // end of song, reload? + + ov_clear(&vf); + + _close_file(); + + if (!has_loop()) { + + playing=false; + repeats=1; + break; + } + + f=FileAccess::open(file,FileAccess::READ); + + int errv = ov_open_callbacks(f,&vf,NULL,0,_ov_callbacks); + if (errv!=0) { + playing=false; + break; // :( + } + + if (loop_restart_time) { + bool ok = ov_time_seek(&vf,loop_restart_time)==0; + if (!ok) { + playing=false; + //ERR_EXPLAIN("loop restart time rejected"); + ERR_PRINT("loop restart time rejected") + } + + frames_mixed=stream_srate*loop_restart_time; + } else { + + frames_mixed=0; + } + repeats++; + continue; + + } + + ret/=stream_channels; + ret/=sizeof(int16_t); + + frames_mixed+=ret; + + p_bufer+=ret*stream_channels; + p_frames-=ret; + + } + + return total-p_frames; + +} + + + +void AudioStreamPlaybackOGGVorbis::play(float p_from) { + + if (playing) + stop(); + + if (_load_stream()!=OK) + return; + + + frames_mixed=0; + playing=true; + if (p_from>0) { + seek_pos(p_from); + } +} + +void AudioStreamPlaybackOGGVorbis::_close_file() { + + if (f) { + + memdelete(f); + f=NULL; + } +} + +bool AudioStreamPlaybackOGGVorbis::is_playing() const { + return playing; +} +void AudioStreamPlaybackOGGVorbis::stop() { + + _clear_stream(); + playing=false; + //_clear(); +} + + + +float AudioStreamPlaybackOGGVorbis::get_pos() const { + + int32_t frames = int32_t(frames_mixed); + if (frames < 0) + frames=0; + return double(frames) / stream_srate; +} + +void AudioStreamPlaybackOGGVorbis::seek_pos(float p_time) { + + + + if (!playing) + return; + bool ok = ov_time_seek(&vf,p_time)==0; + ERR_FAIL_COND(!ok); + frames_mixed=stream_srate*p_time; +} + +String AudioStreamPlaybackOGGVorbis::get_stream_name() const { + + return ""; +} + +void AudioStreamPlaybackOGGVorbis::set_loop(bool p_enable) { + + loops=p_enable; +} + +bool AudioStreamPlaybackOGGVorbis::has_loop() const { + + return loops; +} + +int AudioStreamPlaybackOGGVorbis::get_loop_count() const { + return repeats; +} + + +Error AudioStreamPlaybackOGGVorbis::set_file(const String& p_file) { + + file=p_file; + stream_valid=false; + Error err; + f=FileAccess::open(file,FileAccess::READ,&err); + + if (err) { + ERR_FAIL_COND_V( err, err ); + } + + int errv = ov_open_callbacks(f,&vf,NULL,0,_ov_callbacks); + switch(errv) { + + case OV_EREAD: { // - A read from media returned an error. + memdelete(f); f=NULL; + ERR_FAIL_V( ERR_FILE_CANT_READ ); + } break; + case OV_EVERSION: // - Vorbis version mismatch. + case OV_ENOTVORBIS: { // - Bitstream is not Vorbis data. + memdelete(f); f=NULL; + ERR_FAIL_V( ERR_FILE_UNRECOGNIZED ); + } break; + case OV_EBADHEADER: { // - Invalid Vorbis bitstream header. + memdelete(f); f=NULL; + ERR_FAIL_V( ERR_FILE_CORRUPT ); + } break; + case OV_EFAULT: { // - Internal logic fault; indicates a bug or heap/stack corruption. + memdelete(f); f=NULL; + ERR_FAIL_V( ERR_BUG ); + } break; + } + const vorbis_info *vinfo=ov_info(&vf,-1); + stream_channels=vinfo->channels; + stream_srate=vinfo->rate; + length = ov_time_total(&vf,-1); + ov_clear(&vf); + memdelete(f); + f=NULL; + stream_valid=true; + + + return OK; +} + +Error AudioStreamPlaybackOGGVorbis::_load_stream() { + + ERR_FAIL_COND_V(!stream_valid,ERR_UNCONFIGURED); + + _clear_stream(); + if (file=="") + return ERR_INVALID_DATA; + + Error err; + f=FileAccess::open(file,FileAccess::READ,&err); + if (err) { + ERR_FAIL_COND_V( err, err ); + } + + int errv = ov_open_callbacks(f,&vf,NULL,0,_ov_callbacks); + switch(errv) { + + case OV_EREAD: { // - A read from media returned an error. + memdelete(f); f=NULL; + ERR_FAIL_V( ERR_FILE_CANT_READ ); + } break; + case OV_EVERSION: // - Vorbis version mismatch. + case OV_ENOTVORBIS: { // - Bitstream is not Vorbis data. + memdelete(f); f=NULL; + ERR_FAIL_V( ERR_FILE_UNRECOGNIZED ); + } break; + case OV_EBADHEADER: { // - Invalid Vorbis bitstream header. + memdelete(f); f=NULL; + ERR_FAIL_V( ERR_FILE_CORRUPT ); + } break; + case OV_EFAULT: { // - Internal logic fault; indicates a bug or heap/stack corruption. + memdelete(f); f=NULL; + ERR_FAIL_V( ERR_BUG ); + } break; + } + repeats=0; + stream_loaded=true; + + + return OK; +} + + +float AudioStreamPlaybackOGGVorbis::get_length() const { + + if (!stream_loaded) { + if (const_cast<AudioStreamPlaybackOGGVorbis*>(this)->_load_stream()!=OK) + return 0; + } + return length; +} + +void AudioStreamPlaybackOGGVorbis::_clear_stream() { + + if (!stream_loaded) + return; + + ov_clear(&vf); + _close_file(); + + stream_loaded=false; + //stream_channels=1; + playing=false; +} + +void AudioStreamPlaybackOGGVorbis::set_paused(bool p_paused) { + + paused=p_paused; +} + +bool AudioStreamPlaybackOGGVorbis::is_paused(bool p_paused) const { + + return paused; +} + + +AudioStreamPlaybackOGGVorbis::AudioStreamPlaybackOGGVorbis() { + + loops=false; + playing=false; + _ov_callbacks.read_func=_ov_read_func; + _ov_callbacks.seek_func=_ov_seek_func; + _ov_callbacks.close_func=_ov_close_func; + _ov_callbacks.tell_func=_ov_tell_func; + f = NULL; + stream_loaded=false; + stream_valid=false; + repeats=0; + paused=true; + stream_channels=0; + stream_srate=0; + current_section=0; + length=0; + loop_restart_time=0; +} + + +AudioStreamPlaybackOGGVorbis::~AudioStreamPlaybackOGGVorbis() { + + _clear_stream(); + +} + + + +RES ResourceFormatLoaderAudioStreamOGGVorbis::load(const String &p_path, const String& p_original_path, Error *r_error) { + if (r_error) + *r_error=OK; + + AudioStreamOGGVorbis *ogg_stream = memnew(AudioStreamOGGVorbis); + ogg_stream->set_file(p_path); + return Ref<AudioStreamOGGVorbis>(ogg_stream); +} + +void ResourceFormatLoaderAudioStreamOGGVorbis::get_recognized_extensions(List<String> *p_extensions) const { + + p_extensions->push_back("ogg"); +} +String ResourceFormatLoaderAudioStreamOGGVorbis::get_resource_type(const String &p_path) const { + + if (p_path.get_extension().to_lower()=="ogg") + return "AudioStreamOGGVorbis"; + return ""; +} + +bool ResourceFormatLoaderAudioStreamOGGVorbis::handles_type(const String& p_type) const { + return (p_type=="AudioStream" || p_type=="AudioStreamOGG" || p_type=="AudioStreamOGGVorbis"); +} + diff --git a/modules/vorbis/audio_stream_ogg_vorbis.h b/modules/vorbis/audio_stream_ogg_vorbis.h new file mode 100644 index 0000000000..bc2bfa2ae6 --- /dev/null +++ b/modules/vorbis/audio_stream_ogg_vorbis.h @@ -0,0 +1,142 @@ +/*************************************************************************/ +/* audio_stream_ogg_vorbis.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#ifndef AUDIO_STREAM_OGG_VORBIS_H +#define AUDIO_STREAM_OGG_VORBIS_H + +#include "io/resource_loader.h" +#include "os/file_access.h" +#include "os/thread_safe.h" +#include "scene/resources/audio_stream.h" + +#include <vorbis/vorbisfile.h> + +class AudioStreamPlaybackOGGVorbis : public AudioStreamPlayback { + + GDCLASS(AudioStreamPlaybackOGGVorbis,AudioStreamPlayback); + + enum { + MIN_MIX=1024 + }; + + FileAccess *f; + + ov_callbacks _ov_callbacks; + float length; + static size_t _ov_read_func(void *p_dst,size_t p_data, size_t p_count, void *_f); + static int _ov_seek_func(void *_f,ogg_int64_t offs, int whence); + static int _ov_close_func(void *_f); + static long _ov_tell_func(void *_f); + + String file; + int64_t frames_mixed; + + bool stream_loaded; + volatile bool playing; + OggVorbis_File vf; + int stream_channels; + int stream_srate; + int current_section; + + + bool paused; + bool loops; + int repeats; + + Error _load_stream(); + void _clear_stream(); + void _close_file(); + + bool stream_valid; + float loop_restart_time; + + +public: + + + Error set_file(const String& p_file); + + virtual void play(float p_from=0); + virtual void stop(); + virtual bool is_playing() const; + + virtual void set_loop_restart_time(float p_time) { loop_restart_time=p_time; } + + virtual void set_paused(bool p_paused); + virtual bool is_paused(bool p_paused) const; + + virtual void set_loop(bool p_enable); + virtual bool has_loop() const; + + virtual float get_length() const; + + virtual String get_stream_name() const; + + virtual int get_loop_count() const; + + virtual float get_pos() const; + virtual void seek_pos(float p_time); + + virtual int get_channels() const { return stream_channels; } + virtual int get_mix_rate() const { return stream_srate; } + + virtual int get_minimum_buffer_size() const { return 0; } + virtual int mix(int16_t* p_bufer,int p_frames); + + AudioStreamPlaybackOGGVorbis(); + ~AudioStreamPlaybackOGGVorbis(); +}; + + +class AudioStreamOGGVorbis : public AudioStream { + + GDCLASS(AudioStreamOGGVorbis,AudioStream); + + String file; +public: + + Ref<AudioStreamPlayback> instance_playback() { + Ref<AudioStreamPlaybackOGGVorbis> pb = memnew( AudioStreamPlaybackOGGVorbis ); + pb->set_file(file); + return pb; + } + + void set_file(const String& p_file) { file=p_file; } + +}; + +class ResourceFormatLoaderAudioStreamOGGVorbis : public ResourceFormatLoader { +public: + virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL); + virtual void get_recognized_extensions(List<String> *p_extensions) const; + virtual bool handles_type(const String& p_type) const; + virtual String get_resource_type(const String &p_path) const; +}; + + +#endif // AUDIO_STREAM_OGG_H diff --git a/modules/vorbis/config.py b/modules/vorbis/config.py new file mode 100644 index 0000000000..ef5daca05c --- /dev/null +++ b/modules/vorbis/config.py @@ -0,0 +1,8 @@ + +def can_build(platform): +# return True + return False + + +def configure(env): + pass diff --git a/modules/vorbis/register_types.cpp b/modules/vorbis/register_types.cpp new file mode 100644 index 0000000000..de929d9350 --- /dev/null +++ b/modules/vorbis/register_types.cpp @@ -0,0 +1,45 @@ +/*************************************************************************/ +/* register_types.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#include "register_types.h" + +#include "audio_stream_ogg_vorbis.h" + +static ResourceFormatLoaderAudioStreamOGGVorbis *vorbis_stream_loader = NULL; + +void register_vorbis_types() { + + vorbis_stream_loader = memnew( ResourceFormatLoaderAudioStreamOGGVorbis ); + ResourceLoader::add_resource_format_loader(vorbis_stream_loader); + ClassDB::register_class<AudioStreamOGGVorbis>(); +} + +void unregister_vorbis_types() { + + memdelete( vorbis_stream_loader ); +} diff --git a/modules/vorbis/register_types.h b/modules/vorbis/register_types.h new file mode 100644 index 0000000000..b2adb55acd --- /dev/null +++ b/modules/vorbis/register_types.h @@ -0,0 +1,30 @@ +/*************************************************************************/ +/* register_types.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +void register_vorbis_types(); +void unregister_vorbis_types(); diff --git a/modules/webm/SCsub b/modules/webm/SCsub new file mode 100644 index 0000000000..889f5e83aa --- /dev/null +++ b/modules/webm/SCsub @@ -0,0 +1,34 @@ +#!/usr/bin/env python + +Import('env') +Import('env_modules') + +env_webm = env_modules.Clone() + +# Thirdparty source files +thirdparty_libsimplewebm_dir = "#thirdparty/libsimplewebm/" +thirdparty_libsimplewebm_sources = [ + "libwebm/mkvparser/mkvparser.cc", + "OpusVorbisDecoder.cpp", + "VPXDecoder.cpp", + "WebMDemuxer.cpp", +] +thirdparty_libsimplewebm_sources = [thirdparty_libsimplewebm_dir + file for file in thirdparty_libsimplewebm_sources] + +env_webm.add_source_files(env.modules_sources, thirdparty_libsimplewebm_sources) +env_webm.Append(CPPPATH=[thirdparty_libsimplewebm_dir, thirdparty_libsimplewebm_dir + "libwebm/"]) + +# also requires libogg, libvorbis and libopus +if (env['builtin_libogg'] != 'no'): + env_webm.Append(CPPPATH=["#thirdparty/libogg"]) +if (env['builtin_libvorbis'] != 'no'): + env_webm.Append(CPPPATH=["#thirdparty/libvorbis"]) +if (env['builtin_opus'] != 'no'): + env_webm.Append(CPPPATH=["#thirdparty/opus"]) + +if (env['builtin_libvpx'] != 'no'): + Export('env_webm') + SConscript("libvpx/SCsub") + +# Godot source files +env_webm.add_source_files(env.modules_sources, "*.cpp") diff --git a/modules/webm/config.py b/modules/webm/config.py new file mode 100644 index 0000000000..ef5daca05c --- /dev/null +++ b/modules/webm/config.py @@ -0,0 +1,8 @@ + +def can_build(platform): +# return True + return False + + +def configure(env): + pass diff --git a/modules/webm/libvpx/SCsub b/modules/webm/libvpx/SCsub new file mode 100644 index 0000000000..241d6e30cd --- /dev/null +++ b/modules/webm/libvpx/SCsub @@ -0,0 +1,393 @@ +#!/usr/bin/env python + +libvpx_dir = "#thirdparty/libvpx/" + +libvpx_sources = [ + "vp8/vp8_dx_iface.c", + + "vp8/common/generic/systemdependent.c", + + "vp8/common/alloccommon.c", + "vp8/common/blockd.c", + "vp8/common/copy_c.c", + "vp8/common/debugmodes.c", + "vp8/common/dequantize.c", + "vp8/common/entropy.c", + "vp8/common/entropymode.c", + "vp8/common/entropymv.c", + "vp8/common/extend.c", + "vp8/common/filter.c", + "vp8/common/findnearmv.c", + "vp8/common/idct_blk.c", + "vp8/common/idctllm.c", + "vp8/common/loopfilter_filters.c", + "vp8/common/mbpitch.c", + "vp8/common/modecont.c", + "vp8/common/quant_common.c", + "vp8/common/reconinter.c", + "vp8/common/reconintra.c", + "vp8/common/reconintra4x4.c", + "vp8/common/rtcd.c", + "vp8/common/setupintrarecon.c", + "vp8/common/swapyv12buffer.c", + "vp8/common/treecoder.c", + "vp8/common/vp8_loopfilter.c", + + "vp8/decoder/dboolhuff.c", + "vp8/decoder/decodeframe.c", + "vp8/decoder/decodemv.c", + "vp8/decoder/detokenize.c", + "vp8/decoder/onyxd_if.c", + "vp8/decoder/threading.c", + + + "vp9/vp9_dx_iface.c", + + "vp9/common/vp9_alloccommon.c", + "vp9/common/vp9_blockd.c", + "vp9/common/vp9_common_data.c", + "vp9/common/vp9_debugmodes.c", + "vp9/common/vp9_entropy.c", + "vp9/common/vp9_entropymode.c", + "vp9/common/vp9_entropymv.c", + "vp9/common/vp9_filter.c", + "vp9/common/vp9_frame_buffers.c", + "vp9/common/vp9_idct.c", + "vp9/common/vp9_loopfilter.c", + "vp9/common/vp9_mvref_common.c", + "vp9/common/vp9_pred_common.c", + "vp9/common/vp9_quant_common.c", + "vp9/common/vp9_reconinter.c", + "vp9/common/vp9_reconintra.c", + "vp9/common/vp9_rtcd.c", + "vp9/common/vp9_scale.c", + "vp9/common/vp9_scan.c", + "vp9/common/vp9_seg_common.c", + "vp9/common/vp9_thread_common.c", + "vp9/common/vp9_tile_common.c", + + "vp9/decoder/vp9_decodeframe.c", + "vp9/decoder/vp9_decodemv.c", + "vp9/decoder/vp9_decoder.c", + "vp9/decoder/vp9_detokenize.c", + "vp9/decoder/vp9_dsubexp.c", + "vp9/decoder/vp9_dthread.c", + + + "vpx/src/vpx_codec.c", + "vpx/src/vpx_decoder.c", + "vpx/src/vpx_image.c", + "vpx/src/vpx_psnr.c", + + + "vpx_dsp/bitreader.c", + "vpx_dsp/bitreader_buffer.c", + "vpx_dsp/intrapred.c", + "vpx_dsp/inv_txfm.c", + "vpx_dsp/loopfilter.c", + "vpx_dsp/prob.c", + "vpx_dsp/vpx_convolve.c", + "vpx_dsp/vpx_dsp_rtcd.c", + + + "vpx_mem/vpx_mem.c", + + + "vpx_scale/vpx_scale_rtcd.c", + + "vpx_scale/generic/yv12config.c", + "vpx_scale/generic/yv12extend.c", + + + "vpx_util/vpx_thread.c" +] + +libvpx_sources_intrin_x86 = [ + "vp8/common/x86/filter_x86.c", + "vp8/common/x86/loopfilter_x86.c", + "vp8/common/x86/vp8_asm_stubs.c", + + + "vpx_dsp/x86/vpx_asm_stubs.c" +] +libvpx_sources_intrin_x86_mmx = [ + "vp8/common/x86/idct_blk_mmx.c", +] +libvpx_sources_intrin_x86_sse2 = [ + "vp8/common/x86/idct_blk_sse2.c", + + + "vp9/common/x86/vp9_idct_intrin_sse2.c", + + + "vpx_dsp/x86/inv_txfm_sse2.c", + "vpx_dsp/x86/loopfilter_sse2.c", +] +libvpx_sources_intrin_x86_ssse3 = [ + "vpx_dsp/x86/vpx_subpixel_8t_intrin_ssse3.c" +] +libvpx_sources_intrin_x86_avx2 = [ + "vpx_dsp/x86/loopfilter_avx2.c", + "vpx_dsp/x86/vpx_subpixel_8t_intrin_avx2.c" +] +libvpx_sources_x86asm = [ + "vp8/common/x86/copy_sse2.asm", + "vp8/common/x86/copy_sse3.asm", + "vp8/common/x86/dequantize_mmx.asm", + "vp8/common/x86/idctllm_mmx.asm", + "vp8/common/x86/idctllm_sse2.asm", + "vp8/common/x86/iwalsh_mmx.asm", + "vp8/common/x86/iwalsh_sse2.asm", + "vp8/common/x86/loopfilter_sse2.asm", + "vp8/common/x86/recon_mmx.asm", + "vp8/common/x86/recon_sse2.asm", + "vp8/common/x86/subpixel_mmx.asm", + "vp8/common/x86/subpixel_sse2.asm", + "vp8/common/x86/subpixel_ssse3.asm", + "vp8/common/x86/vp8_loopfilter_mmx.asm", + + + "vpx_dsp/x86/intrapred_sse2.asm", + "vpx_dsp/x86/intrapred_ssse3.asm", + "vpx_dsp/x86/inv_wht_sse2.asm", + "vpx_dsp/x86/vpx_convolve_copy_sse2.asm", + "vpx_dsp/x86/vpx_subpixel_8t_sse2.asm", + "vpx_dsp/x86/vpx_subpixel_8t_ssse3.asm", + "vpx_dsp/x86/vpx_subpixel_bilinear_sse2.asm", + "vpx_dsp/x86/vpx_subpixel_bilinear_ssse3.asm", + + + "vpx_ports/emms.asm" +] +libvpx_sources_x86_64asm = [ + "vp8/common/x86/loopfilter_block_sse2_x86_64.asm", + + + "vpx_dsp/x86/inv_txfm_ssse3_x86_64.asm" +] + +libvpx_sources_arm = [ + "vpx_ports/arm_cpudetect.c", + + + "vp8/common/arm/loopfilter_arm.c", +] +libvpx_sources_arm_neon = [ + "vp8/common/arm/neon/bilinearpredict_neon.c", + "vp8/common/arm/neon/copymem_neon.c", + "vp8/common/arm/neon/dc_only_idct_add_neon.c", + "vp8/common/arm/neon/dequant_idct_neon.c", + "vp8/common/arm/neon/dequantizeb_neon.c", + "vp8/common/arm/neon/idct_blk_neon.c", + "vp8/common/arm/neon/idct_dequant_0_2x_neon.c", + "vp8/common/arm/neon/idct_dequant_full_2x_neon.c", + "vp8/common/arm/neon/iwalsh_neon.c", + "vp8/common/arm/neon/loopfiltersimplehorizontaledge_neon.c", + "vp8/common/arm/neon/loopfiltersimpleverticaledge_neon.c", + "vp8/common/arm/neon/mbloopfilter_neon.c", + "vp8/common/arm/neon/shortidct4x4llm_neon.c", + "vp8/common/arm/neon/sixtappredict_neon.c", + "vp8/common/arm/neon/vp8_loopfilter_neon.c", + + + "vp9/common/arm/neon/vp9_iht4x4_add_neon.c", + "vp9/common/arm/neon/vp9_iht8x8_add_neon.c", + + + "vpx_dsp/arm/idct16x16_1_add_neon.c", + "vpx_dsp/arm/idct16x16_add_neon.c", + "vpx_dsp/arm/idct16x16_neon.c", + "vpx_dsp/arm/idct32x32_1_add_neon.c", + "vpx_dsp/arm/idct32x32_add_neon.c", + "vpx_dsp/arm/idct4x4_1_add_neon.c", + "vpx_dsp/arm/idct4x4_add_neon.c", + "vpx_dsp/arm/idct8x8_1_add_neon.c", + "vpx_dsp/arm/idct8x8_add_neon.c", + "vpx_dsp/arm/intrapred_neon.c", + "vpx_dsp/arm/loopfilter_16_neon.c", + "vpx_dsp/arm/loopfilter_4_neon.c", + "vpx_dsp/arm/loopfilter_8_neon.c", + "vpx_dsp/arm/loopfilter_neon.c", + "vpx_dsp/arm/vpx_convolve8_avg_neon.c", + "vpx_dsp/arm/vpx_convolve8_neon.c", + "vpx_dsp/arm/vpx_convolve_avg_neon.c", + "vpx_dsp/arm/vpx_convolve_copy_neon.c", + "vpx_dsp/arm/vpx_convolve_neon.c" +] +libvpx_sources_arm_neon_gas = [ + "vpx_dsp/arm/gas/intrapred_neon_asm.s", + "vpx_dsp/arm/gas/loopfilter_mb_neon.s", + "vpx_dsp/arm/gas/save_reg_neon.s" +] +libvpx_sources_arm_neon_armasm_ms = [ + "vpx_dsp/arm/armasm_ms/intrapred_neon_asm.asm", + "vpx_dsp/arm/armasm_ms/loopfilter_mb_neon.asm", + "vpx_dsp/arm/armasm_ms/save_reg_neon.asm" +] +libvpx_sources_arm_neon_gas_apple = [ + "vpx_dsp/arm/gas_apple/intrapred_neon_asm.s", + "vpx_dsp/arm/gas_apple/loopfilter_mb_neon.s", + "vpx_dsp/arm/gas_apple/save_reg_neon.s" +] + +libvpx_sources = [libvpx_dir + file for file in libvpx_sources] +libvpx_sources_intrin_x86 = [libvpx_dir + file for file in libvpx_sources_intrin_x86] +libvpx_sources_intrin_x86_mmx = [libvpx_dir + file for file in libvpx_sources_intrin_x86_mmx] +libvpx_sources_intrin_x86_sse2 = [libvpx_dir + file for file in libvpx_sources_intrin_x86_sse2] +libvpx_sources_intrin_x86_ssse3 = [libvpx_dir + file for file in libvpx_sources_intrin_x86_ssse3] +libvpx_sources_intrin_x86_avx2 = [libvpx_dir + file for file in libvpx_sources_intrin_x86_avx2] +libvpx_sources_x86asm = [libvpx_dir + file for file in libvpx_sources_x86asm] +libvpx_sources_x86_64asm = [libvpx_dir + file for file in libvpx_sources_x86_64asm] +libvpx_sources_arm = [libvpx_dir + file for file in libvpx_sources_arm] +libvpx_sources_arm_neon = [libvpx_dir + file for file in libvpx_sources_arm_neon] +libvpx_sources_arm_neon_gas = [libvpx_dir + file for file in libvpx_sources_arm_neon_gas] +libvpx_sources_arm_neon_armasm_ms = [libvpx_dir + file for file in libvpx_sources_arm_neon_armasm_ms] +libvpx_sources_arm_neon_gas_apple = [libvpx_dir + file for file in libvpx_sources_arm_neon_gas_apple] + + +Import('env') +Import('env_webm') + +env_webm.Append(CPPPATH=[libvpx_dir]) + +env_libvpx = env.Clone() +env_libvpx.Append(CPPPATH=[libvpx_dir]) + +cpu_bits = env["bits"] +osx_fat = (env["platform"] == 'osx' and cpu_bits == 'fat') +webm_cpu_x86 = False +webm_cpu_arm = False +if env["platform"] == 'uwp': + if 'arm' in env["PROGSUFFIX"]: + webm_cpu_arm = True + else: + webm_cpu_x86 = True +else: + import platform + is_x11_or_server_arm = ((env["platform"] == 'x11' or env["platform"] == 'server') and platform.machine().startswith('arm')) + is_ios_x86 = (env["platform"] == 'iphone' and env["ios_sim"] == "yes") + is_android_x86 = (env["platform"] == 'android' and env["android_arch"] == 'x86') + if is_android_x86: + cpu_bits = '32' + if osx_fat: + webm_cpu_x86 = True + else: + webm_cpu_x86 = not is_x11_or_server_arm and (cpu_bits == '32' or cpu_bits == '64') and (env["platform"] == 'windows' or env["platform"] == 'x11' or env["platform"] == 'osx' or env["platform"] == 'haiku' or is_android_x86 or is_ios_x86) + webm_cpu_arm = is_x11_or_server_arm or (not is_ios_x86 and env["platform"] == 'iphone') or env["platform"] == 'bb10' or (not is_android_x86 and env["platform"] == 'android') + +if webm_cpu_x86: + import subprocess + import os + + yasm_paths = [ + "yasm", + "../../../yasm", + ] + + yasm_found = False + + devnull = open(os.devnull) + for yasm_path in yasm_paths: + try: + yasm_found = True + subprocess.Popen([yasm_path, "--version"], stdout=devnull, stderr=devnull).communicate() + except: + yasm_found = False + if yasm_found: + break + + if not yasm_found: + webm_cpu_x86 = False + print "YASM is necessary for WebM SIMD optimizations." + +webm_simd_optimizations = False + +if webm_cpu_x86: + if osx_fat: + #'osx' platform only: run python script which will compile using 'yasm' command and then merge 32-bit and 64-bit using 'lipo' command + env_libvpx["AS"] = 'python modules/webm/libvpx/yasm_osx_fat.py' + env_libvpx["ASFLAGS"] = '-I' + libvpx_dir[1:] + env_libvpx["ASCOM"] = '$AS $ASFLAGS $TARGET $SOURCES' + else: + if env["platform"] == 'windows' or env["platform"] == 'uwp': + env_libvpx["ASFORMAT"] = 'win' + elif env["platform"] == 'osx' or env["platform"] == "iphone": + env_libvpx["ASFORMAT"] = 'macho' + else: + env_libvpx["ASFORMAT"] = 'elf' + env_libvpx["ASFORMAT"] += cpu_bits + + env_libvpx["AS"] = 'yasm' + env_libvpx["ASFLAGS"] = '-I' + libvpx_dir[1:] + ' -f $ASFORMAT -D $ASCPU' + env_libvpx["ASCOM"] = '$AS $ASFLAGS -o $TARGET $SOURCES' + + if cpu_bits == '32': + env_libvpx["ASCPU"] = 'X86_32' + elif cpu_bits == '64': + env_libvpx["ASCPU"] = 'X86_64' + + env_libvpx.Append(CCFLAGS=['-DWEBM_X86ASM']) + + webm_simd_optimizations = True + +if webm_cpu_arm: + if env["platform"] == 'iphone': + env_libvpx["ASFLAGS"] = '-arch armv7' + elif env["platform"] == 'android' or env["platform"] == 'x11' or env["platform"] == 'server': + env_libvpx["ASFLAGS"] = '-mfpu=neon' + elif env["platform"] == 'uwp': + env_libvpx["AS"] = 'armasm' + env_libvpx["ASFLAGS"] = '' + env_libvpx["ASCOM"] = '$AS $ASFLAGS -o $TARGET $SOURCES' + + env_libvpx.Append(CCFLAGS=['-DWEBM_ARMASM']) + + webm_simd_optimizations = True + +if webm_simd_optimizations == False: + print "WebM SIMD optimizations are disabled. Check if your CPU architecture, CPU bits or platform are supported!" + + +env_libvpx.add_source_files(env.modules_sources, libvpx_sources) +if webm_cpu_x86: + is_clang_or_gcc = ('gcc' in env["CC"]) or ('clang' in env["CC"]) + + env_libvpx_mmx = env_libvpx.Clone() + if cpu_bits == '32' and is_clang_or_gcc: + env_libvpx_mmx.Append(CCFLAGS=['-mmmx']) + env_libvpx_mmx.add_source_files(env.modules_sources, libvpx_sources_intrin_x86_mmx) + + env_libvpx_sse2 = env_libvpx.Clone() + if cpu_bits == '32' and is_clang_or_gcc: + env_libvpx_sse2.Append(CCFLAGS=['-msse2']) + env_libvpx_sse2.add_source_files(env.modules_sources, libvpx_sources_intrin_x86_sse2) + + env_libvpx_ssse3 = env_libvpx.Clone() + if is_clang_or_gcc: + env_libvpx_ssse3.Append(CCFLAGS=['-mssse3']) + env_libvpx_ssse3.add_source_files(env.modules_sources, libvpx_sources_intrin_x86_ssse3) + + env_libvpx_avx2 = env_libvpx.Clone() + if is_clang_or_gcc: + env_libvpx_avx2.Append(CCFLAGS=['-mavx2']) + env_libvpx_avx2.add_source_files(env.modules_sources, libvpx_sources_intrin_x86_avx2) + + env_libvpx.add_source_files(env.modules_sources, libvpx_sources_intrin_x86) + + env_libvpx.add_source_files(env.modules_sources, libvpx_sources_x86asm) + if cpu_bits == '64' or osx_fat: + env_libvpx.add_source_files(env.modules_sources, libvpx_sources_x86_64asm) +elif webm_cpu_arm: + env_libvpx.add_source_files(env.modules_sources, libvpx_sources_arm) + + env_libvpx_neon = env_libvpx.Clone() + if env["platform"] == 'android' and env["android_arch"] == 'armv6': + env_libvpx_neon.Append(CCFLAGS=['-mfpu=neon']) + env_libvpx_neon.add_source_files(env.modules_sources, libvpx_sources_arm_neon) + + if env["platform"] == 'uwp': + env_libvpx.add_source_files(env.modules_sources, libvpx_sources_arm_neon_armasm_ms) + elif env["platform"] == 'iphone': + env_libvpx.add_source_files(env.modules_sources, libvpx_sources_arm_neon_gas_apple) + else: + env_libvpx.add_source_files(env.modules_sources, libvpx_sources_arm_neon_gas) diff --git a/modules/webm/libvpx/yasm_osx_fat.py b/modules/webm/libvpx/yasm_osx_fat.py new file mode 100644 index 0000000000..0065e2766c --- /dev/null +++ b/modules/webm/libvpx/yasm_osx_fat.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +import sys +import os + +includes = sys.argv[1] +output_file = sys.argv[2] +input_file = sys.argv[3] + +can_remove = {} + +lipo_command = '' + +exit_code = 1 + +for arch in ['32', '64']: + if arch == '32' and input_file.endswith('x86_64.asm'): + can_remove[arch] = False + else: + command = 'yasm ' + includes + ' -f macho' + arch + ' -D X86_' + arch + ' -o ' + output_file + '.' + arch + ' ' + input_file + print(command) + if os.system(command) == 0: + lipo_command += output_file + '.' + arch + ' ' + can_remove[arch] = True + else: + can_remove[arch] = False + +if lipo_command != '': + lipo_command = 'lipo -create ' + lipo_command + '-output ' + output_file + print(lipo_command) + if os.system(lipo_command) == 0: + exit_code = 0 + +for arch in ['32', '64']: + if can_remove[arch]: + os.remove(output_file + '.' + arch) + +sys.exit(exit_code) diff --git a/modules/webm/register_types.cpp b/modules/webm/register_types.cpp new file mode 100644 index 0000000000..e50eb337ae --- /dev/null +++ b/modules/webm/register_types.cpp @@ -0,0 +1,45 @@ +/*************************************************************************/ +/* register_types.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#include "register_types.h" + +#include "video_stream_webm.h" + +static ResourceFormatLoaderVideoStreamWebm *webm_stream_loader = NULL; + +void register_webm_types() { + + webm_stream_loader = memnew(ResourceFormatLoaderVideoStreamWebm); + ResourceLoader::add_resource_format_loader(webm_stream_loader); + ClassDB::register_class<VideoStreamWebm>(); +} + +void unregister_webm_types() { + + memdelete(webm_stream_loader); +} diff --git a/modules/webm/register_types.h b/modules/webm/register_types.h new file mode 100644 index 0000000000..3df0d7bbaa --- /dev/null +++ b/modules/webm/register_types.h @@ -0,0 +1,30 @@ +/*************************************************************************/ +/* register_types.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +void register_webm_types(); +void unregister_webm_types(); diff --git a/modules/webm/video_stream_webm.cpp b/modules/webm/video_stream_webm.cpp new file mode 100644 index 0000000000..d4995ad798 --- /dev/null +++ b/modules/webm/video_stream_webm.cpp @@ -0,0 +1,446 @@ +/*************************************************************************/ +/* av_stream_webm.cpp.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#include "video_stream_webm.h" + +#include "VPXDecoder.hpp" +#include "OpusVorbisDecoder.hpp" + +#include "mkvparser/mkvparser.h" +#include "../theora/yuv2rgb.h" + +#include "os/file_access.h" +#include "global_config.h" + +#include <string.h> + +class MkvReader : public mkvparser::IMkvReader { + +public: + MkvReader(const String &p_file) { + + file = FileAccess::open(p_file, FileAccess::READ); + ERR_FAIL_COND(!file); + } + ~MkvReader() { + + if (file) + memdelete(file); + } + + virtual int Read(long long pos, long len, unsigned char *buf) { + + if (file) { + + if (file->get_pos() != (size_t)pos) + file->seek(pos); + if (file->get_buffer(buf, len) == len) + return 0; + } + return -1; + } + + virtual int Length(long long *total, long long *available) { + + if (file) { + + const size_t len = file->get_len(); + if (total) + *total = len; + if (available) + *available = len; + return 0; + } + return -1; + } + +private: + FileAccess *file; +}; + +/**/ + +VideoStreamPlaybackWebm::VideoStreamPlaybackWebm() : + audio_track(0), + webm(NULL), + video(NULL), + audio(NULL), + video_frames(NULL), audio_frame(NULL), + video_frames_pos(0), video_frames_capacity(0), + num_decoded_samples(0), samples_offset(-1), + mix_callback(NULL), + mix_udata(NULL), + playing(false), paused(false), + delay_compensation(0.0), + time(0.0), video_frame_delay(0.0), video_pos(0.0), + texture(memnew(ImageTexture)), + pcm(NULL) +{} +VideoStreamPlaybackWebm::~VideoStreamPlaybackWebm() { + + delete_pointers(); +} + +bool VideoStreamPlaybackWebm::open_file(const String &p_file) { + + file_name = p_file; + webm = memnew(WebMDemuxer(new MkvReader(file_name), 0, audio_track)); + if (webm->isOpen()) { + + video = memnew(VPXDecoder(*webm, 8)); //TODO: Detect CPU threads + if (video->isOpen()) { + + audio = memnew(OpusVorbisDecoder(*webm)); + if (audio->isOpen()) { + + audio_frame = memnew(WebMFrame); + pcm = (int16_t *)memalloc(sizeof(int16_t) * audio->getBufferSamples() * webm->getChannels()); + } else { + + memdelete(audio); + audio = NULL; + } + + frame_data.resize((webm->getWidth() * webm->getHeight()) << 2); + texture->create(webm->getWidth(), webm->getHeight(), Image::FORMAT_RGBA8, Texture::FLAG_FILTER | Texture::FLAG_VIDEO_SURFACE); + + return true; + } + memdelete(video); + video = NULL; + } + memdelete(webm); + webm = NULL; + return false; +} + +void VideoStreamPlaybackWebm::stop() { + + if (playing) { + + delete_pointers(); + + pcm = NULL; + + audio_frame = NULL; + video_frames = NULL; + + video = NULL; + audio = NULL; + + open_file(file_name); //Should not fail here... + + video_frames_capacity = video_frames_pos = 0; + num_decoded_samples = 0; + samples_offset = -1; + video_frame_delay = video_pos = 0.0; + } + time = 0.0; + playing = false; +} +void VideoStreamPlaybackWebm::play() { + + stop(); + + delay_compensation = GlobalConfig::get_singleton()->get("audio/video_delay_compensation_ms"); + delay_compensation /= 1000.0; + + playing = true; +} + +bool VideoStreamPlaybackWebm::is_playing() const { + + return playing; +} + +void VideoStreamPlaybackWebm::set_paused(bool p_paused) { + + paused = p_paused; +} +bool VideoStreamPlaybackWebm::is_paused(bool p_paused) const { + + return paused; +} + +void VideoStreamPlaybackWebm::set_loop(bool p_enable) { + + //Empty +} +bool VideoStreamPlaybackWebm::has_loop() const { + + return false; +} + +float VideoStreamPlaybackWebm::get_length() const { + + if (webm) + return webm->getLength(); + return 0.0f; +} + +float VideoStreamPlaybackWebm::get_pos() const { + + return video_pos; +} +void VideoStreamPlaybackWebm::seek_pos(float p_time) { + + //Not implemented +} + +void VideoStreamPlaybackWebm::set_audio_track(int p_idx) { + + audio_track = p_idx; +} + +Ref<Texture> VideoStreamPlaybackWebm::get_texture() { + + return texture; +} +void VideoStreamPlaybackWebm::update(float p_delta) { + + if ((!playing || paused) || !video) + return; + + bool audio_buffer_full = false; + + if (samples_offset > -1) { + + //Mix remaining samples + const int to_read = num_decoded_samples - samples_offset; + const int mixed = mix_callback(mix_udata, pcm + samples_offset * webm->getChannels(), to_read); + if (mixed != to_read) { + + samples_offset += mixed; + audio_buffer_full = true; + } else { + + samples_offset = -1; + } + } + + const bool hasAudio = (audio && mix_callback); + while ((hasAudio && (!audio_buffer_full || !has_enough_video_frames())) || (!hasAudio && video_frames_pos == 0)) { + + if (hasAudio && !audio_buffer_full && audio_frame->isValid() && audio->getPCMS16(*audio_frame, pcm, num_decoded_samples) && num_decoded_samples > 0) { + + const int mixed = mix_callback(mix_udata, pcm, num_decoded_samples); + if (mixed != num_decoded_samples) { + + samples_offset = mixed; + audio_buffer_full = true; + } + } + + WebMFrame *video_frame; + if (video_frames_pos >= video_frames_capacity) { + + WebMFrame **video_frames_new = (WebMFrame **)memrealloc(video_frames, ++video_frames_capacity * sizeof(void *)); + ERR_FAIL_COND(!video_frames_new); //Out of memory + (video_frames = video_frames_new)[video_frames_capacity - 1] = memnew(WebMFrame); + } + video_frame = video_frames[video_frames_pos]; + + if (!webm->readFrame(video_frame, audio_frame)) //This will invalidate frames + break; //Can't demux, EOS? + + if (video_frame->isValid()) + ++video_frames_pos; + }; + + const double video_delay = video->getFramesDelay() * video_frame_delay; + + bool want_this_frame = false; + while (video_frames_pos > 0 && !want_this_frame) { + + WebMFrame *video_frame = video_frames[0]; + if (video_frame->time <= time + video_delay) { + + if (video->decode(*video_frame)) { + + VPXDecoder::IMAGE_ERROR err; + VPXDecoder::Image image; + + while ((err = video->getImage(image)) != VPXDecoder::NO_FRAME) { + + want_this_frame = (time - video_frame->time <= video_frame_delay); + + if (want_this_frame) { + + if (err == VPXDecoder::NO_ERROR && image.w == webm->getWidth() && image.h == webm->getHeight()) { + + PoolVector<uint8_t>::Write w = frame_data.write(); + bool converted = false; + + if (image.chromaShiftW == 1 && image.chromaShiftH == 1) { + + yuv420_2_rgb8888(w.ptr(), image.planes[0], image.planes[2], image.planes[1], image.w, image.h, image.linesize[0], image.linesize[1], image.w << 2, 0); +// libyuv::I420ToARGB(image.planes[0], image.linesize[0], image.planes[2], image.linesize[2], image.planes[1], image.linesize[1], w.ptr(), image.w << 2, image.w, image.h); + converted = true; + } else if (image.chromaShiftW == 1 && image.chromaShiftH == 0) { + + yuv422_2_rgb8888(w.ptr(), image.planes[0], image.planes[2], image.planes[1], image.w, image.h, image.linesize[0], image.linesize[1], image.w << 2, 0); +// libyuv::I422ToARGB(image.planes[0], image.linesize[0], image.planes[2], image.linesize[2], image.planes[1], image.linesize[1], w.ptr(), image.w << 2, image.w, image.h); + converted = true; + } else if (image.chromaShiftW == 0 && image.chromaShiftH == 0) { + + yuv444_2_rgb8888(w.ptr(), image.planes[0], image.planes[2], image.planes[1], image.w, image.h, image.linesize[0], image.linesize[1], image.w << 2, 0); +// libyuv::I444ToARGB(image.planes[0], image.linesize[0], image.planes[2], image.linesize[2], image.planes[1], image.linesize[1], w.ptr(), image.w << 2, image.w, image.h); + converted = true; + } else if (image.chromaShiftW == 2 && image.chromaShiftH == 0) { + +// libyuv::I411ToARGB(image.planes[0], image.linesize[0], image.planes[2], image.linesize[2], image.planes[1], image.linesize[1], w.ptr(), image.w << 2, image.w, image.h); +// converted = true; + } + + if (converted) + texture->set_data(Image(image.w, image.h, 0, Image::FORMAT_RGBA8, frame_data)); //Zero copy send to visual server + } + + break; + } + } + } + + video_frame_delay = video_frame->time - video_pos; + video_pos = video_frame->time; + + memmove(video_frames, video_frames + 1, (--video_frames_pos) * sizeof(void *)); + video_frames[video_frames_pos] = video_frame; + } else { + + break; + } + } + + time += p_delta; + + if (video_frames_pos == 0 && webm->isEOS()) + stop(); +} + +void VideoStreamPlaybackWebm::set_mix_callback(VideoStreamPlayback::AudioMixCallback p_callback, void *p_userdata) { + + mix_callback = p_callback; + mix_udata = p_userdata; +} +int VideoStreamPlaybackWebm::get_channels() const { + + if (audio) + return webm->getChannels(); + return 0; +} +int VideoStreamPlaybackWebm::get_mix_rate() const { + + if (audio) + return webm->getSampleRate(); + return 0; +} + +inline bool VideoStreamPlaybackWebm::has_enough_video_frames() const +{ + if (video_frames_pos > 0) { + + const double audio_delay = AudioServer::get_singleton()->get_output_delay(); + const double video_time = video_frames[video_frames_pos - 1]->time; + return video_time >= time + audio_delay + delay_compensation; + } + return false; +} + +void VideoStreamPlaybackWebm::delete_pointers() { + + if (pcm) + memfree(pcm); + + if (audio_frame) + memdelete(audio_frame); + for (int i = 0; i < video_frames_capacity; ++i) + memdelete(video_frames[i]); + if (video_frames) + memfree(video_frames); + + if (video) + memdelete(video); + if (audio) + memdelete(audio); + + if (webm) + memdelete(webm); +} + +/**/ + +RES ResourceFormatLoaderVideoStreamWebm::load(const String &p_path, const String &p_original_path, Error *r_error) { + + Ref<VideoStreamWebm> stream = memnew(VideoStreamWebm); + stream->set_file(p_path); + if (r_error) + *r_error = OK; + return stream; +} + +void ResourceFormatLoaderVideoStreamWebm::get_recognized_extensions(List<String> *p_extensions) const { + + p_extensions->push_back("webm"); +} +bool ResourceFormatLoaderVideoStreamWebm::handles_type(const String &p_type) const { + + return (p_type == "VideoStream" || p_type == "VideoStreamWebm"); +} + +String ResourceFormatLoaderVideoStreamWebm::get_resource_type(const String &p_path) const { + + const String exl = p_path.get_extension().to_lower(); + if (exl == "webm") + return "VideoStreamWebm"; + return ""; +} + +/**/ + +VideoStreamWebm::VideoStreamWebm() : + audio_track(0) +{} + +Ref<VideoStreamPlayback> VideoStreamWebm::instance_playback() { + + Ref<VideoStreamPlaybackWebm> pb = memnew(VideoStreamPlaybackWebm); + pb->set_audio_track(audio_track); + if (pb->open_file(file)) + return pb; + return NULL; +} + +void VideoStreamWebm::set_file(const String &p_file) { + + file = p_file; +} +void VideoStreamWebm::set_audio_track(int p_track) { + + audio_track = p_track; +} diff --git a/modules/webm/video_stream_webm.h b/modules/webm/video_stream_webm.h new file mode 100644 index 0000000000..cb4ef53f6d --- /dev/null +++ b/modules/webm/video_stream_webm.h @@ -0,0 +1,128 @@ +/*************************************************************************/ +/* av_stream_webm.cpp.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#include "scene/resources/video_stream.h" +#include "io/resource_loader.h" + +class WebMFrame; +class WebMDemuxer; +class VPXDecoder; +class OpusVorbisDecoder; + +class VideoStreamPlaybackWebm : public VideoStreamPlayback { + + GDCLASS(VideoStreamPlaybackWebm, VideoStreamPlayback) + + String file_name; + int audio_track; + + WebMDemuxer *webm; + VPXDecoder *video; + OpusVorbisDecoder *audio; + + WebMFrame **video_frames, *audio_frame; + int video_frames_pos, video_frames_capacity; + + int num_decoded_samples, samples_offset; + AudioMixCallback mix_callback; + void *mix_udata; + + bool playing, paused; + double delay_compensation; + double time, video_frame_delay, video_pos; + + PoolVector<uint8_t> frame_data; + Ref<ImageTexture> texture; + + int16_t *pcm; + +public: + VideoStreamPlaybackWebm(); + ~VideoStreamPlaybackWebm(); + + bool open_file(const String &p_file); + + virtual void stop(); + virtual void play(); + + virtual bool is_playing() const; + + virtual void set_paused(bool p_paused); + virtual bool is_paused(bool p_paused) const; + + virtual void set_loop(bool p_enable); + virtual bool has_loop() const; + + virtual float get_length() const; + + virtual float get_pos() const; + virtual void seek_pos(float p_time); + + virtual void set_audio_track(int p_idx); + + virtual Ref<Texture> get_texture(); + virtual void update(float p_delta); + + virtual void set_mix_callback(AudioMixCallback p_callback, void *p_userdata); + virtual int get_channels() const; + virtual int get_mix_rate() const; + +private: + inline bool has_enough_video_frames() const; + + void delete_pointers(); +}; + +/**/ + +class VideoStreamWebm : public VideoStream { + + GDCLASS(VideoStreamWebm, VideoStream) + + String file; + int audio_track; + +public: + VideoStreamWebm(); + + virtual Ref<VideoStreamPlayback> instance_playback(); + + virtual void set_file(const String &p_file); + virtual void set_audio_track(int p_track); +}; + +/**/ + +class ResourceFormatLoaderVideoStreamWebm : public ResourceFormatLoader { + +public: + virtual RES load(const String &p_path, const String &p_original_path, Error *r_error); + virtual void get_recognized_extensions(List<String> *p_extensions) const; + virtual bool handles_type(const String &p_type) const; + virtual String get_resource_type(const String &p_path) const; +}; diff --git a/modules/webp/SCsub b/modules/webp/SCsub new file mode 100644 index 0000000000..aa3486a2c5 --- /dev/null +++ b/modules/webp/SCsub @@ -0,0 +1,131 @@ +#!/usr/bin/env python + +Import('env') +Import('env_modules') + +env_webp = env_modules.Clone() + +# Thirdparty source files +if (env['builtin_libwebp'] != 'no'): + thirdparty_dir = "#thirdparty/libwebp/" + thirdparty_sources = [ + "dec/alpha_dec.c", + "dec/buffer_dec.c", + "dec/frame_dec.c", + "dec/idec_dec.c", + "dec/io_dec.c", + "dec/quant_dec.c", + "dec/tree_dec.c", + "dec/vp8_dec.c", + "dec/vp8l_dec.c", + "dec/webp_dec.c", + "demux/anim_decode.c", + "demux/demux.c", + "dsp/alpha_processing.c", + "dsp/alpha_processing_mips_dsp_r2.c", + "dsp/alpha_processing_neon.c", + "dsp/alpha_processing_sse2.c", + "dsp/alpha_processing_sse41.c", + "dsp/argb.c", + "dsp/argb_mips_dsp_r2.c", + "dsp/argb_sse2.c", + "dsp/cost.c", + "dsp/cost_mips32.c", + "dsp/cost_mips_dsp_r2.c", + "dsp/cost_sse2.c", + "dsp/cpu.c", + "dsp/dec.c", + "dsp/dec_clip_tables.c", + "dsp/dec_mips32.c", + "dsp/dec_mips_dsp_r2.c", + "dsp/dec_msa.c", + "dsp/dec_neon.c", + "dsp/dec_sse2.c", + "dsp/dec_sse41.c", + "dsp/enc_avx2.c", + "dsp/enc.c", + "dsp/enc_mips32.c", + "dsp/enc_mips_dsp_r2.c", + "dsp/enc_msa.c", + "dsp/enc_neon.c", + "dsp/enc_sse2.c", + "dsp/enc_sse41.c", + "dsp/filters.c", + "dsp/filters_mips_dsp_r2.c", + "dsp/filters_msa.c", + "dsp/filters_neon.c", + "dsp/filters_sse2.c", + "dsp/lossless.c", + "dsp/lossless_enc.c", + "dsp/lossless_enc_mips32.c", + "dsp/lossless_enc_mips_dsp_r2.c", + "dsp/lossless_enc_msa.c", + "dsp/lossless_enc_neon.c", + "dsp/lossless_enc_sse2.c", + "dsp/lossless_enc_sse41.c", + "dsp/lossless_mips_dsp_r2.c", + "dsp/lossless_msa.c", + "dsp/lossless_neon.c", + "dsp/lossless_sse2.c", + "dsp/rescaler.c", + "dsp/rescaler_mips32.c", + "dsp/rescaler_mips_dsp_r2.c", + "dsp/rescaler_msa.c", + "dsp/rescaler_neon.c", + "dsp/rescaler_sse2.c", + "dsp/upsampling.c", + "dsp/upsampling_mips_dsp_r2.c", + "dsp/upsampling_msa.c", + "dsp/upsampling_neon.c", + "dsp/upsampling_sse2.c", + "dsp/yuv.c", + "dsp/yuv_mips32.c", + "dsp/yuv_mips_dsp_r2.c", + "dsp/yuv_sse2.c", + "enc/alpha_enc.c", + "enc/analysis_enc.c", + "enc/backward_references_enc.c", + "enc/config_enc.c", + "enc/cost_enc.c", + "enc/delta_palettization_enc.c", + "enc/filter_enc.c", + "enc/frame_enc.c", + "enc/histogram_enc.c", + "enc/iterator_enc.c", + "enc/near_lossless_enc.c", + "enc/picture_csp_enc.c", + "enc/picture_enc.c", + "enc/picture_psnr_enc.c", + "enc/picture_rescale_enc.c", + "enc/picture_tools_enc.c", + "enc/predictor_enc.c", + "enc/quant_enc.c", + "enc/syntax_enc.c", + "enc/token_enc.c", + "enc/tree_enc.c", + "enc/vp8l_enc.c", + "enc/webp_enc.c", + "mux/anim_encode.c", + "mux/muxedit.c", + "mux/muxinternal.c", + "mux/muxread.c", + "utils/bit_reader_utils.c", + "utils/bit_writer_utils.c", + "utils/color_cache_utils.c", + "utils/filters_utils.c", + "utils/huffman_encode_utils.c", + "utils/huffman_utils.c", + "utils/quant_levels_dec_utils.c", + "utils/quant_levels_utils.c", + "utils/random_utils.c", + "utils/rescaler_utils.c", + "utils/thread_utils.c", + "utils/utils.c", + ] + thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] + + env_webp.add_source_files(env.modules_sources, thirdparty_sources) + env_webp.Append(CPPPATH=[thirdparty_dir]) + +# Godot source files +env_webp.add_source_files(env.modules_sources, "*.cpp") diff --git a/modules/webp/config.py b/modules/webp/config.py new file mode 100644 index 0000000000..fb920482f5 --- /dev/null +++ b/modules/webp/config.py @@ -0,0 +1,7 @@ + +def can_build(platform): + return True + + +def configure(env): + pass diff --git a/modules/webp/image_loader_webp.cpp b/modules/webp/image_loader_webp.cpp new file mode 100644 index 0000000000..3508c6a663 --- /dev/null +++ b/modules/webp/image_loader_webp.cpp @@ -0,0 +1,183 @@ +/*************************************************************************/ +/* image_loader_webp.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#include "image_loader_webp.h" + +#include "io/marshalls.h" +#include "print_string.h" +#include "os/os.h" + +#include <stdlib.h> +#include <webp/decode.h> +#include <webp/encode.h> + +static PoolVector<uint8_t> _webp_lossy_pack(const Image& p_image,float p_quality) { + + ERR_FAIL_COND_V(p_image.empty(),PoolVector<uint8_t>()); + + Image img=p_image; + if (img.detect_alpha()) + img.convert(Image::FORMAT_RGBA8); + else + img.convert(Image::FORMAT_RGB8); + + Size2 s(img.get_width(),img.get_height()); + PoolVector<uint8_t> data = img.get_data(); + PoolVector<uint8_t>::Read r = data.read(); + + uint8_t *dst_buff=NULL; + size_t dst_size=0; + if (img.get_format()==Image::FORMAT_RGB8) { + + dst_size = WebPEncodeRGB(r.ptr(),s.width,s.height,3*s.width,CLAMP(p_quality*100.0,0,100.0),&dst_buff); + } else { + dst_size = WebPEncodeRGBA(r.ptr(),s.width,s.height,4*s.width,CLAMP(p_quality*100.0,0,100.0),&dst_buff); + } + + ERR_FAIL_COND_V(dst_size==0,PoolVector<uint8_t>()); + PoolVector<uint8_t> dst; + dst.resize(4+dst_size); + PoolVector<uint8_t>::Write w = dst.write(); + w[0]='W'; + w[1]='E'; + w[2]='B'; + w[3]='P'; + copymem(&w[4],dst_buff,dst_size); + free(dst_buff); + w=PoolVector<uint8_t>::Write(); + return dst; +} + +static Image _webp_lossy_unpack(const PoolVector<uint8_t>& p_buffer) { + + int size = p_buffer.size()-4; + ERR_FAIL_COND_V(size<=0,Image()); + PoolVector<uint8_t>::Read r = p_buffer.read(); + + ERR_FAIL_COND_V(r[0]!='W' || r[1]!='E' || r[2]!='B' || r[3]!='P',Image()); + WebPBitstreamFeatures features; + if (WebPGetFeatures(&r[4],size,&features)!=VP8_STATUS_OK) { + ERR_EXPLAIN("Error unpacking WEBP image:"); + ERR_FAIL_V(Image()); + } + + //print_line("width: "+itos(features.width)); + //print_line("height: "+itos(features.height)); + //print_line("alpha: "+itos(features.has_alpha)); + + PoolVector<uint8_t> dst_image; + int datasize = features.width*features.height*(features.has_alpha?4:3); + dst_image.resize(datasize); + + PoolVector<uint8_t>::Write dst_w = dst_image.write(); + + bool errdec=false; + if (features.has_alpha) { + errdec = WebPDecodeRGBAInto(&r[4],size,dst_w.ptr(),datasize,4*features.width)==NULL; + } else { + errdec = WebPDecodeRGBInto(&r[4],size,dst_w.ptr(),datasize,3*features.width)==NULL; + + } + + //ERR_EXPLAIN("Error decoding webp! - "+p_file); + ERR_FAIL_COND_V(errdec,Image()); + + dst_w = PoolVector<uint8_t>::Write(); + + return Image(features.width,features.height,0,features.has_alpha?Image::FORMAT_RGBA8:Image::FORMAT_RGB8,dst_image); + +} + + +Error ImageLoaderWEBP::load_image(Image *p_image,FileAccess *f) { + + + uint32_t size = f->get_len(); + PoolVector<uint8_t> src_image; + src_image.resize(size); + + WebPBitstreamFeatures features; + + PoolVector<uint8_t>::Write src_w = src_image.write(); + f->get_buffer(src_w.ptr(),size); + ERR_FAIL_COND_V(f->eof_reached(), ERR_FILE_EOF); + + if (WebPGetFeatures(src_w.ptr(),size,&features)!=VP8_STATUS_OK) { + f->close(); + //ERR_EXPLAIN("Error decoding WEBP image: "+p_file); + ERR_FAIL_V(ERR_FILE_CORRUPT); + } + + print_line("width: "+itos(features.width)); + print_line("height: "+itos(features.height)); + print_line("alpha: "+itos(features.has_alpha)); + + src_w = PoolVector<uint8_t>::Write(); + + PoolVector<uint8_t> dst_image; + int datasize = features.width*features.height*(features.has_alpha?4:3); + dst_image.resize(datasize); + + PoolVector<uint8_t>::Read src_r = src_image.read(); + PoolVector<uint8_t>::Write dst_w = dst_image.write(); + + + bool errdec=false; + if (features.has_alpha) { + errdec = WebPDecodeRGBAInto(src_r.ptr(),size,dst_w.ptr(),datasize,4*features.width)==NULL; + } else { + errdec = WebPDecodeRGBInto(src_r.ptr(),size,dst_w.ptr(),datasize,3*features.width)==NULL; + + } + + //ERR_EXPLAIN("Error decoding webp! - "+p_file); + ERR_FAIL_COND_V(errdec,ERR_FILE_CORRUPT); + + src_r = PoolVector<uint8_t>::Read(); + dst_w = PoolVector<uint8_t>::Write(); + + *p_image = Image(features.width,features.height,0,features.has_alpha?Image::FORMAT_RGBA8:Image::FORMAT_RGB8,dst_image); + + + return OK; + +} + +void ImageLoaderWEBP::get_recognized_extensions(List<String> *p_extensions) const { + + p_extensions->push_back("webp"); +} + + +ImageLoaderWEBP::ImageLoaderWEBP() { + + Image::lossy_packer=_webp_lossy_pack; + Image::lossy_unpacker=_webp_lossy_unpack; +} + + diff --git a/modules/webp/image_loader_webp.h b/modules/webp/image_loader_webp.h new file mode 100644 index 0000000000..eb1b32ac95 --- /dev/null +++ b/modules/webp/image_loader_webp.h @@ -0,0 +1,49 @@ +/*************************************************************************/ +/* image_loader_webp.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#ifndef IMAGE_LOADER_WEBP_H +#define IMAGE_LOADER_WEBP_H + +#include "io/image_loader.h" + +/** + @author Juan Linietsky <reduzio@gmail.com> +*/ +class ImageLoaderWEBP : public ImageFormatLoader { + + +public: + + virtual Error load_image(Image *p_image,FileAccess *f); + virtual void get_recognized_extensions(List<String> *p_extensions) const; + ImageLoaderWEBP(); +}; + + + +#endif diff --git a/modules/webp/register_types.cpp b/modules/webp/register_types.cpp new file mode 100644 index 0000000000..7a4e35dc4c --- /dev/null +++ b/modules/webp/register_types.cpp @@ -0,0 +1,44 @@ +/*************************************************************************/ +/* register_types.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#include "register_types.h" + +#include "image_loader_webp.h" + +static ImageLoaderWEBP *image_loader_webp = NULL; + +void register_webp_types() { + + image_loader_webp = memnew( ImageLoaderWEBP ); + ImageLoader::add_image_format_loader(image_loader_webp); +} + +void unregister_webp_types() { + + memdelete( image_loader_webp ); +} diff --git a/modules/webp/register_types.h b/modules/webp/register_types.h new file mode 100644 index 0000000000..ce1f29937b --- /dev/null +++ b/modules/webp/register_types.h @@ -0,0 +1,30 @@ +/*************************************************************************/ +/* register_types.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +void register_webp_types(); +void unregister_webp_types(); |