From 9b8696d3dd92e2ed6f310ad0f0bf3c2182c9c6ae Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Wed, 11 Jun 2014 10:41:03 -0300 Subject: [PATCH] Light Baker! -=-=-=-=-=-= -Support for lightmap baker, have fun figuring out how it works before tutorial is published. --- SConstruct | 1 + core/SCsub | 28 + core/bind/core_bind.cpp | 4 +- core/image.cpp | 9 +- core/image.h | 6 +- core/io/resource_format_xml.cpp | 9 +- core/io/resource_format_xml.h | 2 +- core/math/aabb.cpp | 9 - core/math/aabb.h | 61 +- core/math/face3.cpp | 2 +- core/math/face3.h | 169 ++ core/packed_data_container.cpp | 20 +- core/packed_data_container.h | 2 + core/script_language.cpp | 2 - core/script_language.h | 1 + core/ustring.cpp | 113 +- core/variant_op.cpp | 2 +- demos/3d/platformer/stage2.xml | 336 ---- demos/3d/platformer/tiles.res | Bin 81468 -> 81673 bytes drivers/gles2/rasterizer_gles2.cpp | 49 +- drivers/gles2/shaders/material.glsl | 89 +- drivers/unix/ip_unix.cpp | 2 + modules/gdscript/gd_script.cpp | 29 +- modules/gdscript/gd_tokenizer.cpp | 1 + modules/gdscript/register_types.cpp | 78 +- modules/gridmap/grid_map.cpp | 140 +- modules/gridmap/grid_map.h | 13 + platform/javascript/detect.py | 2 +- scene/3d/baked_light.cpp | 7 - scene/3d/baked_light.h | 15 - scene/3d/baked_light_instance.cpp | 65 + scene/3d/baked_light_instance.h | 33 + scene/3d/light.cpp | 32 + scene/3d/light.h | 17 + scene/3d/sprite_3d.cpp | 1 + scene/3d/sprite_3d.h | 4 +- scene/3d/visual_instance.cpp | 76 +- scene/3d/visual_instance.h | 9 +- scene/register_scene_types.cpp | 5 +- scene/resources/baked_light.cpp | 308 +++ scene/resources/baked_light.h | 106 + scene/scene_string_names.cpp | 4 + scene/scene_string_names.h | 3 + servers/visual/rasterizer.h | 21 + servers/visual/visual_server_raster.cpp | 309 ++- servers/visual/visual_server_raster.h | 57 +- servers/visual/visual_server_wrap_mt.h | 20 + servers/visual_server.cpp | 2 + servers/visual_server.h | 29 +- tools/editor/editor_import_export.cpp | 63 +- tools/editor/editor_import_export.h | 14 + tools/editor/icons/icon_bake.png | Bin 0 -> 419 bytes tools/editor/icons/icon_reload.png | Bin 371 -> 567 bytes .../io_plugins/editor_import_collada.cpp | 1 + .../editor_texture_import_plugin.cpp | 16 +- tools/editor/plugins/baked_light_baker.cpp | 1765 +++++++++++++++++ tools/editor/plugins/baked_light_baker.h | 316 +++ .../plugins/baked_light_editor_plugin.cpp | 1096 ++-------- .../plugins/baked_light_editor_plugin.h | 30 +- tools/editor/project_export.cpp | 70 +- tools/editor/project_export.h | 9 + 61 files changed, 4252 insertions(+), 1430 deletions(-) delete mode 100644 demos/3d/platformer/stage2.xml delete mode 100644 scene/3d/baked_light.cpp delete mode 100644 scene/3d/baked_light.h create mode 100644 scene/3d/baked_light_instance.cpp create mode 100644 scene/3d/baked_light_instance.h create mode 100644 scene/resources/baked_light.cpp create mode 100644 scene/resources/baked_light.h create mode 100644 tools/editor/icons/icon_bake.png create mode 100644 tools/editor/plugins/baked_light_baker.cpp create mode 100644 tools/editor/plugins/baked_light_baker.h diff --git a/SConstruct b/SConstruct index a5489d1534..19c5d8ce8a 100644 --- a/SConstruct +++ b/SConstruct @@ -169,6 +169,7 @@ if (env_base['target']=='debug'): env_base.platforms = {} + for p in platform_list: if env_base['platform'] != "" and env_base['platform'] != p: diff --git a/core/SCsub b/core/SCsub index 9a86c2943d..7eace22b73 100644 --- a/core/SCsub +++ b/core/SCsub @@ -19,9 +19,37 @@ f = open("global_defaults.cpp","wb") f.write(gd_cpp) f.close() +import os +txt = "0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0" +if ("SCRIPT_AES256_ENCRYPTION_KEY" in os.environ): + e=os.environ["SCRIPT_AES256_ENCRYPTION_KEY"] + txt = "" + ec_valid=True + if (len(e)!=64): + ec_valid=False + else: + + for i in range(len(e)>>1): + if (i>0): + txt+="," + txts="0x"+e[i*2:i*2+2] + try: + int(txts,16) + except: + ec_valid=False + txt+=txts + if (not ec_valid): + txt = "0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0" + print("Invalid AES256 encryption key, not 64 bits hex: "+e) + +f = open("script_encryption_key.cpp", "wb") +f.write("#include \"globals.h\"\nuint8_t script_encryption_key[32]={" + txt + "};\n") +f.close() + env.add_source_files(env.core_sources,"*.cpp") + Export('env') import make_binders diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp index 960cdbac20..8d6662157d 100644 --- a/core/bind/core_bind.cpp +++ b/core/bind/core_bind.cpp @@ -1418,7 +1418,7 @@ String _Marshalls::variant_to_base64(const Variant& p_var) { err = encode_variant(p_var,&w[0],len); ERR_FAIL_COND_V( err != OK, "" ); - int b64len = len / 3 * 4 + 4; + int b64len = len / 3 * 4 + 4 + 1; DVector b64buff; b64buff.resize(b64len); DVector::Write w64 = b64buff.write(); @@ -1437,7 +1437,7 @@ Variant _Marshalls::base64_to_variant(const String& p_str) { CharString cstr = p_str.ascii(); DVector buf; - buf.resize(strlen / 4 * 3); + buf.resize(strlen / 4 * 3 + 1); DVector::Write w = buf.write(); int len = base64_decode((char*)(&w[0]), (char*)cstr.get_data(), strlen); diff --git a/core/image.cpp b/core/image.cpp index db20862af5..b577117f1e 100644 --- a/core/image.cpp +++ b/core/image.cpp @@ -1399,14 +1399,17 @@ int Image::get_format_pallete_size(Format p_format) { } -void Image::decompress() { +Error Image::decompress() { if (format>=FORMAT_BC1 && format<=FORMAT_BC5 && _image_decompress_bc) _image_decompress_bc(this); - if (format>=FORMAT_PVRTC2 && format<=FORMAT_PVRTC4_ALPHA && _image_decompress_pvrtc) + else if (format>=FORMAT_PVRTC2 && format<=FORMAT_PVRTC4_ALPHA && _image_decompress_pvrtc) _image_decompress_pvrtc(this); - if (format==FORMAT_ETC && _image_decompress_etc) + else if (format==FORMAT_ETC && _image_decompress_etc) _image_decompress_etc(this); + else + return ERR_UNAVAILABLE; + return OK; } diff --git a/core/image.h b/core/image.h index 99300fc3af..87f851959c 100644 --- a/core/image.h +++ b/core/image.h @@ -45,8 +45,8 @@ class Image { enum { - MAX_WIDTH=4096, // force a limit somehow - MAX_HEIGHT=4096 // force a limit somehow + MAX_WIDTH=16384, // force a limit somehow + MAX_HEIGHT=16384// force a limit somehow }; public: @@ -317,7 +317,7 @@ public: Error compress(CompressMode p_mode=COMPRESS_BC); Image compressed(int p_mode); /* from the Image::CompressMode enum */ - void decompress(); + Error decompress(); void fix_alpha_edges(); void premultiply_alpha(); diff --git a/core/io/resource_format_xml.cpp b/core/io/resource_format_xml.cpp index f3c0f1cb8b..dae95097d3 100644 --- a/core/io/resource_format_xml.cpp +++ b/core/io/resource_format_xml.cpp @@ -193,7 +193,9 @@ Error ResourceInteractiveLoaderXML::close_tag(const String& p_name) { void ResourceInteractiveLoaderXML::unquote(String& p_str) { - p_str=p_str.strip_edges(); + p_str=p_str.strip_edges().replace("\"","").xml_unescape(); + + /*p_str=p_str.strip_edges(); p_str=p_str.replace("\"",""); p_str=p_str.replace(">","<"); p_str=p_str.replace("<",">"); @@ -205,7 +207,7 @@ void ResourceInteractiveLoaderXML::unquote(String& p_str) { p_str=p_str.replace("&#"+String::num(i)+";",chr); } p_str=p_str.replace("&","&"); - +*/ //p_str.parse_utf8( p_str.ascii(true).get_data() ); } @@ -652,11 +654,14 @@ Error ResourceInteractiveLoaderXML::parse_property(Variant& r_v, String &r_name) while( idx>1]=byte; + //printf("%x\n",int(byte)); } else { byte=HEX2CHR(c)<<4; diff --git a/core/io/resource_format_xml.h b/core/io/resource_format_xml.h index 7874431a38..cfa4744915 100644 --- a/core/io/resource_format_xml.h +++ b/core/io/resource_format_xml.h @@ -68,7 +68,7 @@ friend class ResourceFormatLoaderXML; List resource_cache; Tag* parse_tag(bool* r_exit=NULL,bool p_printerr=true); Error close_tag(const String& p_name); - void unquote(String& p_str); + _FORCE_INLINE_ void unquote(String& p_str); Error goto_end_of_tag(); Error parse_property_data(String &r_data); Error parse_property(Variant& r_v, String &r_name); diff --git a/core/math/aabb.cpp b/core/math/aabb.cpp index 0d454cd07d..576e4fa928 100644 --- a/core/math/aabb.cpp +++ b/core/math/aabb.cpp @@ -335,15 +335,6 @@ AABB AABB::grow(real_t p_by) const { aabb.grow_by(p_by); return aabb; } -void AABB::grow_by(real_t p_amount) { - - pos.x-=p_amount; - pos.y-=p_amount; - pos.z-=p_amount; - size.x+=2.0*p_amount; - size.y+=2.0*p_amount; - size.z+=2.0*p_amount; -} void AABB::get_edge(int p_edge,Vector3& r_from,Vector3& r_to) const { diff --git a/core/math/aabb.h b/core/math/aabb.h index 87be03cf16..089d5d15f7 100644 --- a/core/math/aabb.h +++ b/core/math/aabb.h @@ -73,6 +73,8 @@ public: AABB intersection(const AABB& p_aabb) const; ///get box where two intersect, empty if no intersection occurs bool intersects_segment(const Vector3& p_from, const Vector3& p_to,Vector3* r_clip=NULL,Vector3* r_normal=NULL) const; bool intersects_ray(const Vector3& p_from, const Vector3& p_dir,Vector3* r_clip=NULL,Vector3* r_normal=NULL) const; + _FORCE_INLINE_ bool smits_intersect_ray(const Vector3 &from,const Vector3& p_dir, float t0, float t1) const; + _FORCE_INLINE_ bool intersects_convex_shape(const Plane *p_plane, int p_plane_count) const; bool intersects_plane(const Plane &p_plane) const; @@ -89,7 +91,7 @@ public: _FORCE_INLINE_ real_t get_shortest_axis_size() const; AABB grow(real_t p_by) const; - void grow_by(real_t p_amount); + _FORCE_INLINE_ void grow_by(real_t p_amount); void get_edge(int p_edge,Vector3& r_from,Vector3& r_to) const; _FORCE_INLINE_ Vector3 get_endpoint(int p_point) const; @@ -314,6 +316,63 @@ inline real_t AABB::get_shortest_axis_size() const { return max_size; } +bool AABB::smits_intersect_ray(const Vector3 &from,const Vector3& dir, float t0, float t1) const { + + float divx=1.0/dir.x; + float divy=1.0/dir.y; + float divz=1.0/dir.z; + + Vector3 upbound=pos+size; + float tmin, tmax, tymin, tymax, tzmin, tzmax; + if (dir.x >= 0) { + tmin = (pos.x - from.x) * divx; + tmax = (upbound.x - from.x) * divx; + } + else { + tmin = (upbound.x - from.x) * divx; + tmax = (pos.x - from.x) * divx; + } + if (dir.y >= 0) { + tymin = (pos.y - from.y) * divy; + tymax = (upbound.y - from.y) * divy; + } + else { + tymin = (upbound.y - from.y) * divy; + tymax = (pos.y - from.y) * divy; + } + if ( (tmin > tymax) || (tymin > tmax) ) + return false; + if (tymin > tmin) + tmin = tymin; + if (tymax < tmax) + tmax = tymax; + if (dir.z >= 0) { + tzmin = (pos.z - from.z) * divz; + tzmax = (upbound.z - from.z) * divz; + } + else { + tzmin = (upbound.z - from.z) * divz; + tzmax = (pos.z - from.z) * divz; + } + if ( (tmin > tzmax) || (tzmin > tmax) ) + return false; + if (tzmin > tmin) + tmin = tzmin; + if (tzmax < tmax) + tmax = tzmax; + return ( (tmin < t1) && (tmax > t0) ); +} + +void AABB::grow_by(real_t p_amount) { + + pos.x-=p_amount; + pos.y-=p_amount; + pos.z-=p_amount; + size.x+=2.0*p_amount; + size.y+=2.0*p_amount; + size.z+=2.0*p_amount; +} + typedef AABB Rect3; #endif // AABB_H diff --git a/core/math/face3.cpp b/core/math/face3.cpp index 9cdf31ed84..814f2d675d 100644 --- a/core/math/face3.cpp +++ b/core/math/face3.cpp @@ -247,7 +247,7 @@ bool Face3::intersects_aabb(const AABB& p_aabb) const { p_aabb.get_edge(i,from,to); Vector3 e1=from-to; for (int j=0;j<3;j++) { - Vector3 e2=edge_norms[i]; + Vector3 e2=edge_norms[j]; Vector3 axis=vec3_cross( e1, e2 ); diff --git a/core/math/face3.h b/core/math/face3.h index 3a62f7f812..630c408de3 100644 --- a/core/math/face3.h +++ b/core/math/face3.h @@ -86,6 +86,7 @@ public: } bool intersects_aabb(const AABB& p_aabb) const; + _FORCE_INLINE_ bool intersects_aabb2(const AABB& p_aabb) const; operator String() const; inline Face3() {} @@ -94,4 +95,172 @@ public: }; +bool Face3::intersects_aabb2(const AABB& p_aabb) const { + + Vector3 perp = (vertex[0]-vertex[2]).cross(vertex[0]-vertex[1]); + + Vector3 half_extents = p_aabb.size * 0.5; + Vector3 ofs = p_aabb.pos + half_extents; + + Vector3 sup =Vector3( + (perp.x>0) ? -half_extents.x : half_extents.x, + (perp.y>0) ? -half_extents.y : half_extents.y, + (perp.z>0) ? -half_extents.z : half_extents.z + ); + + float d = perp.dot(vertex[0]); + float dist_a = perp.dot(ofs+sup)-d; + float dist_b = perp.dot(ofs-sup)-d; + + if (dist_a*dist_b > 0) + return false; //does not intersect the plane + + +#define TEST_AXIS(m_ax)\ + {\ + float aabb_min=p_aabb.pos.m_ax;\ + float aabb_max=p_aabb.pos.m_ax+p_aabb.size.m_ax;\ + float tri_min,tri_max;\ + for (int i=0;i<3;i++) {\ + if (i==0 || vertex[i].m_ax > tri_max)\ + tri_max=vertex[i].m_ax;\ + if (i==0 || vertex[i].m_ax < tri_min)\ + tri_min=vertex[i].m_ax;\ + }\ +\ + if (tri_max0) ? -half_extents.x : half_extents.x, + (axis.y>0) ? -half_extents.y : half_extents.y, + (axis.z>0) ? -half_extents.z : half_extents.z + ); + + float maxB = axis.dot(ofs+sup2); + float minB = axis.dot(ofs-sup2); + if (minB>maxB) { + SWAP(maxB,minB); + } + + float minT=1e20,maxT=-1e20; + for (int k=0;k<3;k++) { + + float d=axis.dot(vertex[k]); + + if (d > maxT) + maxT=d; + + if (d < minT) + minT=d; + } + + if (maxB::Read rd=data.read(); + const uint8_t *r=&rd[p_ofs]; + uint32_t type = decode_uint32(r); + + return type; +}; + int PackedDataContainer::_size(uint32_t p_ofs) const { DVector::Read rd=data.read(); @@ -408,6 +419,10 @@ Variant PackedDataContainerRef::_iter_get(const Variant& p_iter){ return from->_iter_get_ofs(p_iter,offset); } +bool PackedDataContainerRef::_is_dictionary() const { + + return from->_type_at_ofs(offset) == PackedDataContainer::TYPE_DICT; +}; void PackedDataContainerRef::_bind_methods() { @@ -415,6 +430,7 @@ void PackedDataContainerRef::_bind_methods() { ObjectTypeDB::bind_method(_MD("_iter_init"),&PackedDataContainerRef::_iter_init); ObjectTypeDB::bind_method(_MD("_iter_get"),&PackedDataContainerRef::_iter_get); ObjectTypeDB::bind_method(_MD("_iter_next"),&PackedDataContainerRef::_iter_next); + ObjectTypeDB::bind_method(_MD("_is_dictionary"),&PackedDataContainerRef::_is_dictionary); } diff --git a/core/packed_data_container.h b/core/packed_data_container.h index dcbac447ba..b223d3bcfe 100644 --- a/core/packed_data_container.h +++ b/core/packed_data_container.h @@ -68,6 +68,7 @@ class PackedDataContainer : public Resource { friend class PackedDataContainerRef; Variant _key_at_ofs(uint32_t p_ofs,const Variant& p_key,bool &err) const; Variant _get_at_ofs(uint32_t p_ofs, const uint8_t *p_buf, bool &err) const; + uint32_t _type_at_ofs(uint32_t p_ofs) const; int _size(uint32_t p_ofs) const; protected: @@ -100,6 +101,7 @@ public: Variant _iter_init(const Array& p_iter); Variant _iter_next(const Array& p_iter); Variant _iter_get(const Variant& p_iter); + bool _is_dictionary() const; int size() const; virtual Variant getvar(const Variant& p_key, bool *r_valid=NULL) const; diff --git a/core/script_language.cpp b/core/script_language.cpp index 58d8bcf8ee..031fcb0c4c 100644 --- a/core/script_language.cpp +++ b/core/script_language.cpp @@ -229,8 +229,6 @@ ScriptDebugger::ScriptDebugger() { } - - bool PlaceHolderScriptInstance::set(const StringName& p_name, const Variant& p_value) { if (values.has(p_name)) { diff --git a/core/script_language.h b/core/script_language.h index 560de520ca..8c59a9e6b8 100644 --- a/core/script_language.h +++ b/core/script_language.h @@ -166,6 +166,7 @@ public: virtual ~ScriptLanguage() {}; }; +extern uint8_t script_encryption_key[32]; class PlaceHolderScriptInstance : public ScriptInstance { diff --git a/core/ustring.cpp b/core/ustring.cpp index 188818bc2a..00477e7570 100644 --- a/core/ustring.cpp +++ b/core/ustring.cpp @@ -1596,6 +1596,7 @@ bool String::is_numeric() const { }; #define IS_DIGIT(m_d) ( (m_d)>='0' && (m_d)<='9' ) +#define IS_HEX_DIGIT(m_d) ( ( (m_d)>='0' && (m_d)<='9' ) || ( (m_d)>='a' && (m_d)<='f' ) || ( (m_d)>='A' && (m_d)<='F' ) ) template static double built_in_strtod(const C *string, /* A decimal ASCII floating-point number, @@ -2891,23 +2892,107 @@ String String::xml_escape(bool p_escape_quotes) const { return str; } +static _FORCE_INLINE_ int _xml_unescape(const CharType *p_src,int p_src_len,CharType *p_dst) { + + int len=0; + while(p_src_len) { + + if (*p_src=='&') { + + int eat=0; + + if (p_src_len>=4 && p_src[1]=='#') { + + CharType c=0; + + for(int i=2;i='0' && ct<='9') { + ct=ct-'0'; + } else if (ct>='a' && ct<='f') { + ct=(ct-'a')+10; + } else if (ct>='A' && ct<='F') { + ct=(ct-'A')+10; + } else { + continue; + } + c<<=4; + c|=ct; + } + + if (p_dst) + *p_dst=c; + + } else if (p_src_len>=4 && p_src[1]=='g' && p_src[2]=='t' && p_src[3]==';') { + + if (p_dst) + *p_dst='<'; + eat=4; + } else if (p_src_len>=4 && p_src[1]=='l' && p_src[2]=='t' && p_src[3]==';') { + + if (p_dst) + *p_dst='>'; + eat=4; + } else if (p_src_len>=5 && p_src[1]=='a' && p_src[2]=='m' && p_src[3]=='p' && p_src[4]==';') { + + if (p_dst) + *p_dst='&'; + eat=5; + } else if (p_src_len>=6 && p_src[1]=='q' && p_src[2]=='u' && p_src[3]=='o' && p_src[4]=='t' && p_src[5]==';') { + + if (p_dst) + *p_dst='"'; + eat=6; + } else if (p_src_len>=6 && p_src[1]=='a' && p_src[2]=='p' && p_src[3]=='o' && p_src[4]=='s' && p_src[5]==';') { + + if (p_dst) + *p_dst='\''; + eat=6; + } else { + + if (p_dst) + *p_dst=*p_src; + eat=1; + + } + + if (p_dst) + p_dst++; + + len++; + p_src+=eat; + p_src_len-=eat; + } else { + + if (p_dst) { + *p_dst=*p_src; + p_dst++; + } + len++; + p_src++; + p_src_len--; + } + } + + return len; + +} + String String::xml_unescape() const { - String str=*this; - str=str.strip_edges(); - //str=str.replace("\"",""); - str=str.replace(">","<"); - str=str.replace("<",">"); - str=str.replace("'","'"); - str=str.replace(""","\""); - /* - for (int i=1;i<32;i++) { - - char chr[2]={i,0}; - str=str.replace("&#"+String::num(i)+";",chr); - }*/ - str=str.replace("&","&"); + String str; + int l = length(); + int len = _xml_unescape(c_str(),l,NULL); + if (len==0) + return String(); + str.resize(len+1); + _xml_unescape(c_str(),l,&str[0]); + str[len]=0; return str; } diff --git a/core/variant_op.cpp b/core/variant_op.cpp index 7f46f4c322..1f0f038d77 100644 --- a/core/variant_op.cpp +++ b/core/variant_op.cpp @@ -2907,7 +2907,7 @@ bool Variant::iter_init(Variant& r_iter,bool &valid) const { ref.push_back(r_iter); Variant vref=ref; const Variant *refp[]={&vref}; - Variant ret = _get_obj().obj->call(CoreStringNames::get_singleton()->_iter_next,refp,1,ce); + Variant ret = _get_obj().obj->call(CoreStringNames::get_singleton()->_iter_init,refp,1,ce); if (ref.size()!=1 || ce.error!=Variant::CallError::CALL_OK) { valid=false; diff --git a/demos/3d/platformer/stage2.xml b/demos/3d/platformer/stage2.xml deleted file mode 100644 index 3b9f5957e1..0000000000 --- a/demos/3d/platformer/stage2.xml +++ /dev/null @@ -1,336 +0,0 @@ - - - - - - - - - 4 - 0, 0, 0, 1 - - - 1 - 1 - True - 2 - 0 - 0.5 - False - 1 - 100 - 10 - True - 0.4 - 1 - 0.9 - 0.5 - 0.4 - 8 - 2 - True - 10 - 0, 0.773632, 0.985852, 1 - 0, 0, 0, 1 - 0.965936 - True - False - 1 - 1 - 1.608 - False - 1.414214 - - - - - "names" - - "world" - "Spatial" - "__meta__" - "GridMap" - "theme/theme" - "theme/bake" - "cell/size" - "cell/octant_size" - "cell/center_x" - "cell/center_y" - "cell/center_z" - "cell/scale" - "data" - "DirectionalLight" - "transform/local" - "layers" - "params/energy" - "colors/ambient" - "colors/diffuse" - "colors/specular" - "shadow/shadow" - "shadow/darkening" - "shadow/z_offset" - "shadow/z_slope_scale" - "projector" - "operator" - "shadow/mode" - "shadow/max_distance" - "shadow/split_weight" - "shadow/zoffset_scale" - "environment" - "WorldEnvironment" - "coins" - "Node" - "coin" - "Area" - "coin 2" - "coin 3" - "coin 3 2" - "coin 4" - "coin 4 2" - "coin 4 3" - "coin 3 3" - "coin 5" - "coin 4 4" - "coin 3 4" - "coin 4 4 2" - "coin 6" - "coin 4 5" - "coin 3 5" - "coin 4 5 2" - "coin 4 4 3" - "coin 3 5 2" - "coin 6 2" - "coin 4 5 3" - "coin 7" - "coin 4 6" - "coin 6 3" - "coin 3 5 3" - "coin 4 4 4" - "coin 3 6" - "coin 4 5 4" - "coin 4 5 4 2" - "coin 8" - "coin 4 4 5" - "coin 4 7" - "coin 6 4" - "coin 3 5 4" - "coin 4 5 5" - "coin 3 7" - "coin 4 5 4 3" - "coin 9" - "coin 4 4 6" - "coin 4 8" - "coin 4 5 6" - "coin 3 5 5" - "coin 6 5" - "coin 3 8" - "coin 4 5 4 4" - "enemies" - "enemy" - "RigidBody" - "enemy 2" - "enemy 3" - "enemy 4" - "player" - - "version" - 1 - "conn_count" - 0 - "node_count" - 55 - "variants" - - - "__editor_plugin_states__" - - "2D" - - "pixel_snap" - False - "zoom" - 1 - "ofs" - 1, 1 - - "3D" - - "zfar" - 500 - "fov" - 400 - "viewports" - - - "distance" - 7.724576 - "x_rot" - 0.745795 - "y_rot" - 0.6875 - "use_orthogonal" - False - "use_environment" - False - "pos" - 8.30511, 0.427271, 15.7846 - - - "distance" - 4 - "x_rot" - 0 - "y_rot" - 0 - "use_orthogonal" - False - "use_environment" - False - "pos" - 0, 0, 0 - - - "distance" - 4 - "x_rot" - 0 - "y_rot" - 0 - "use_orthogonal" - False - "use_environment" - False - "pos" - 0, 0, 0 - - - "distance" - 4 - "x_rot" - 0 - "y_rot" - 0 - "use_orthogonal" - False - "use_environment" - False - "pos" - 0, 0, 0 - - - "viewport_mode" - 1 - "default_light" - False - "show_grid" - True - "show_origin" - True - "znear" - 0.1 - - - "__editor_run_settings__" - - "custom_args" - "-l $scene" - "run_mode" - 0 - - "__editor_plugin_screen__" - "3D" - - - False - 2 - 4 - True - 1.001 - - "cells" - 3, 0, 1048584, 12, 0, 1441800, 65539, 0, 1048584, 65548, 0, 1441800, 131075, 0, 1048578, 131084, 0, 1441800, 196611, 0, 1048578, 196620, 0, 1441800, 262147, 0, 1048578, 262156, 0, 1441800, 327683, 0, 1048584, 327692, 0, 1441794, 393219, 0, 1048584, 393228, 0, 1441794, 458752, 0, 655367, 458753, 0, 655367, 458754, 0, 655367, 458755, 0, 655367, 458764, 0, 1441794, 524286, 0, 655367, 524287, 0, 655367, 524300, 0, 1441798, -65533, 0, 1048579, -65532, 0, 1441799, -65531, 0, 1441799, -65530, 0, 1441799, -65529, 0, 1441799, -65528, 0, 1441799, -65527, 0, 1441799, -65526, 0, 1441799, -65525, 0, 1441799, -65524, 0, 1441800, 3, 1, 1048584, 12, 1, 1441800, 29, 1, 8, 30, 1, 8, 31, 1, 8, 65539, 1, 1048584, 65548, 1, 1441800, 65560, 1, 655366, 65561, 1, 655366, 65562, 1, 655366, 65563, 1, 655366, 65564, 1, 655365, 65565, 1, 6, 65566, 1, 6, 65567, 1, 6, 65568, 1, 655366, 65569, 1, 655365, 131075, 1, 1048578, 131084, 1, 1441800, 196611, 1, 1048578, 196620, 1, 1441800, 262147, 1, 1048578, 262156, 1, 1441800, 327683, 1, 1048584, 327692, 1, 1441794, 393219, 1, 1048584, 393228, 1, 1441794, 458752, 1, 655367, 458753, 1, 655367, 458754, 1, 655367, 458755, 1, 655367, 458764, 1, 1441794, 524285, 1, 655367, 524286, 1, 655367, 524287, 1, 655367, 524300, 1, 1441798, -65533, 1, 1048579, -65532, 1, 1441799, -65531, 1, 1441799, -65530, 1, 1441799, -65529, 1, 1441799, -65528, 1, 1441799, -65527, 1, 1441799, -65526, 1, 1441799, -65525, 1, 1441799, -65524, 1, 1441800, -65507, 1, 3, -65506, 1, 3, -65505, 1, 3, 3, 2, 1048584, 5, 2, 1441797, 6, 2, 655365, 8, 2, 1441801, 9, 2, 655368, 10, 2, 655368, 11, 2, 655368, 12, 2, 1441800, 28, 2, 1048584, 32, 2, 9, 65539, 2, 1048584, 65544, 2, 1441797, 65545, 2, 655366, 65546, 2, 655366, 65547, 2, 655366, 65548, 2, 1441800, 65564, 2, 655369, 65568, 2, 5, 65569, 2, 1048583, 65570, 2, 655365, 131075, 2, 1048578, 131084, 2, 1441800, 131100, 2, 655369, 196611, 2, 1048578, 196620, 2, 1441800, 196632, 2, 655366, 196633, 2, 655366, 196634, 2, 655366, 196635, 2, 655366, 196636, 2, 655365, 262147, 2, 1048578, 262156, 2, 1441800, 327683, 2, 1048584, 327692, 2, 1441794, 393219, 2, 1048584, 393228, 2, 1441794, 458752, 2, 655367, 458753, 2, 655367, 458754, 2, 655367, 458755, 2, 655367, 458764, 2, 1441794, 524285, 2, 655367, 524286, 2, 655367, 524287, 2, 655367, 524300, 2, 1441798, -65533, 2, 1048579, -65532, 2, 1048583, -65531, 2, 1441796, -65530, 2, 655364, -65529, 2, 1441799, -65528, 2, 1441796, -65527, 2, 655363, -65526, 2, 655363, -65525, 2, 655363, -65524, 2, 1441800, -65508, 2, 1048579, -65507, 2, 1441799, -65506, 2, 1441799, -65505, 2, 1441799, -65504, 2, 4, 3, 3, 1048584, 5, 3, 5, 6, 3, 1048581, 8, 3, 9, 9, 3, 8, 10, 3, 8, 11, 3, 8, 12, 3, 1441800, 28, 3, 1048585, 33, 3, 9, 65539, 3, 1048584, 65544, 3, 5, 65545, 3, 6, 65546, 3, 6, 65547, 3, 6, 65548, 3, 1441800, 65564, 3, 1048585, 65569, 3, 5, 65570, 3, 1048583, 65571, 3, 655365, 131075, 3, 1048578, 131084, 3, 1441800, 131100, 3, 1048585, 196611, 3, 1048578, 196620, 3, 1441800, 196632, 3, 655363, 196633, 3, 655363, 196634, 3, 655363, 196635, 3, 655364, 196636, 3, 1048581, 262147, 3, 1048578, 262156, 3, 1441800, 262168, 3, 655366, 262169, 3, 655366, 262170, 3, 655366, 262171, 3, 655365, 327683, 3, 1048584, 327692, 3, 1441794, 393219, 3, 1048584, 393228, 3, 1441794, 458752, 3, 655367, 458753, 3, 655366, 458754, 3, 655366, 458755, 3, 655367, 458764, 3, 1441794, 458771, 3, 1048578, 524284, 3, 655367, 524285, 3, 655367, 524286, 3, 655367, 524287, 3, 655367, 524300, 3, 1441798, -65533, 3, 1048579, -65532, 3, 1048583, -65531, 3, 4, -65530, 3, 1048580, -65529, 3, 1441799, -65528, 3, 4, -65527, 3, 3, -65526, 3, 3, -65525, 3, 3, -65524, 3, 1441800, -65508, 3, 1048580, -65507, 3, 1441799, -65506, 3, 1441799, -65505, 3, 1441799, -65504, 3, 1441799, -65503, 3, 4, 3, 4, 1048584, 12, 4, 1441800, 27, 4, 1048584, 34, 4, 1441800, 65539, 4, 1048584, 65548, 4, 1441800, 65563, 4, 1048584, 65570, 4, 1048583, 65571, 4, 1048582, 131075, 4, 1048578, 131084, 4, 9, 131085, 4, 3, 131086, 4, 3, 131087, 4, 3, 131088, 4, 3, 131089, 4, 3, 131090, 4, 3, 131099, 4, 1048584, 196611, 4, 1048578, 196620, 4, 9, 196621, 4, 8, 196622, 4, 8, 196623, 4, 8, 196624, 4, 8, 196625, 4, 8, 196626, 4, 8, 196635, 4, 1048584, 262147, 4, 1048578, 262156, 4, 1441800, 262168, 4, 655363, 262169, 4, 655363, 262170, 4, 655364, 262171, 4, 1048582, 327680, 4, 8, 327681, 4, 8, 327682, 4, 8, 327683, 4, 1048580, 327691, 4, 1441808, 327692, 4, 9, 327693, 4, 3, 327694, 4, 3, 327695, 4, 3, 327696, 4, 3, 327697, 4, 3, 393216, 4, 8, 393217, 4, 8, 393218, 4, 8, 393219, 4, 1048585, 393228, 4, 9, 393229, 4, 2, 393230, 4, 2, 393231, 4, 2, 393232, 4, 2, 393233, 4, 2, 458752, 4, 6, 458753, 4, 6, 458754, 4, 6, 458755, 4, 1048581, 458764, 4, 1441800, 458771, 4, 1048578, 458774, 4, 1048583, 458775, 4, 1048583, 458776, 4, 1048583, 458777, 4, 1048583, 458778, 4, 1048582, 524284, 4, 655367, 524285, 4, 655367, 524286, 4, 655367, 524287, 4, 1048583, 524300, 4, 1441798, 524307, 4, 1048582, -65533, 4, 1048579, -65532, 4, 7, -65531, 4, 7, -65530, 4, 7, -65529, 4, 7, -65528, 4, 1441799, -65527, 4, 1441799, -65526, 4, 1441799, -65525, 4, 1441799, -65524, 4, 1441800, -65509, 4, 1048579, -65508, 4, 1441799, -65507, 4, 1441799, -65506, 4, 1441799, -65505, 4, 1441799, -65504, 4, 1441799, -65503, 4, 1441799, -65502, 4, 1441795, 3, 5, 1048584, 11, 5, 1441801, 27, 5, 1048584, 34, 5, 9, 65538, 5, 3, 65539, 5, 1048580, 65547, 5, 1441801, 65563, 5, 1048584, 65570, 5, 5, 65571, 5, 1048582, 131074, 5, 2, 131075, 5, 1048585, 131083, 5, 1441797, 131084, 5, 7, 131085, 5, 7, 131086, 5, 7, 131087, 5, 7, 131088, 5, 7, 131089, 5, 7, 131090, 5, 7, 131091, 5, 1441795, 131099, 5, 1048584, 196610, 5, 2, 196611, 5, 1048585, 196627, 5, 1441800, 196635, 5, 1048584, 262146, 5, 2, 262147, 5, 1048585, 262156, 5, 1441806, 262157, 5, 1, 262158, 5, 1, 262159, 5, 1, 262160, 5, 1, 262161, 5, 655361, 262162, 5, 655361, 262170, 5, 1048584, 262171, 5, 1048582, 327680, 5, 655366, 327681, 5, 1441798, 327682, 5, 6, 327683, 5, 1048581, 327692, 5, 1441798, 327693, 5, 7, 327694, 5, 7, 327695, 5, 7, 327696, 5, 7, 327697, 5, 1048583, 327698, 5, 1441795, 393215, 5, 1048584, 393234, 5, 1441794, 458751, 5, 1048584, 458764, 5, 1441806, 458765, 5, 655361, 458766, 5, 655361, 458767, 5, 655361, 458768, 5, 655361, 458769, 5, 655361, 458771, 5, 1048578, 458773, 5, 1048583, 458774, 5, 1048583, 458775, 5, 1048583, 458776, 5, 1048583, 458777, 5, 1048583, 458778, 5, 1048582, 524283, 5, 655367, 524284, 5, 655367, 524285, 5, 655367, 524286, 5, 655367, 524287, 5, 1048582, 524300, 5, 1441798, 524301, 5, 1441799, 524302, 5, 1441799, 524303, 5, 1441799, 524304, 5, 1441799, 524305, 5, 1441799, 524306, 5, 1441799, 524307, 5, 1048582, -65533, 5, 1048579, -65532, 5, 7, -65531, 5, 7, -65530, 5, 7, -65529, 5, 1048583, -65528, 5, 1441799, -65527, 5, 1441799, -65526, 5, 1441799, -65525, 5, 1441801, -65509, 5, 1048579, -65508, 5, 1441799, -65507, 5, 1441799, -65506, 5, 1441799, -65505, 5, 1441799, -65504, 5, 1441799, -65503, 5, 1441799, -65502, 5, 4, 2, 6, 655368, 3, 6, 655368, 4, 6, 655369, 11, 6, 1441794, 27, 6, 1048584, 35, 6, 1441800, 65537, 6, 1048579, 65538, 6, 655366, 65539, 6, 655366, 65540, 6, 655365, 65547, 6, 1441794, 65563, 6, 1048584, 65571, 6, 1441798, 131073, 6, 1048584, 131083, 6, 1441798, 131084, 6, 7, 131085, 6, 7, 131086, 6, 7, 131087, 6, 7, 131088, 6, 7, 131089, 6, 7, 131090, 6, 7, 131091, 6, 1441795, 131099, 6, 1048584, 196609, 6, 1048584, 196627, 6, 1441800, 196635, 6, 1048584, 262145, 6, 1048584, 262156, 6, 1441806, 262157, 6, 1, 262158, 6, 1, 262159, 6, 1, 262160, 6, 1, 262161, 6, 655361, 262162, 6, 655361, 262170, 6, 1048584, 262171, 6, 1048582, 327680, 6, 1441799, 327681, 6, 1048582, 327692, 6, 1441798, 327693, 6, 7, 327694, 6, 7, 327695, 6, 7, 327696, 6, 7, 327697, 6, 1048583, 327698, 6, 1441795, 393215, 6, 1048584, 393234, 6, 1441794, 458751, 6, 1048584, 458764, 6, 1441806, 458765, 6, 655361, 458766, 6, 655361, 458767, 6, 655361, 458768, 6, 655361, 458769, 6, 655361, 458771, 6, 1048578, 458773, 6, 1048583, 458774, 6, 1048583, 458775, 6, 1048583, 458776, 6, 1048583, 458777, 6, 1048583, 458778, 6, 1048582, 524283, 6, 655367, 524284, 6, 655367, 524285, 6, 655367, 524286, 6, 655367, 524287, 6, 1048582, 524300, 6, 1441798, 524301, 6, 1441799, 524302, 6, 1441799, 524303, 6, 1441799, 524304, 6, 1441799, 524305, 6, 1441799, 524306, 6, 1441799, 524307, 6, 1048582, -65534, 6, 655363, -65533, 6, 655363, -65532, 6, 655364, -65531, 6, 655367, -65530, 6, 655367, -65529, 6, 1048583, -65528, 6, 7, -65527, 6, 1441799, -65526, 6, 1441799, -65525, 6, 1441795, -65509, 6, 1048579, -65508, 6, 1441799, -65507, 6, 1441799, -65506, 6, 1441799, -65505, 6, 1441799, -65504, 6, 1441799, -65503, 6, 1441799, -65502, 6, 1441799, -65501, 6, 1441800, 4, 7, 1048584, 6, 7, 11, 11, 7, 9, 27, 7, 1048584, 35, 7, 1441800, 65537, 7, 1048579, 65538, 7, 1441799, 65539, 7, 1441799, 65540, 7, 1048582, 65542, 7, 12, 65547, 7, 9, 65563, 7, 1048584, 65571, 7, 1441798, 131073, 7, 1048584, 131078, 7, 1441804, 131083, 7, 5, 131084, 7, 7, 131085, 7, 1441796, 131086, 7, 655363, 131087, 7, 655363, 131088, 7, 655364, 131089, 7, 7, 131090, 7, 7, 131091, 7, 1441795, 131099, 7, 1048584, 196609, 7, 1048584, 196614, 7, 13, 196621, 7, 1441801, 196622, 7, 655362, 196623, 7, 655362, 196624, 7, 655369, 196627, 7, 1441800, 196635, 7, 1048584, 262145, 7, 1048584, 262156, 7, 1441806, 262157, 7, 1441806, 262158, 7, 1, 262159, 7, 1, 262160, 7, 1, 262161, 7, 655361, 262162, 7, 655361, 262170, 7, 1048584, 262171, 7, 1048582, 327680, 7, 1441799, 327681, 7, 1048582, 327691, 7, 1441809, 327692, 7, 1441801, 327693, 7, 655363, 327694, 7, 655363, 327695, 7, 655363, 327696, 7, 655364, 327697, 7, 1048583, 327698, 7, 1441795, 393215, 7, 1048584, 393228, 7, 1441801, 393229, 7, 655368, 393230, 7, 655368, 393231, 7, 655368, 393232, 7, 655369, 393234, 7, 1441794, 458751, 7, 1048584, 458764, 7, 1441800, 458768, 7, 655361, 458769, 7, 655361, 458771, 7, 1048578, 458774, 7, 1048583, 458775, 7, 1048583, 458776, 7, 1048583, 458777, 7, 1048583, 458778, 7, 1048582, 524282, 7, 655367, 524283, 7, 655367, 524284, 7, 655367, 524285, 7, 655367, 524286, 7, 655367, 524287, 7, 1048582, 524300, 7, 1441798, 524301, 7, 1441799, 524302, 7, 1441799, 524303, 7, 1441799, 524304, 7, 1441799, 524305, 7, 1441799, 524306, 7, 1441799, 524307, 7, 1048582, -65532, 7, 1048579, -65531, 7, 1048583, -65530, 7, 10, -65529, 7, 1441799, -65528, 7, 1441799, -65527, 7, 1441799, -65526, 7, 1441799, -65525, 7, 4, -65509, 7, 1048579, -65508, 7, 1441799, -65507, 7, 1441799, -65506, 7, 1441799, -65505, 7, 1441799, -65504, 7, 1441799, -65503, 7, 1441799, -65502, 7, 1441799, -65501, 7, 1441800, 2, 8, 3, 3, 8, 3, 4, 8, 1048585, 12, 8, 1441800, 27, 8, 1048584, 35, 8, 1441800, 65537, 8, 1048579, 65538, 8, 6, 65539, 8, 6, 65540, 8, 1048581, 65548, 8, 1441800, 65563, 8, 1048584, 65571, 8, 1441798, 65572, 8, 655366, 65573, 8, 655366, 65574, 8, 655366, 65575, 8, 655366, 65576, 8, 655366, 65577, 8, 655365, 131073, 8, 1048584, 131084, 8, 1441796, 131088, 8, 1048579, 131089, 8, 7, 131090, 8, 7, 131091, 8, 1441795, 131099, 8, 1048584, 196609, 8, 1048584, 196620, 8, 1441801, 196624, 8, 1048584, 196627, 8, 1441800, 196635, 8, 1048584, 262145, 8, 1048584, 262156, 8, 1441800, 262161, 8, 655361, 262162, 8, 655361, 262170, 8, 1048584, 262171, 8, 1048582, 327680, 8, 1441799, 327681, 8, 1048581, 327692, 8, 1441800, 327695, 8, 3, 327696, 8, 1048580, 327697, 8, 1048583, 327698, 8, 1441795, 393215, 8, 1048584, 393228, 8, 1441800, 393231, 8, 8, 393232, 8, 1048585, 393234, 8, 1441794, 458751, 8, 1048584, 458764, 8, 9, 458769, 8, 655361, 458771, 8, 1048578, 458774, 8, 1048583, 458775, 8, 1048583, 458776, 8, 1048583, 458777, 8, 1048583, 458778, 8, 1048582, 524282, 8, 655367, 524283, 8, 655367, 524284, 8, 655367, 524285, 8, 655367, 524286, 8, 655367, 524287, 8, 1048582, 524300, 8, 5, 524301, 8, 1441799, 524302, 8, 1441799, 524303, 8, 1441799, 524304, 8, 1441799, 524305, 8, 1441799, 524306, 8, 1441799, 524307, 8, 1048582, -65534, 8, 3, -65533, 8, 3, -65532, 8, 1048580, -65531, 8, 655367, -65530, 8, 655367, -65529, 8, 655367, -65528, 8, 1441799, -65527, 8, 1441799, -65526, 8, 1441799, -65525, 8, 655367, -65524, 8, 1441800, -65509, 8, 1048579, -65508, 8, 1441799, -65507, 8, 1441799, -65506, 8, 1441799, -65505, 8, 1441799, -65504, 8, 1441799, -65503, 8, 1441799, -65502, 8, 1441799, -65501, 8, 1441800, 1, 9, 1048578, 2, 9, 5, 3, 9, 1048581, 8, 9, 11, 12, 9, 1441800, 27, 9, 1048584, 35, 9, 1441800, 65537, 9, 1048578, 65544, 9, 12, 65548, 9, 1441800, 65563, 9, 1048584, 65570, 9, 1441809, 65571, 9, 1441801, 65572, 9, 655363, 65573, 9, 655363, 65574, 9, 655363, 65575, 9, 655363, 65576, 9, 655363, 131073, 9, 1048578, 131080, 9, 1048588, 131084, 9, 1441800, 131088, 9, 1048579, 131089, 9, 7, 131090, 9, 7, 131091, 9, 1441795, 131099, 9, 1048584, 131107, 9, 1441797, 131108, 9, 655366, 131109, 9, 655366, 131110, 9, 655366, 131111, 9, 655366, 131112, 9, 655366, 131113, 9, 655365, 196609, 9, 1048578, 196616, 9, 1048588, 196620, 9, 1441800, 196624, 9, 1048584, 196627, 9, 1441800, 196635, 9, 1048584, 262145, 9, 1048578, 262152, 9, 1048589, 262156, 9, 1441800, 262161, 9, 655361, 262162, 9, 655361, 262169, 9, 3, 262170, 9, 1048580, 262171, 9, 1048582, 327680, 9, 655368, 327681, 9, 655369, 327682, 9, 1048592, 327692, 9, 1441800, 327694, 9, 1048579, 327695, 9, 1441799, 327696, 9, 1441799, 327697, 9, 1441799, 327698, 9, 1441795, 327705, 9, 8, 327706, 9, 1048585, 393216, 9, 655368, 393217, 9, 655369, 393228, 9, 1441800, 393230, 9, 1048584, 393234, 9, 1441794, 393241, 9, 8, 393242, 9, 1048585, 458752, 9, 655366, 458753, 9, 655365, 458764, 9, 1441798, 458765, 9, 1441795, 458767, 9, 655361, 458768, 9, 655361, 458769, 9, 655361, 458771, 9, 1048578, 458774, 9, 1048583, 458775, 9, 1048583, 458776, 9, 1048583, 458777, 9, 6, 458778, 9, 1048581, 524282, 9, 655367, 524283, 9, 655367, 524284, 9, 655367, 524285, 9, 655367, 524286, 9, 655367, 524287, 9, 655367, 524301, 9, 1441798, 524302, 9, 1441799, 524303, 9, 1441799, 524304, 9, 1441799, 524305, 9, 1441799, 524306, 9, 1441799, 524307, 9, 1048582, -65535, 9, 1048584, -65534, 9, 4, -65533, 9, 1048580, -65532, 9, 7, -65531, 9, 7, -65530, 9, 7, -65529, 9, 7, -65528, 9, 10, -65527, 9, 1441799, -65526, 9, 1441799, -65525, 9, 655367, -65524, 9, 1441800, -65509, 9, 1048579, -65508, 9, 1441799, -65507, 9, 1441799, -65506, 9, 1441799, -65505, 9, 1441799, -65504, 9, 1441799, -65503, 9, 1441799, -65502, 9, 1441799, -65501, 9, 1441800, 1, 10, 1048578, 12, 10, 1441800, 26, 10, 8, 27, 10, 1048585, 35, 10, 1441800, 65537, 10, 1048578, 65548, 10, 1441800, 65561, 10, 3, 65562, 10, 3, 65563, 10, 1048585, 65571, 10, 1441800, 131073, 10, 1048578, 131084, 10, 1441800, 131088, 10, 1048580, 131089, 10, 1048583, 131090, 10, 1048583, 131091, 10, 4, 131097, 10, 8, 131098, 10, 8, 131099, 10, 1048585, 131106, 10, 1441809, 131107, 10, 1441801, 131108, 10, 655363, 131109, 10, 655363, 131110, 10, 655363, 131111, 10, 655363, 131112, 10, 655364, 131113, 10, 1048582, 196609, 10, 1048578, 196620, 10, 1441800, 196624, 10, 1048585, 196627, 10, 9, 196633, 10, 8, 196634, 10, 8, 196635, 10, 1048585, 196643, 10, 1441797, 196644, 10, 655366, 196645, 10, 655366, 196646, 10, 655366, 196647, 10, 655366, 196648, 10, 655366, 196649, 10, 655365, 262145, 10, 1048578, 262156, 10, 1441800, 262161, 10, 1, 262162, 10, 1, 262168, 10, 1048579, 262169, 10, 6, 262170, 10, 6, 262171, 10, 1048581, 327681, 10, 1048578, 327685, 10, 655377, 327689, 10, 655376, 327692, 10, 1441800, 327694, 10, 1048579, 327695, 10, 1441799, 327696, 10, 1441796, 327697, 10, 655363, 327704, 10, 1048584, 393217, 10, 1048584, 393228, 10, 1441800, 393230, 10, 1048584, 393232, 10, 1441801, 393233, 10, 655362, 393240, 10, 1048584, 458752, 10, 6, 458753, 10, 1048582, 458764, 10, 1441798, 458765, 10, 4, 458766, 10, 3, 458767, 10, 14, 458768, 10, 3, 458769, 10, 8, 458770, 10, 8, 458771, 10, 1048585, 458774, 10, 1048583, 458775, 10, 1048583, 458776, 10, 1048582, 524282, 10, 655367, 524283, 10, 655367, 524284, 10, 655367, 524285, 10, 655367, 524286, 10, 655367, 524287, 10, 655367, 524301, 10, 5, 524302, 10, 6, 524303, 10, 6, 524304, 10, 6, 524305, 10, 6, 524306, 10, 6, 524307, 10, 1048581, -65535, 10, 1048584, -65534, 10, 1048583, -65533, 10, 7, -65532, 10, 7, -65531, 10, 7, -65530, 10, 7, -65529, 10, 7, -65528, 10, 655367, -65527, 10, 655367, -65526, 10, 655367, -65525, 10, 655367, -65524, 10, 1441800, -65511, 10, 3, -65510, 10, 3, -65509, 10, 1048580, -65508, 10, 7, -65507, 10, 7, -65506, 10, 7, -65505, 10, 7, -65504, 10, 7, -65503, 10, 7, -65502, 10, 1441799, -65501, 10, 1441795, 2, 11, 655368, 3, 11, 655368, 4, 11, 655368, 5, 11, 655368, 6, 11, 655368, 7, 11, 655368, 8, 11, 655368, 9, 11, 655368, 10, 11, 655368, 11, 11, 655368, 21, 11, 8, 22, 11, 8, 23, 11, 8, 24, 11, 1048585, 25, 11, 1441801, 26, 11, 655369, 35, 11, 1441800, 65538, 11, 655368, 65539, 11, 655368, 65540, 11, 655368, 65541, 11, 655368, 65542, 11, 655368, 65543, 11, 655368, 65544, 11, 655368, 65545, 11, 655368, 65546, 11, 655368, 65547, 11, 655368, 65549, 11, 8, 65550, 11, 8, 65551, 11, 8, 65552, 11, 8, 65553, 11, 8, 65554, 11, 8, 65555, 11, 8, 65556, 11, 8, 65557, 11, 8, 65558, 11, 8, 65559, 11, 8, 65560, 11, 1048585, 65561, 11, 1441797, 65562, 11, 655365, 65571, 11, 1441800, 131074, 11, 655368, 131075, 11, 655368, 131076, 11, 655368, 131077, 11, 655368, 131078, 11, 655368, 131079, 11, 655368, 131080, 11, 655368, 131081, 11, 655368, 131082, 11, 655368, 131083, 11, 655368, 131085, 11, 8, 131086, 11, 8, 131087, 11, 1048585, 131088, 11, 6, 131089, 11, 6, 131090, 11, 6, 131091, 11, 6, 131092, 11, 9, 131093, 11, 8, 131094, 11, 8, 131095, 11, 8, 131096, 11, 1048585, 131107, 11, 1441800, 196610, 11, 655368, 196611, 11, 655368, 196612, 11, 655368, 196613, 11, 655368, 196614, 11, 655368, 196615, 11, 655368, 196616, 11, 655368, 196617, 11, 655368, 196618, 11, 655368, 196619, 11, 655368, 196621, 11, 8, 196622, 11, 8, 196623, 11, 1048585, 196628, 11, 9, 196629, 11, 8, 196630, 11, 8, 196631, 11, 8, 196632, 11, 1048585, 196642, 11, 1441809, 196643, 11, 1441801, 196644, 11, 655363, 196645, 11, 655363, 196646, 11, 655363, 196647, 11, 655363, 196648, 11, 655364, 196649, 11, 1048582, 262146, 11, 655368, 262147, 11, 655368, 262148, 11, 655368, 262149, 11, 655368, 262150, 11, 655368, 262151, 11, 655368, 262152, 11, 655368, 262153, 11, 655368, 262154, 11, 655368, 262155, 11, 655368, 262157, 11, 8, 262158, 11, 8, 262159, 11, 8, 262160, 11, 14, 262161, 11, 14, 262162, 11, 14, 262163, 11, 14, 262164, 11, 8, 262165, 11, 8, 262166, 11, 8, 262167, 11, 8, 262168, 11, 1048585, 262179, 11, 1441797, 262180, 11, 655366, 262181, 11, 655366, 262182, 11, 655366, 262183, 11, 655366, 262184, 11, 655366, 262185, 11, 655365, 327682, 11, 655362, 327683, 11, 655362, 327684, 11, 655362, 327685, 11, 655369, 327686, 11, 655366, 327687, 11, 655366, 327688, 11, 655366, 327689, 11, 1441801, 327690, 11, 655368, 327691, 11, 655368, 327693, 11, 8, 327694, 11, 1048585, 327695, 11, 6, 327696, 11, 9, 327697, 11, 8, 327698, 11, 8, 327699, 11, 8, 327700, 11, 8, 327701, 11, 8, 327702, 11, 8, 327703, 11, 8, 327704, 11, 1048585, 393218, 11, 655362, 393219, 11, 655362, 393220, 11, 655362, 393221, 11, 655369, 393225, 11, 1441801, 393226, 11, 655368, 393227, 11, 655368, 393229, 11, 8, 393230, 11, 1048585, 393232, 11, 9, 393233, 11, 2, 393234, 11, 2, 393235, 11, 2, 393236, 11, 2, 393237, 11, 8, 393238, 11, 8, 393239, 11, 8, 393240, 11, 1048585, 458752, 11, 655367, 458753, 11, 655367, 458754, 11, 655366, 458755, 11, 655366, 458756, 11, 655366, 458757, 11, 655366, 458761, 11, 1441797, 458762, 11, 655366, 458763, 11, 655366, 458764, 11, 1441799, 458765, 11, 6, 458766, 11, 1048581, 458768, 11, 5, 458769, 11, 6, 458770, 11, 6, 458771, 11, 6, 458772, 11, 6, 458773, 11, 6, 458774, 11, 6, 458775, 11, 6, 458776, 11, 1048581, 524282, 11, 655367, 524283, 11, 655367, 524284, 11, 655367, 524285, 11, 655367, 524286, 11, 655367, 524287, 11, 655367, -65534, 11, 655363, -65533, 11, 655363, -65532, 11, 655363, -65531, 11, 655363, -65530, 11, 655363, -65529, 11, 655363, -65528, 11, 655363, -65527, 11, 655363, -65526, 11, 655363, -65525, 11, 655363, -65512, 11, 1048580, -65511, 11, 1441796, -65510, 11, 655364, -65509, 11, 7, -65508, 11, 7, -65507, 11, 7, -65506, 11, 7, -65505, 11, 7, -65504, 11, 7, -65503, 11, 7, -65502, 11, 7, -65501, 11, 1441795, 21, 12, 15, 23, 12, 1048582, 25, 12, 9, 26, 12, 1048585, 35, 12, 1441800, 65548, 12, 1048584, 65549, 12, 1048583, 65550, 12, 1048583, 65551, 12, 1048583, 65552, 12, 1048583, 65553, 12, 1048583, 65554, 12, 1048583, 65555, 12, 1048583, 65556, 12, 1048583, 65561, 12, 5, 65562, 12, 1048581, 65571, 12, 1441800, 131084, 12, 1048584, 131087, 12, 16, 131092, 12, 17, 131107, 12, 1441800, 196620, 12, 1048584, 196643, 12, 1441800, 262156, 12, 1048584, 262178, 12, 1441809, 262179, 12, 1441801, 262180, 12, 655363, 262181, 12, 655363, 262182, 12, 655363, 262183, 12, 655363, 262184, 12, 655364, 262185, 12, 1048582, 327686, 12, 655363, 327687, 12, 655363, 327688, 12, 655363, 327692, 12, 1048584, 327694, 12, 16, 327696, 12, 17, 327715, 12, 1441797, 327716, 12, 655366, 327717, 12, 655366, 327718, 12, 655366, 327719, 12, 655366, 327720, 12, 655365, 393222, 12, 655368, 393223, 12, 655368, 393224, 12, 655368, 393228, 12, 1048584, 458752, 12, 655367, 458753, 12, 655367, 458754, 12, 655367, 458755, 12, 655367, 458756, 12, 655367, 458757, 12, 655367, 458758, 12, 655366, 458759, 12, 655366, 458760, 12, 655366, 458761, 12, 1441799, 458762, 12, 1441799, 458763, 12, 1441799, 458764, 12, 655366, 524282, 12, 655367, 524283, 12, 655367, 524284, 12, 655367, 524285, 12, 655367, 524286, 12, 655367, 524287, 12, 655367, -65513, 12, 1048579, -65512, 12, 7, -65511, 12, 4, -65510, 12, 1048580, -65509, 12, 7, -65508, 12, 7, -65507, 12, 7, -65506, 12, 7, -65505, 12, 7, -65504, 12, 7, -65503, 12, 7, -65502, 12, 7, -65501, 12, 1441795, 21, 13, 15, 23, 13, 1048582, 28, 13, 1441801, 29, 13, 655369, 35, 13, 1441800, 65548, 13, 1048584, 65549, 13, 1048583, 65550, 13, 1048583, 65551, 13, 1048583, 65552, 13, 1048583, 65553, 13, 1048583, 65554, 13, 1048583, 65555, 13, 1048583, 65556, 13, 1048583, 65564, 13, 1441801, 65565, 13, 655369, 65571, 13, 1441800, 131084, 13, 1048584, 131100, 13, 1441797, 131101, 13, 655365, 131107, 13, 1441800, 196620, 13, 1048584, 196643, 13, 1441800, 262156, 13, 1048584, 262179, 13, 1441800, 327692, 13, 1048584, 327715, 13, 1441798, 393228, 13, 1048584, 458752, 13, 655367, 458753, 13, 655367, 458754, 13, 655367, 458755, 13, 655367, 458756, 13, 655367, 458757, 13, 655367, 458758, 13, 655367, 458759, 13, 655367, 458760, 13, 655367, 458761, 13, 655367, 458762, 13, 1441799, 458763, 13, 1441799, 458764, 13, 655366, 524282, 13, 655367, 524283, 13, 655367, 524284, 13, 655367, 524285, 13, 655367, 524286, 13, 655367, 524287, 13, 655367, -65513, 13, 1048579, -65512, 13, 7, -65511, 13, 7, -65510, 13, 7, -65509, 13, 7, -65508, 13, 1441796, -65507, 13, 655364, -65506, 13, 7, -65505, 13, 7, -65504, 13, 7, -65503, 13, 7, -65502, 13, 7, -65501, 13, 1441795, 21, 14, 15, 23, 14, 1048582, 28, 14, 9, 29, 14, 1048585, 35, 14, 1441800, 65548, 14, 1048584, 65549, 14, 1048583, 65550, 14, 1048583, 65551, 14, 1048583, 65552, 14, 1048583, 65553, 14, 655373, 65554, 14, 655373, 65555, 14, 1048583, 65556, 14, 1048583, 65564, 14, 9, 65565, 14, 1048585, 65571, 14, 1441800, 131084, 14, 1048584, 131090, 14, 655373, 131100, 14, 5, 131101, 14, 1048581, 131107, 14, 1441800, 196620, 14, 1048584, 196643, 14, 1441800, 262156, 14, 1048584, 262179, 14, 1441800, 327692, 14, 1048584, 327715, 14, 1441798, 393228, 14, 1048584, 458752, 14, 655367, 458753, 14, 655367, 458754, 14, 655367, 458755, 14, 655367, 458756, 14, 655367, 458757, 14, 655367, 458758, 14, 655367, 458759, 14, 655367, 458760, 14, 655367, 458761, 14, 655367, 458762, 14, 1441799, 458763, 14, 1441799, 458764, 14, 655366, 524282, 14, 655367, 524283, 14, 655367, 524284, 14, 655367, 524285, 14, 655367, 524286, 14, 655367, 524287, 14, 655367, -65513, 14, 1048579, -65512, 14, 7, -65511, 14, 7, -65510, 14, 7, -65509, 14, 7, -65508, 14, 4, -65507, 14, 1048580, -65506, 14, 7, -65505, 14, 7, -65504, 14, 7, -65503, 14, 7, -65502, 14, 7, -65501, 14, 1441795, 21, 15, 655368, 22, 15, 655368, 23, 15, 655368, 24, 15, 655369, 31, 15, 1441801, 32, 15, 655369, 35, 15, 1441800, 65548, 15, 1048584, 65549, 15, 655368, 65550, 15, 655368, 65551, 15, 655368, 65552, 15, 655368, 65553, 15, 655368, 65554, 15, 655368, 65555, 15, 655368, 65556, 15, 655368, 65557, 15, 655368, 65558, 15, 655368, 65559, 15, 655368, 65560, 15, 655369, 65567, 15, 1441801, 65568, 15, 655369, 65571, 15, 1441800, 131084, 15, 1048584, 131085, 15, 655368, 131086, 15, 655368, 131087, 15, 655368, 131088, 15, 655368, 131089, 15, 655368, 131090, 15, 655368, 131091, 15, 655368, 131092, 15, 655368, 131093, 15, 655368, 131094, 15, 655368, 131095, 15, 655368, 131096, 15, 655369, 131103, 15, 1441801, 131104, 15, 655369, 131107, 15, 1441800, 196620, 15, 1048584, 196621, 15, 655368, 196622, 15, 655368, 196623, 15, 655368, 196624, 15, 655368, 196625, 15, 655368, 196626, 15, 655368, 196627, 15, 655368, 196628, 15, 655368, 196629, 15, 655368, 196630, 15, 655368, 196631, 15, 655368, 196632, 15, 655369, 196639, 15, 1441797, 196640, 15, 655365, 196643, 15, 1441800, 262156, 15, 1048584, 262158, 15, 655368, 262159, 15, 655368, 262160, 15, 655368, 262161, 15, 655368, 262162, 15, 655368, 262163, 15, 655368, 262164, 15, 655368, 262165, 15, 655368, 262166, 15, 655368, 262167, 15, 655368, 262168, 15, 655369, 262179, 15, 1441800, 327692, 15, 1048584, 327693, 15, 655368, 327694, 15, 655368, 327695, 15, 655368, 327696, 15, 655368, 327697, 15, 655368, 327698, 15, 655368, 327699, 15, 655368, 327700, 15, 655366, 327701, 15, 655366, 327702, 15, 655366, 327703, 15, 655366, 327704, 15, 655365, 327715, 15, 1441798, 393228, 15, 1048584, 393229, 15, 655368, 393230, 15, 655368, 393231, 15, 655368, 393232, 15, 655368, 393233, 15, 655368, 393234, 15, 655368, 393235, 15, 655368, 458752, 15, 655367, 458753, 15, 655367, 458754, 15, 655367, 458755, 15, 655367, 458756, 15, 655367, 458757, 15, 655367, 458758, 15, 655367, 458759, 15, 655367, 458760, 15, 655367, 458761, 15, 655367, 458762, 15, 1441799, 458763, 15, 1441799, 458764, 15, 655366, 458765, 15, 655366, 458766, 15, 655366, 458767, 15, 655366, 458768, 15, 655366, 458769, 15, 655366, 458770, 15, 655366, 458771, 15, 655366, 524282, 15, 655367, 524284, 15, 655367, 524285, 15, 655367, 524286, 15, 655367, 524287, 15, 655367, -65512, 15, 655364, -65511, 15, 7, -65510, 15, 7, -65509, 15, 7, -65508, 15, 7, -65507, 15, 7, -65506, 15, 7, -65505, 15, 1441796, -65504, 15, 655364, -65503, 15, 7, -65502, 15, 7, -65501, 15, 1441795, 25, 16, 655369, 31, 16, 9, 32, 16, 1048585, 34, 16, 1441801, 65548, 16, 1048584, 65561, 16, 655369, 65567, 16, 9, 65568, 16, 1048585, 65570, 16, 1441801, 131084, 16, 1048584, 131097, 16, 655369, 131103, 16, 9, 131104, 16, 1048585, 131106, 16, 1441801, 196620, 16, 1048584, 196633, 16, 655369, 196639, 16, 5, 196640, 16, 1048581, 196642, 16, 1441801, 262156, 16, 1048584, 262169, 16, 655369, 262178, 16, 1441801, 327692, 16, 1048584, 327705, 16, 655365, 327714, 16, 1441797, 393228, 16, 1048584, 458752, 16, 655367, 458753, 16, 655367, 458754, 16, 655367, 458755, 16, 655367, 458756, 16, 655367, 458757, 16, 655367, 458758, 16, 655367, 458759, 16, 655367, 458760, 16, 655367, 458761, 16, 655367, 458762, 16, 1441799, 458763, 16, 1441799, 458764, 16, 655366, 524282, 16, 655367, 524284, 16, 655367, 524285, 16, 655367, 524286, 16, 655367, 524287, 16, 655367, -65511, 16, 655364, -65510, 16, 7, -65509, 16, 7, -65508, 16, 7, -65507, 16, 7, -65506, 16, 7, -65505, 16, 4, -65504, 16, 1048580, -65503, 16, 7, -65502, 16, 1441796, 25, 17, 1048584, 34, 17, 1441800, 65548, 17, 1048584, 65561, 17, 1048584, 65570, 17, 1441800, 131084, 17, 1048584, 131097, 17, 1048584, 131106, 17, 1441800, 196633, 17, 1048584, 196642, 17, 1441800, 262169, 17, 1048584, 262174, 17, 655377, 262177, 17, 655376, 262178, 17, 1441800, 327705, 17, 1048582, 327714, 17, 1441798, 458752, 17, 655367, 458753, 17, 655367, 458754, 17, 655367, 458755, 17, 655367, 458756, 17, 655367, 458757, 17, 655367, 458758, 17, 655367, 458759, 17, 655367, 458760, 17, 655367, 458761, 17, 655367, 458762, 17, 1441799, 458763, 17, 1441799, 458764, 17, 1441799, 524282, 17, 655367, 524283, 17, 655367, 524284, 17, 655367, 524285, 17, 655367, 524286, 17, 655367, 524287, 17, 655367, -65511, 17, 1048579, -65510, 17, 7, -65509, 17, 7, -65508, 17, 7, -65507, 17, 7, -65506, 17, 7, -65505, 17, 7, -65504, 17, 7, -65503, 17, 7, -65502, 17, 1441795, 26, 18, 655368, 27, 18, 655368, 28, 18, 655368, 29, 18, 655368, 30, 18, 655368, 31, 18, 655368, 32, 18, 655368, 33, 18, 655368, 65562, 18, 655368, 65563, 18, 655368, 65564, 18, 655368, 65565, 18, 655368, 65566, 18, 655368, 65567, 18, 655368, 65568, 18, 655368, 65569, 18, 655368, 131098, 18, 655368, 131099, 18, 655368, 131100, 18, 655368, 131101, 18, 655368, 131102, 18, 655368, 131103, 18, 655368, 131104, 18, 655368, 131105, 18, 655368, 196634, 18, 655368, 196635, 18, 655368, 196636, 18, 655368, 196637, 18, 655368, 196638, 18, 655368, 196639, 18, 655368, 196640, 18, 655368, 196641, 18, 655368, 262170, 18, 655368, 262171, 18, 655368, 262172, 18, 655368, 262173, 18, 655368, 262174, 18, 655369, 262175, 18, 655366, 262176, 18, 655366, 262177, 18, 1441801, 327706, 18, 655366, 327707, 18, 655366, 327708, 18, 655366, 327709, 18, 655366, 327710, 18, 655366, 327713, 18, 1441797, 458752, 18, 655367, 458753, 18, 655367, 458754, 18, 655367, 458755, 18, 655367, 458756, 18, 655367, 458757, 18, 655367, 458758, 18, 655367, 458759, 18, 655367, 458760, 18, 655367, 458762, 18, 1441799, 458763, 18, 1441799, 458764, 18, 1441799, 524283, 18, 655367, 524284, 18, 655367, 524285, 18, 655367, 524286, 18, 655367, 524287, 18, 655367, -65510, 18, 655363, -65509, 18, 655363, -65508, 18, 655363, -65507, 18, 655363, -65506, 18, 655363, -65505, 18, 655363, -65504, 18, 655363, -65503, 18, 655363, 524287, 19, 655367, 65540, 65533, 3, 131076, 65533, 2, 131077, 65533, 3, 196611, 65533, 1048579, 196612, 65533, 6, 196613, 65533, 6, 196614, 65533, 655366, 196615, 65533, 655366, 196616, 65533, 655366, 196617, 65533, 655366, 196618, 65533, 7, 196619, 65533, 655366, 196620, 65533, 1441801, 262147, 65533, 1048578, 262156, 65533, 1441801, 327683, 65533, 1048584, 327692, 65533, 1441801, 393219, 65533, 1048584, 393228, 65533, 1441801, 458764, 65533, 1441801, 524300, 65533, 1441797, 65539, 65534, 1048579, 65540, 65534, 1048583, 65541, 65534, 4, 131075, 65534, 1048578, 131077, 65534, 5, 131078, 65534, 4, 196611, 65534, 1048578, 196614, 65534, 5, 196615, 65534, 7, 196616, 65534, 655370, 196617, 65534, 7, 196618, 65534, 7, 196619, 65534, 7, 196620, 65534, 1441800, 262147, 65534, 1048578, 262152, 65534, 655372, 262156, 65534, 1441800, 327683, 65534, 1048584, 327688, 65534, 655373, 327692, 65534, 1441794, 393219, 65534, 1048584, 393228, 65534, 1441794, 458753, 65534, 655367, 458754, 65534, 655367, 458764, 65534, 1441794, 524300, 65534, 1441798, 4, 65535, 2, 5, 65535, 2, 6, 65535, 2, 7, 65535, 2, 8, 65535, 2, 9, 65535, 2, 10, 65535, 2, 11, 65535, 2, 65539, 65535, 1048579, 65540, 65535, 5, 65541, 65535, 1048581, 65542, 65535, 4, 65543, 65535, 2, 65544, 65535, 2, 65545, 65535, 2, 65546, 65535, 2, 65547, 65535, 2, 131075, 65535, 1048578, 131078, 65535, 5, 131079, 65535, 9, 131080, 65535, 2, 131081, 65535, 2, 131082, 65535, 2, 131083, 65535, 2, 196611, 65535, 1048578, 196615, 65535, 5, 196616, 65535, 6, 196617, 65535, 6, 196618, 65535, 6, 196619, 65535, 6, 196620, 65535, 1441800, 262147, 65535, 1048578, 262156, 65535, 1441800, 327683, 65535, 1048584, 327692, 65535, 1441794, 393219, 65535, 1048584, 393228, 65535, 1441794, 458752, 65535, 655367, 458753, 65535, 655367, 458754, 65535, 655367, 458755, 65535, 655367, 458764, 65535, 1441794, 524287, 65535, 655367, 524300, 65535, 1441798, -65532, 65535, 2, -65531, 65535, 2, -65530, 65535, 2, -65529, 65535, 2, -65528, 65535, 2, -65527, 65535, 2, -65526, 65535, 2, -65525, 65535, 2 - - - "_editor_clip_" - 0 - "_editor_floor_" - 0, 2, 0 - - 0.522923, 0.663002, -0.535706, -0.24539, 0.718971, 0.650281, 0.816294, -0.20859, 0.53866, 0, 0, 0 - 1 - 1.5 - 0.159092, 0.219774, 0.52093, 1 - 1, 1, 1, 1 - 0 - 0.08 - 0.5 - 0 - 3 - 40 - 0.410558 - - - "_editor_collapsed" - True - - - 1, 0, 0, 0, 1, 0, 0, 0, 1, 18.5311, 2.85075, 5.24675 - 1, 0, 0, 0, 1, 0, 0, 0, 1, 18.5311, 2.85075, 7.24675 - 1, 0, 0, 0, 1, 0, 0, 0, 1, 20.5311, 2.85075, 5.24675 - 1, 0, 0, 0, 1, 0, 0, 0, 1, 20.5311, 2.85075, 7.24675 - 1, 0, 0, 0, 1, 0, 0, 0, 1, 1.61344, 11.28, 11.0239 - 1, 0, 0, 0, 1, 0, 0, 0, 1, 1.61344, 11.28, 13.0239 - 1, 0, 0, 0, 1, 0, 0, 0, 1, 3.61344, 11.28, 11.0239 - 1, 0, 0, 0, 1, 0, 0, 0, 1, 3.61344, 11.28, 13.0239 - 1, 0, 0, 0, 1, 0, 0, 0, 1, 1.61344, 12.9027, 11.03 - 1, 0, 0, 0, 1, 0, 0, 0, 1, 1.61344, 12.9027, 13.03 - 1, 0, 0, 0, 1, 0, 0, 0, 1, 3.61344, 12.9027, 13.03 - 1, 0, 0, 0, 1, 0, 0, 0, 1, 3.61344, 12.9027, 11.03 - 1, 0, 0, 0, 1, 0, 0, 0, 1, 1.61344, 11.28, 15.0922 - 1, 0, 0, 0, 1, 0, 0, 0, 1, 1.61344, 11.28, 17.0922 - 1, 0, 0, 0, 1, 0, 0, 0, 1, 3.61344, 11.28, 17.0922 - 1, 0, 0, 0, 1, 0, 0, 0, 1, 3.61344, 11.28, 15.0922 - 1, 0, 0, 0, 1, 0, 0, 0, 1, 3.61344, 12.9027, 15.0983 - 1, 0, 0, 0, 1, 0, 0, 0, 1, 3.61344, 12.9027, 17.0983 - 1, 0, 0, 0, 1, 0, 0, 0, 1, 1.61344, 12.9027, 15.0983 - 1, 0, 0, 0, 1, 0, 0, 0, 1, 1.61344, 12.9027, 17.0983 - 1, 0, 0, 0, 1, 0, 0, 0, 1, 57.057, 4.14271, 26.9338 - 1, 0, 0, 0, 1, 0, 0, 0, 1, 57.057, 4.14271, 28.9338 - 1, 0, 0, 0, 1, 0, 0, 0, 1, 57.057, 5.76534, 26.9399 - 1, 0, 0, 0, 1, 0, 0, 0, 1, 59.057, 5.76534, 28.9399 - 1, 0, 0, 0, 1, 0, 0, 0, 1, 59.057, 5.76534, 26.9399 - 1, 0, 0, 0, 1, 0, 0, 0, 1, 59.057, 4.14271, 28.9338 - 1, 0, 0, 0, 1, 0, 0, 0, 1, 59.057, 4.14271, 26.9338 - 1, 0, 0, 0, 1, 0, 0, 0, 1, 57.057, 5.76534, 28.9399 - 1, 0, 0, 0, 1, 0, 0, 0, 1, 62.9108, 6.16547, 31.0899 - 1, 0, 0, 0, 1, 0, 0, 0, 1, 64.9108, 7.7881, 31.096 - 1, 0, 0, 0, 1, 0, 0, 0, 1, 62.9108, 6.16547, 33.0899 - 1, 0, 0, 0, 1, 0, 0, 0, 1, 62.9108, 7.7881, 31.096 - 1, 0, 0, 0, 1, 0, 0, 0, 1, 64.9108, 7.7881, 33.096 - 1, 0, 0, 0, 1, 0, 0, 0, 1, 64.9108, 6.16547, 31.0899 - 1, 0, 0, 0, 1, 0, 0, 0, 1, 64.9108, 6.16547, 33.0899 - 1, 0, 0, 0, 1, 0, 0, 0, 1, 62.9108, 7.7881, 33.096 - 1, 0, 0, 0, 1, 0, 0, 0, 1, 51.5614, 2.98252, 23.1775 - 1, 0, 0, 0, 1, 0, 0, 0, 1, 53.5614, 4.60515, 23.1836 - 1, 0, 0, 0, 1, 0, 0, 0, 1, 51.5614, 2.98252, 25.1775 - 1, 0, 0, 0, 1, 0, 0, 0, 1, 53.5614, 2.98252, 23.1775 - 1, 0, 0, 0, 1, 0, 0, 0, 1, 53.5614, 4.60515, 25.1836 - 1, 0, 0, 0, 1, 0, 0, 0, 1, 51.5614, 4.60515, 23.1836 - 1, 0, 0, 0, 1, 0, 0, 0, 1, 53.5614, 2.98252, 25.1775 - 1, 0, 0, 0, 1, 0, 0, 0, 1, 51.5614, 4.60515, 25.1836 - - 1, 0, 0, 0, 1, 0, 0, 0, 1, 18.3062, 5.40827, 5.96938 - 1, 0, 0, 0, 1, 0, 0, 0, 1, 64.1292, 5.40827, 17.1396 - 1, 0, 0, 0, 1, 0, 0, 0, 1, 64.1292, 5.40827, 32.6128 - 1, 0, 0, 0, 1, 0, 0, 0, 1, 55.5702, 5.40827, 32.6128 - - 0.0160676, 0, -0.999871, 0, 1, 0, 0.999871, 0, 0.0160676, 8.50167, 4.15811, 15.9334 - - "nodes" - -1, -1, 1, 0, -1, 1, 2, 0, 0, 0, 0, 3, 3, -1, 10, 4, 1, 5, 2, 6, 3, 7, 4, 8, 5, 9, 5, 10, 5, 11, 6, 12, 7, 2, 8, 0, 0, 0, 13, 13, -1, 16, 14, 9, 15, 10, 16, 11, 17, 12, 18, 13, 19, 13, 20, 5, 21, 14, 22, 15, 23, 16, 24, 17, 25, 18, 26, 19, 27, 20, 28, 21, 29, 3, 0, 0, 0, 31, 30, -1, 1, 30, 22, 0, 0, 0, 33, 32, -1, 1, 2, 23, 0, 4, 0, 35, 34, 24, 1, 14, 25, 0, 4, 0, 35, 36, 24, 1, 14, 26, 0, 4, 0, 35, 37, 24, 1, 14, 27, 0, 4, 0, 35, 38, 24, 1, 14, 28, 0, 4, 0, 35, 39, 24, 1, 14, 29, 0, 4, 0, 35, 40, 24, 1, 14, 30, 0, 4, 0, 35, 41, 24, 1, 14, 31, 0, 4, 0, 35, 42, 24, 1, 14, 32, 0, 4, 0, 35, 43, 24, 1, 14, 33, 0, 4, 0, 35, 44, 24, 1, 14, 34, 0, 4, 0, 35, 45, 24, 1, 14, 35, 0, 4, 0, 35, 46, 24, 1, 14, 36, 0, 4, 0, 35, 47, 24, 1, 14, 37, 0, 4, 0, 35, 48, 24, 1, 14, 38, 0, 4, 0, 35, 49, 24, 1, 14, 39, 0, 4, 0, 35, 50, 24, 1, 14, 40, 0, 4, 0, 35, 51, 24, 1, 14, 41, 0, 4, 0, 35, 52, 24, 1, 14, 42, 0, 4, 0, 35, 53, 24, 1, 14, 43, 0, 4, 0, 35, 54, 24, 1, 14, 44, 0, 4, 0, 35, 55, 24, 1, 14, 45, 0, 4, 0, 35, 56, 24, 1, 14, 46, 0, 4, 0, 35, 57, 24, 1, 14, 47, 0, 4, 0, 35, 58, 24, 1, 14, 48, 0, 4, 0, 35, 59, 24, 1, 14, 49, 0, 4, 0, 35, 60, 24, 1, 14, 50, 0, 4, 0, 35, 61, 24, 1, 14, 51, 0, 4, 0, 35, 62, 24, 1, 14, 52, 0, 4, 0, 35, 63, 24, 1, 14, 53, 0, 4, 0, 35, 64, 24, 1, 14, 54, 0, 4, 0, 35, 65, 24, 1, 14, 55, 0, 4, 0, 35, 66, 24, 1, 14, 56, 0, 4, 0, 35, 67, 24, 1, 14, 57, 0, 4, 0, 35, 68, 24, 1, 14, 58, 0, 4, 0, 35, 69, 24, 1, 14, 59, 0, 4, 0, 35, 70, 24, 1, 14, 60, 0, 4, 0, 35, 71, 24, 1, 14, 61, 0, 4, 0, 35, 72, 24, 1, 14, 62, 0, 4, 0, 35, 73, 24, 1, 14, 63, 0, 4, 0, 35, 74, 24, 1, 14, 64, 0, 4, 0, 35, 75, 24, 1, 14, 65, 0, 4, 0, 35, 76, 24, 1, 14, 66, 0, 4, 0, 35, 77, 24, 1, 14, 67, 0, 4, 0, 35, 78, 24, 1, 14, 68, 0, 0, 0, 33, 79, -1, 0, 0, 49, 0, 81, 80, 69, 1, 14, 70, 0, 49, 0, 81, 82, 69, 1, 14, 71, 0, 49, 0, 81, 83, 69, 1, 14, 72, 0, 49, 0, 81, 84, 69, 1, 14, 73, 0, 0, 0, 81, 85, 74, 1, 14, 75, 0 - "conns" - - - - - \ No newline at end of file diff --git a/demos/3d/platformer/tiles.res b/demos/3d/platformer/tiles.res index 0ab7c92ef66763c970cc744ecfb629c6fc3e2f79..e7e810f23fb1e4803737e24f8898c98dc7a92eae 100644 GIT binary patch delta 15879 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

GdHh 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 - ERR_FAIL_COND(p_width<=0 || p_width>4096); - ERR_FAIL_COND(p_height<=0 || p_height>4096); + ERR_FAIL_COND(p_width<=0 || p_width>16384); + ERR_FAIL_COND(p_height<=0 || p_height>16384); //real texture size is in alloc width and height texture->width=p_width; texture->height=p_height; @@ -5471,6 +5471,7 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans const ParamOverrideMap* prev_overrides=NULL; // make it diferent than NULL const Skeleton *prev_skeleton =NULL; uint8_t prev_sort_flags=0xFF; + const BakedLightData *prev_baked_light=NULL; Geometry::Type prev_geometry_type=Geometry::GEOMETRY_INVALID; @@ -5486,6 +5487,9 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans material_shader.set_conditional(MaterialShaderGLES2::LIGHT_USE_PSSM,false); material_shader.set_conditional(MaterialShaderGLES2::LIGHT_USE_PSSM4,false); material_shader.set_conditional(MaterialShaderGLES2::SHADELESS,false); + material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_OCTREE,false); +// material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_TEXTURE,false); + } @@ -5503,8 +5507,10 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans uint8_t sort_flags= e->sort_flags; const Skeleton *skeleton = e->skeleton; const Geometry *geometry_cmp = e->geometry_cmp; + const BakedLightData *baked_light = e->instance->baked_light; bool rebind=false; + bool bind_baked_light_octree=false; bool additive=false; @@ -5622,6 +5628,32 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans current_blend_mode=desired_blend_mode; } + material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_OCTREE,false); +// material_shader.set_conditional(MaterialShaderGLES2::USE_AMBIENT_TEXTURE,false); + + if (!additive && baked_light) { + + if (baked_light->mode==VS::BAKED_LIGHT_OCTREE && baked_light->octree_texture.is_valid() && e->instance->baked_light_octree_xform) { + material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_OCTREE,true); + bind_baked_light_octree=true; + if (prev_baked_light!=baked_light) { + Texture *tex=texture_owner.get(baked_light->octree_texture); + if (tex) { + + glActiveTexture(GL_TEXTURE5); + glBindTexture(tex->target,tex->tex_id); //bind the texture + } + + } + } else if (baked_light->mode==VS::BAKED_LIGHT_LIGHTMAPS) { + + //material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_TEXTURE,true); + } + } + + if (int(prev_baked_light!=NULL) ^ int(baked_light!=NULL)) { + rebind=true; + } } if (sort_flags!=prev_sort_flags) { @@ -5672,6 +5704,18 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans } } + if (bind_baked_light_octree && (baked_light!=prev_baked_light || rebind)) { + + material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_OCTREE_INVERSE_TRANSFORM, *e->instance->baked_light_octree_xform); + material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_OCTREE_LATTICE_SIZE, baked_light->octree_lattice_size); + material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_OCTREE_LATTICE_DIVIDE, baked_light->octree_lattice_divide); + material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_OCTREE_STEPS, baked_light->octree_steps); + material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_OCTREE_TEX,5); + material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_OCTREE_PIX_SIZE,baked_light->octree_tex_pixel_size); + + + } + _set_cull(e->mirror,p_reverse_cull); @@ -5726,6 +5770,7 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans prev_light=e->light; prev_light_type=e->light_type; prev_sort_flags=sort_flags; + prev_baked_light=baked_light; // prev_geometry_type=geometry->type; } diff --git a/drivers/gles2/shaders/material.glsl b/drivers/gles2/shaders/material.glsl index a919e3b1e2..7ed59ae9cd 100644 --- a/drivers/gles2/shaders/material.glsl +++ b/drivers/gles2/shaders/material.glsl @@ -93,6 +93,13 @@ varying vec3 tangent_interp; varying vec3 binormal_interp; #endif +#ifdef ENABLE_AMBIENT_OCTREE + +uniform highp mat4 ambient_octree_inverse_transform; +varying highp vec3 ambient_octree_coords; + +#endif + #ifdef USE_FOG varying vec4 fog_interp; @@ -173,12 +180,19 @@ void main() { #ifdef USE_UNIFORM_INSTANCING highp mat4 modelview = (camera_inverse_transform * (world_transform * instance_transform)); +#ifdef ENABLE_AMBIENT_OCTREE + highp mat4 ambient_octree_transform = (ambient_octree_inverse_transform * (world_transform * instance_transform)); +#endif + #else #ifdef USE_ATTRIBUTE_INSTANCING highp mat4 minst=mat4(instance_row0,instance_row1,instance_row2,instance_row3); highp mat4 modelview = (camera_inverse_transform * (world_transform * minst)); +#ifdef ENABLE_AMBIENT_OCTREE + highp mat4 ambient_octree_transform = (ambient_octree_inverse_transform * (world_transform * minst)); +#endif #else @@ -201,9 +215,16 @@ void main() { );*/ highp mat4 modelview = (camera_inverse_transform * (world_transform * minst)); +#ifdef ENABLE_AMBIENT_OCTREE + highp mat4 ambient_octree_transform = (ambient_octree_inverse_transform * (world_transform * minst)); +#endif #else highp mat4 modelview = (camera_inverse_transform * world_transform); +#ifdef ENABLE_AMBIENT_OCTREE + highp mat4 ambient_octree_transform = (ambient_octree_inverse_transform * world_transform); +#endif + #endif #endif @@ -233,6 +254,11 @@ void main() { #endif +#ifdef ENABLE_AMBIENT_OCTREE + + ambient_octree_coords = (ambient_octree_transform * vertex_in).xyz; +#endif + vertex_interp = (modelview * vertex_in).xyz; normal_interp = normalize((modelview * vec4(normal_in,0.0)).xyz); @@ -515,6 +541,16 @@ vec3 process_shade(in vec3 normal, in vec3 light_dir, in vec3 eye_vec, in vec3 d uniform float const_light_mult; uniform float time; +#ifdef ENABLE_AMBIENT_OCTREE + +varying highp vec3 ambient_octree_coords; +uniform highp float ambient_octree_lattice_size; +uniform highp vec2 ambient_octree_pix_size; +uniform highp float ambient_octree_lattice_divide; +uniform highp sampler2D ambient_octree_tex; +uniform int ambient_octree_steps; + +#endif FRAGMENT_SHADER_GLOBALS @@ -745,10 +781,57 @@ FRAGMENT_SHADER_CODE } #endif +#ifdef ENABLE_AMBIENT_OCTREE + + vec3 ambientmap_color = vec3(0.0,0.0,0.0); + + + { + + //read position from initial lattice grid + highp vec3 lattice_pos = floor(ambient_octree_coords*ambient_octree_lattice_size); + highp vec2 octant_uv = highp vec2(lattice_pos.x+ambient_octree_lattice_size*lattice_pos.z,lattice_pos.y); + octant_uv=(octant_uv*highp vec2(2.0,4.0)+highp vec2(0.0,4.0)); + highp float ld = 1.0/ambient_octree_lattice_size; + + + //go down the octree + + for(int i=0;i *r_addresses) const { getifaddrs(&ifAddrStruct); for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) { + if (!ifa->ifa_addr) + continue; if (ifa ->ifa_addr->sa_family==AF_INET) { // check it is IP4 // is a valid IP4 Address diff --git a/modules/gdscript/gd_script.cpp b/modules/gdscript/gd_script.cpp index d183782864..2885b754be 100644 --- a/modules/gdscript/gd_script.cpp +++ b/modules/gdscript/gd_script.cpp @@ -31,6 +31,7 @@ #include "global_constants.h" #include "gd_compiler.h" #include "os/file_access.h" +#include "io/file_access_encrypted.h" /* TODO: @@ -1591,7 +1592,28 @@ void GDScript::_bind_methods() { Error GDScript::load_byte_code(const String& p_path) { - Vector bytecode = FileAccess::get_file_as_array(p_path); + Vector bytecode; + + if (p_path.ends_with("gde")) { + + FileAccess *fa = FileAccess::open(p_path,FileAccess::READ); + ERR_FAIL_COND_V(!fa,ERR_CANT_OPEN); + FileAccessEncrypted *fae = memnew( FileAccessEncrypted ); + ERR_FAIL_COND_V(!fae,ERR_CANT_OPEN); + Vector key; + key.resize(32); + for(int i=0;iopen_and_parse(fa,key,FileAccessEncrypted::MODE_READ); + ERR_FAIL_COND_V(err,err); + bytecode.resize(fae->get_len()); + fae->get_buffer(bytecode.ptr(),bytecode.size()); + memdelete(fae); + } else { + + bytecode = FileAccess::get_file_as_array(p_path); + } ERR_FAIL_COND_V(bytecode.size()==0,ERR_PARSE_ERROR); path=p_path; @@ -2225,7 +2247,7 @@ RES ResourceFormatLoaderGDScript::load(const String &p_path,const String& p_orig Ref scriptres(script); - if (p_path.ends_with(".gdc")) { + if (p_path.ends_with(".gde") || p_path.ends_with(".gdc")) { script->set_script_path(p_original_path); // script needs this. script->set_path(p_original_path); @@ -2258,6 +2280,7 @@ void ResourceFormatLoaderGDScript::get_recognized_extensions(List *p_ext p_extensions->push_back("gd"); p_extensions->push_back("gdc"); + p_extensions->push_back("gde"); } bool ResourceFormatLoaderGDScript::handles_type(const String& p_type) const { @@ -2268,7 +2291,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(); - if (el=="gd" || el=="gdc") + if (el=="gd" || el=="gdc" || el=="gde") return "GDScript"; return ""; } diff --git a/modules/gdscript/gd_tokenizer.cpp b/modules/gdscript/gd_tokenizer.cpp index aeee1f6667..a92e2f22ea 100644 --- a/modules/gdscript/gd_tokenizer.cpp +++ b/modules/gdscript/gd_tokenizer.cpp @@ -757,6 +757,7 @@ void GDTokenizerText::_advance() { {Variant::_RID,"RID"}, {Variant::OBJECT,"Object"}, {Variant::INPUT_EVENT,"InputEvent"}, + {Variant::NODE_PATH,"NodePath"}, {Variant::DICTIONARY,"dict"}, {Variant::DICTIONARY,"Dictionary"}, {Variant::ARRAY,"Array"}, diff --git a/modules/gdscript/register_types.cpp b/modules/gdscript/register_types.cpp index 6bcd12857b..abb3d5a946 100644 --- a/modules/gdscript/register_types.cpp +++ b/modules/gdscript/register_types.cpp @@ -14,6 +14,8 @@ #include "gd_script.h" #include "io/resource_loader.h" #include "os/file_access.h" +#include "io/file_access_encrypted.h" + GDScriptLanguage *script_language_gd=NULL; @@ -25,6 +27,7 @@ ResourceFormatSaverGDScript *resource_saver_gd=NULL; #include "tools/editor/editor_import_export.h" #include "gd_tokenizer.h" #include "tools/editor/editor_node.h" +#include "tools/editor/editor_settings.h" class EditorExportGDScript : public EditorExportPlugin { @@ -34,20 +37,69 @@ public: virtual Vector custom_export(String& p_path,const Ref &p_platform) { //compile gdscript to bytecode - if (p_path.ends_with(".gd")) { - Vector file = FileAccess::get_file_as_array(p_path); - if (file.empty()) - return file; - String txt; - txt.parse_utf8((const char*)file.ptr(),file.size()); - file = GDTokenizerBuffer::parse_code_string(txt); - if (!file.empty()) { - print_line("PREV: "+p_path); - p_path=p_path.basename()+".gdc"; - print_line("NOW: "+p_path); - return file; - } + if (EditorImportExport::get_singleton()->script_get_action()!=EditorImportExport::SCRIPT_ACTION_NONE) { + + if (p_path.ends_with(".gd")) { + Vector file = FileAccess::get_file_as_array(p_path); + if (file.empty()) + return file; + String txt; + txt.parse_utf8((const char*)file.ptr(),file.size()); + file = GDTokenizerBuffer::parse_code_string(txt); + + if (!file.empty()) { + + if (EditorImportExport::get_singleton()->script_get_action()==EditorImportExport::SCRIPT_ACTION_ENCRYPT) { + + String tmp_path=EditorSettings::get_singleton()->get_settings_path().plus_file("tmp/script.gde"); + FileAccess *fa = FileAccess::open(tmp_path,FileAccess::WRITE); + String skey=EditorImportExport::get_singleton()->script_get_encryption_key().to_lower(); + Vector key; + key.resize(32); + for(int i=0;i<32;i++) { + int v=0; + if (i*2='0' && ct<='9') + ct=ct-'0'; + else if (ct>='a' && ct<='f') + ct=10+ct-'a'; + v|=ct<<4; + } + + if (i*2+1='0' && ct<='9') + ct=ct-'0'; + else if (ct>='a' && ct<='f') + ct=10+ct-'a'; + v|=ct; + } + key[i]=v; + } + FileAccessEncrypted *fae=memnew(FileAccessEncrypted); + Error err = fae->open_and_parse(fa,key,FileAccessEncrypted::MODE_WRITE_AES256); + if (err==OK) { + + fae->store_buffer(file.ptr(),file.size()); + p_path=p_path.basename()+".gde"; + } + + memdelete(fae); + + file=FileAccess::get_file_as_array(tmp_path); + return file; + + + } else { + + p_path=p_path.basename()+".gdc"; + return file; + } + } + + } } return Vector(); diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp index 7ccd85702d..d258e26a0e 100644 --- a/modules/gridmap/grid_map.cpp +++ b/modules/gridmap/grid_map.cpp @@ -31,7 +31,9 @@ #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" bool GridMap::_set(const StringName& p_name, const Variant& p_value) { @@ -53,6 +55,8 @@ bool GridMap::_set(const StringName& p_name, const Variant& p_value) { set_center_z(p_value); } 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") { @@ -120,6 +124,7 @@ bool GridMap::_set(const StringName& p_name, const Variant& p_value) { 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()); } } @@ -169,6 +174,8 @@ bool GridMap::_get(const StringName& p_name,Variant &r_ret) const { r_ret= get_center_z(); } 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") { @@ -231,6 +238,7 @@ void GridMap::_get_property_list( List *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") ); @@ -428,6 +436,8 @@ void GridMap::set_cell_item(int p_x,int p_y,int p_z, int p_item,int p_rot){ 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 @@ -863,6 +873,12 @@ void GridMap::_notification(int p_what) { awaiting_update=false; last_transform=get_global_transform(); + + if (use_baked_light) { + + _find_baked_light(); + } + } break; case NOTIFICATION_TRANSFORM_CHANGED: { @@ -883,6 +899,17 @@ 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(); //_update_area_instances(); @@ -1028,6 +1055,14 @@ void GridMap::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_unused_area_id","area"),&GridMap::get_unused_area_id); ObjectTypeDB::bind_method(_MD("bake_geometry"),&GridMap::bake_geometry); + 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); + + ObjectTypeDB::bind_method(_MD("_get_baked_light_meshes"),&GridMap::_get_baked_light_meshes); + + + ObjectTypeDB::set_method_flags("GridMap","bake_geometry",METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR); ObjectTypeDB::bind_method(_MD("clear"),&GridMap::clear); @@ -1496,6 +1531,108 @@ void GridMap::bake_geometry() { } +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::Element *E=octant_map.front();E;E=E->next()) { + + for(Map::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(); + 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() { + + if (theme.is_null()) + return Array(); + + Vector3 ofs(cell_size*0.5*int(center_x),cell_size*0.5*int(center_y),cell_size*0.5*int(center_z)); + Array meshes; + + for (Map::Element *E=cell_map.front();E;E=E->next()) { + + + int id = E->get().item; + if (!theme->has_item(id)) + continue; + Ref mesh=theme->get_item_mesh(id); + if (mesh.is_null()) + continue; + + IndexKey ik=E->key(); + + Vector3 cellpos = Vector3(ik.x,ik.y,ik.z ); + + Transform xform; + + xform.basis.set_orthogonal_index(E->get().rot); + + + xform.set_origin( cellpos*cell_size+ofs); + xform.basis.scale(Vector3(cell_scale,cell_scale,cell_scale)); + + meshes.push_back(xform); + meshes.push_back(mesh); + + } + + 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; +} GridMap::GridMap() { @@ -1516,7 +1653,8 @@ GridMap::GridMap() { bake=false; cell_scale=1.0; - + baked_light_instance=NULL; + use_baked_light=false; } diff --git a/modules/gridmap/grid_map.h b/modules/gridmap/grid_map.h index 7a13ace143..df805d99fa 100644 --- a/modules/gridmap/grid_map.h +++ b/modules/gridmap/grid_map.h @@ -38,6 +38,8 @@ //should scale better with hardware that supports instancing +class BakedLightInstance; + class GridMap : public Spatial { @@ -202,6 +204,14 @@ 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); @@ -211,6 +221,7 @@ protected: void _notification(int p_what); static void _bind_methods(); + public: enum { @@ -262,6 +273,8 @@ public: void bake_geometry(); + void set_use_baked_light(bool p_use); + bool is_using_baked_light() const; void clear(); GridMap(); diff --git a/platform/javascript/detect.py b/platform/javascript/detect.py index da92c0869b..e4cdaad313 100644 --- a/platform/javascript/detect.py +++ b/platform/javascript/detect.py @@ -30,7 +30,7 @@ def get_flags(): ('theora', 'no'), ('tools', 'no'), ('nedmalloc', 'no'), - ('vorbis', 'yes'), + ('vorbis', 'no'), ('musepack', 'no'), ('squirrel', 'no'), ('squish', 'no'), diff --git a/scene/3d/baked_light.cpp b/scene/3d/baked_light.cpp deleted file mode 100644 index 55832b7c18..0000000000 --- a/scene/3d/baked_light.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include "baked_light.h" -#include "mesh_instance.h" - -BakedLight::BakedLight() { - - -} diff --git a/scene/3d/baked_light.h b/scene/3d/baked_light.h deleted file mode 100644 index a6f997afe9..0000000000 --- a/scene/3d/baked_light.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef BAKED_LIGHT_H -#define BAKED_LIGHT_H - -#include "scene/3d/spatial.h" -class BakedLightBaker; - - -class BakedLight : public Spatial { - OBJ_TYPE(BakedLight,Spatial); - -public: - BakedLight(); -}; - -#endif // BAKED_LIGHT_H diff --git a/scene/3d/baked_light_instance.cpp b/scene/3d/baked_light_instance.cpp new file mode 100644 index 0000000000..c1cc1f6b68 --- /dev/null +++ b/scene/3d/baked_light_instance.cpp @@ -0,0 +1,65 @@ +#include "baked_light_instance.h" +#include "scene/scene_string_names.h" + + +RID BakedLightInstance::get_baked_light_instance() const { + + if (baked_light.is_null()) + return RID(); + else + return get_instance(); + +} + +void BakedLightInstance::set_baked_light(const Ref& p_baked_light) { + + baked_light=p_baked_light; + + RID base_rid; + + if (baked_light.is_valid()) + base_rid=baked_light->get_rid(); + else + base_rid=RID(); + + set_base(base_rid); + + if (is_inside_world()) { + + emit_signal(SceneStringNames::get_singleton()->baked_light_changed); + +// for (List::Element *E=baked_geometry.front();E;E=E->next()) { +// VS::get_singleton()->instance_geometry_set_baked_light(E->get()->get_instance(),baked_light.is_valid()?get_instance():RID()); +// } + } +} + +Ref BakedLightInstance::get_baked_light() const{ + + return baked_light; +} + +AABB BakedLightInstance::get_aabb() const { + + return AABB(Vector3(0,0,0),Vector3(1,1,1)); +} +DVector BakedLightInstance::get_faces(uint32_t p_usage_flags) const { + + return DVector(); +} + + +void BakedLightInstance::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_baked_light","baked_light"),&BakedLightInstance::set_baked_light); + ObjectTypeDB::bind_method(_MD("get_baked_light"),&BakedLightInstance::get_baked_light); + ObjectTypeDB::bind_method(_MD("get_baked_light_instance"),&BakedLightInstance::get_baked_light_instance); + + ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"baked_light",PROPERTY_HINT_RESOURCE_TYPE,"BakedLight"),_SCS("set_baked_light"),_SCS("get_baked_light")); + ADD_SIGNAL( MethodInfo("baked_light_changed")); +} + +BakedLightInstance::BakedLightInstance() { + + +} diff --git a/scene/3d/baked_light_instance.h b/scene/3d/baked_light_instance.h new file mode 100644 index 0000000000..b904ced9a7 --- /dev/null +++ b/scene/3d/baked_light_instance.h @@ -0,0 +1,33 @@ +#ifndef BAKED_LIGHT_INSTANCE_H +#define BAKED_LIGHT_INSTANCE_H + +#include "scene/3d/visual_instance.h" +#include "scene/resources/baked_light.h" + +class BakedLightBaker; + + +class BakedLightInstance : public VisualInstance { + OBJ_TYPE(BakedLightInstance,VisualInstance); + + Ref baked_light; + + +protected: + + static void _bind_methods(); +public: + + + RID get_baked_light_instance() const; + + void set_baked_light(const Ref& baked_light); + Ref get_baked_light() const; + + virtual AABB get_aabb() const; + virtual DVector get_faces(uint32_t p_usage_flags) const; + + BakedLightInstance(); +}; + +#endif // BAKED_LIGHT_H diff --git a/scene/3d/light.cpp b/scene/3d/light.cpp index b4b7b400c6..7cc1d12daa 100644 --- a/scene/3d/light.cpp +++ b/scene/3d/light.cpp @@ -351,6 +351,17 @@ void Light::set_operator(Operator p_op) { } +void Light::set_bake_mode(BakeMode p_bake_mode) { + + bake_mode=p_bake_mode; +} + +Light::BakeMode Light::get_bake_mode() const { + + return bake_mode; +} + + Light::Operator Light::get_operator() const { return op; @@ -416,6 +427,18 @@ void Light::approximate_opengl_attenuation(float p_constant, float p_linear, flo } +void Light::set_enabled(bool p_enabled) { + + enabled=p_enabled; + VS::get_singleton()->instance_light_set_enabled(get_instance(),enabled); +} + +bool Light::is_enabled() const{ + + return enabled; +} + + void Light::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_parameter","variable","value"), &Light::set_parameter ); @@ -428,8 +451,14 @@ void Light::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_projector:Texture"), &Light::get_projector ); ObjectTypeDB::bind_method(_MD("set_operator","operator"), &Light::set_operator ); ObjectTypeDB::bind_method(_MD("get_operator"), &Light::get_operator ); + ObjectTypeDB::bind_method(_MD("set_bake_mode","bake_mode"), &Light::set_bake_mode ); + ObjectTypeDB::bind_method(_MD("get_bake_mode"), &Light::get_bake_mode ); + ObjectTypeDB::bind_method(_MD("set_enabled","enabled"), &Light::set_enabled ); + ObjectTypeDB::bind_method(_MD("is_enabled"), &Light::is_enabled ); + ADD_PROPERTY( PropertyInfo( Variant::BOOL, "params/enabled"), _SCS("set_enabled"), _SCS("is_enabled")); + ADD_PROPERTY( PropertyInfo( Variant::INT, "params/bake_mode",PROPERTY_HINT_ENUM,"Disabled,Indirect,Full"), _SCS("set_bake_mode"), _SCS("get_bake_mode")); ADD_PROPERTYI( PropertyInfo( Variant::REAL, "params/energy", PROPERTY_HINT_EXP_RANGE, "0,64,0.01"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_ENERGY ); /* if (type == VisualServer::LIGHT_OMNI || type == VisualServer::LIGHT_SPOT) { @@ -490,6 +519,8 @@ Light::Light(VisualServer::LightType p_type) { op=OPERATOR_ADD; set_project_shadows( false ); set_base(light); + enabled=true; + bake_mode=BAKE_MODE_DISABLED; } @@ -563,6 +594,7 @@ DirectionalLight::DirectionalLight() : Light( VisualServer::LIGHT_DIRECTIONAL ) shadow_param[SHADOW_PARAM_PSSM_SPLIT_WEIGHT]=0.5; shadow_param[SHADOW_PARAM_PSSM_ZOFFSET_SCALE]=2.0; + } diff --git a/scene/3d/light.h b/scene/3d/light.h index dea7dbee6c..76b44c8712 100644 --- a/scene/3d/light.h +++ b/scene/3d/light.h @@ -64,6 +64,14 @@ public: COLOR_SPECULAR=VisualServer::LIGHT_COLOR_SPECULAR }; + enum BakeMode { + + BAKE_MODE_DISABLED, + BAKE_MODE_INDIRECT, + BAKE_MODE_FULL + + }; + enum Operator { @@ -78,8 +86,10 @@ private: Color colors[3]; + BakeMode bake_mode; VisualServer::LightType type; bool shadows; + bool enabled; Operator op; // bind helpers @@ -114,6 +124,12 @@ public: void set_operator(Operator p_op); Operator get_operator() const; + void set_bake_mode(BakeMode p_bake_mode); + BakeMode get_bake_mode() const; + + void set_enabled(bool p_enabled); + bool is_enabled() const; + virtual AABB get_aabb() const; virtual DVector get_faces(uint32_t p_usage_flags) const; @@ -127,6 +143,7 @@ public: VARIANT_ENUM_CAST( Light::Parameter ); VARIANT_ENUM_CAST( Light::LightColor ); VARIANT_ENUM_CAST( Light::Operator ); +VARIANT_ENUM_CAST( Light::BakeMode); class DirectionalLight : public Light { diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp index 21fdb9abd3..49e593c1f5 100644 --- a/scene/3d/sprite_3d.cpp +++ b/scene/3d/sprite_3d.cpp @@ -479,6 +479,7 @@ void Sprite3D::set_frame(int p_frame) { if (frame != p_frame) frame=p_frame; + _queue_update(); } int Sprite3D::get_frame() const { diff --git a/scene/3d/sprite_3d.h b/scene/3d/sprite_3d.h index 1330cd1c30..fe8e1f6ebf 100644 --- a/scene/3d/sprite_3d.h +++ b/scene/3d/sprite_3d.h @@ -5,9 +5,9 @@ #include "scene/2d/animated_sprite.h" -class SpriteBase3D : public VisualInstance { +class SpriteBase3D : public GeometryInstance { - OBJ_TYPE(SpriteBase3D,VisualInstance); + OBJ_TYPE(SpriteBase3D,GeometryInstance); public: enum DrawFlags { diff --git a/scene/3d/visual_instance.cpp b/scene/3d/visual_instance.cpp index 96f16ab8c8..625da9b093 100644 --- a/scene/3d/visual_instance.cpp +++ b/scene/3d/visual_instance.cpp @@ -31,7 +31,7 @@ #include "servers/visual_server.h" #include "room_instance.h" #include "scene/scene_string_names.h" - +#include "baked_light_instance.h" #include "skeleton.h" AABB VisualInstance::get_transformed_aabb() const { @@ -186,6 +186,61 @@ float GeometryInstance::get_draw_range_end() const { return draw_end; } +void GeometryInstance::_notification(int p_what) { + + if (p_what==NOTIFICATION_ENTER_WORLD) { + + if (flags[FLAG_USE_BAKED_LIGHT]) { + + _find_baked_light(); + } + + + } else if (p_what==NOTIFICATION_EXIT_WORLD) { + + if (flags[FLAG_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(); + + } + } + +} + +void GeometryInstance::_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()); + +} + +void GeometryInstance::_find_baked_light() { + + Node *n=get_parent(); + while(n) { + + BakedLightInstance *bl=n->cast_to(); + 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(); +} + void GeometryInstance::set_flag(Flags p_flag,bool p_value) { ERR_FAIL_INDEX(p_flag,FLAG_MAX); @@ -198,8 +253,20 @@ void GeometryInstance::set_flag(Flags p_flag,bool p_value) { _change_notify("geometry/visible"); emit_signal(SceneStringNames::get_singleton()->visibility_changed); } + if (p_flag==FLAG_USE_BAKED_LIGHT) { - + if (is_inside_world()) { + if (!p_value) { + 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 GeometryInstance::get_flag(Flags p_flag) const{ @@ -224,6 +291,8 @@ void GeometryInstance::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_draw_range_end","mode"), &GeometryInstance::set_draw_range_end); ObjectTypeDB::bind_method(_MD("get_draw_range_end"), &GeometryInstance::get_draw_range_end); + ObjectTypeDB::bind_method(_MD("_baked_light_changed"), &GeometryInstance::_baked_light_changed); + ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/visible"), _SCS("set_flag"), _SCS("get_flag"),FLAG_VISIBLE); ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "geometry/material_override",PROPERTY_HINT_RESOURCE_TYPE,"Material"), _SCS("set_material_override"), _SCS("get_material_override")); ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/cast_shadow"), _SCS("set_flag"), _SCS("get_flag"),FLAG_CAST_SHADOW); @@ -234,6 +303,7 @@ void GeometryInstance::_bind_methods() { ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/billboard_y"), _SCS("set_flag"), _SCS("get_flag"),FLAG_BILLBOARD_FIX_Y); ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/depth_scale"), _SCS("set_flag"), _SCS("get_flag"),FLAG_DEPH_SCALE); ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/visible_in_all_rooms"), _SCS("set_flag"), _SCS("get_flag"),FLAG_VISIBLE_IN_ALL_ROOMS); + ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/use_baked_light"), _SCS("set_flag"), _SCS("get_flag"),FLAG_USE_BAKED_LIGHT); ADD_SIGNAL( MethodInfo("visibility_changed")); @@ -258,5 +328,7 @@ GeometryInstance::GeometryInstance() { flags[FLAG_BILLBOARD_FIX_Y]=false; flags[FLAG_DEPH_SCALE]=false; flags[FLAG_VISIBLE_IN_ALL_ROOMS]=false; + baked_light_instance=NULL; + } diff --git a/scene/3d/visual_instance.h b/scene/3d/visual_instance.h index afb9ed70f8..1cf96d5d9e 100644 --- a/scene/3d/visual_instance.h +++ b/scene/3d/visual_instance.h @@ -78,6 +78,8 @@ public: }; +class BakedLightInstance; + class GeometryInstance : public VisualInstance { OBJ_TYPE( GeometryInstance, VisualInstance ); @@ -91,7 +93,7 @@ public: FLAG_BILLBOARD_FIX_Y=VS::INSTANCE_FLAG_BILLBOARD_FIX_Y, FLAG_DEPH_SCALE=VS::INSTANCE_FLAG_DEPH_SCALE, FLAG_VISIBLE_IN_ALL_ROOMS=VS::INSTANCE_FLAG_VISIBLE_IN_ALL_ROOMS, - FLAG_USE_BAKED_LIGHT_VOLUME=VS::INSTANCE_FLAG_USE_BAKED_LIGHT_VOLUME, + FLAG_USE_BAKED_LIGHT=VS::INSTANCE_FLAG_USE_BAKED_LIGHT, FLAG_MAX=VS::INSTANCE_FLAG_MAX, }; @@ -102,8 +104,13 @@ private: Ref material_override; float draw_begin; float draw_end; + void _find_baked_light(); + BakedLightInstance *baked_light_instance; + + void _baked_light_changed(); protected: + void _notification(int p_what); static void _bind_methods(); public: diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index f3d757b601..30e6e01842 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -187,7 +187,7 @@ #include "scene/3d/area.h" #include "scene/3d/physics_joint.h" #include "scene/3d/multimesh_instance.h" -#include "scene/3d/baked_light.h" +#include "scene/3d/baked_light_instance.h" #include "scene/3d/ray_cast.h" #include "scene/3d/immediate_geometry.h" #include "scene/3d/sprite_3d.h" @@ -407,7 +407,7 @@ void register_scene_types() { ObjectTypeDB::register_type(); ObjectTypeDB::register_type(); ObjectTypeDB::register_type(); - ObjectTypeDB::register_type(); + ObjectTypeDB::register_type(); ObjectTypeDB::register_type(); //scenariofx @@ -515,6 +515,7 @@ void register_scene_types() { ObjectTypeDB::register_type(); ObjectTypeDB::register_type(); + ObjectTypeDB::register_type(); OS::get_singleton()->yield(); //may take time to init diff --git a/scene/resources/baked_light.cpp b/scene/resources/baked_light.cpp new file mode 100644 index 0000000000..b3de7143ee --- /dev/null +++ b/scene/resources/baked_light.cpp @@ -0,0 +1,308 @@ +#include "baked_light.h" +#include "servers/visual_server.h" + +void BakedLight::set_mode(Mode p_mode) { + + mode=p_mode; + VS::get_singleton()->baked_light_set_mode(baked_light,(VS::BakedLightMode(p_mode))); +} + +BakedLight::Mode BakedLight::get_mode() const{ + + return mode; +} + +void BakedLight::set_octree(const DVector& p_octree) { + + VS::get_singleton()->baked_light_set_octree(baked_light,p_octree); +} + +DVector BakedLight::get_octree() const { + + return VS::get_singleton()->baked_light_get_octree(baked_light); +} + + +void BakedLight::_update_lightmaps() { + + VS::get_singleton()->baked_light_clear_lightmaps(baked_light); + for(Map >::Element *E=lightmaps.front();E;E=E->next()) { + + VS::get_singleton()->baked_light_add_lightmap(baked_light,E->get()->get_rid(),E->key()); + } + +} + +void BakedLight::add_lightmap(const Ref p_texture,int p_id) { + + ERR_FAIL_COND(!p_texture.is_valid()); + ERR_FAIL_COND(p_id<0); + lightmaps[p_id]=p_texture; + VS::get_singleton()->baked_light_add_lightmap(baked_light,p_texture->get_rid(),p_id); +} + +void BakedLight::erase_lightmap(int p_id) { + + ERR_FAIL_COND(!lightmaps.has(p_id)); + lightmaps.erase(p_id); + _update_lightmaps(); +} + +void BakedLight::get_lightmaps(List *r_lightmaps) { + + for(Map >::Element *E=lightmaps.front();E;E=E->next()) { + + r_lightmaps->push_back(E->key()); + } + +} + +Ref BakedLight::get_lightmap_texture(int p_id) { + + if (!lightmaps.has(p_id)) + return Ref(); + + return lightmaps[p_id]; + + +} + +void BakedLight::clear_lightmaps() { + + lightmaps.clear(); + _update_lightmaps(); +} + +RID BakedLight::get_rid() const { + + return baked_light; +} + +Array BakedLight::_get_lightmap_data() const { + + Array ret; + ret.resize(lightmaps.size()*2); + + int idx=0; + for(Map >::Element *E=lightmaps.front();E;E=E->next()) { + + ret[idx++]=E->key(); + ret[idx++]=E->get(); + } + + return ret; + +} + +void BakedLight::_set_lightmap_data(Array p_array){ + + lightmaps.clear(); + for(int i=0;i tex = p_array[i+1]; + ERR_CONTINUE(id<0); + ERR_CONTINUE(tex.is_null()); + lightmaps[id]=tex; + } + _update_lightmaps(); +} + + +void BakedLight::set_cell_subdivision(int p_subdiv) { + + cell_subdiv=p_subdiv; +} + +int BakedLight::get_cell_subdivision() const{ + + return cell_subdiv; +} + +void BakedLight::set_initial_lattice_subdiv(int p_size){ + + lattice_subdiv=p_size; +} +int BakedLight::get_initial_lattice_subdiv() const{ + + return lattice_subdiv; +} + +void BakedLight::set_plot_size(float p_size){ + + plot_size=p_size; +} +float BakedLight::get_plot_size() const{ + + return plot_size; +} + +void BakedLight::set_bounces(int p_size){ + + bounces=p_size; +} +int BakedLight::get_bounces() const{ + + return bounces; +} + +void BakedLight::set_cell_extra_margin(float p_margin) { + cell_extra_margin=p_margin; +} + +float BakedLight::get_cell_extra_margin() const { + + return cell_extra_margin; +} + +void BakedLight::set_edge_damp(float p_margin) { + edge_damp=p_margin; +} + +float BakedLight::get_edge_damp() const { + + return edge_damp; +} + + +void BakedLight::set_normal_damp(float p_margin) { + normal_damp=p_margin; +} + +float BakedLight::get_normal_damp() const { + + return normal_damp; +} + +void BakedLight::set_energy_multiplier(float p_multiplier){ + + energy_multiply=p_multiplier; +} +float BakedLight::get_energy_multiplier() const{ + + return energy_multiply; +} + +void BakedLight::set_gamma_adjust(float p_adjust){ + + gamma_adjust=p_adjust; +} +float BakedLight::get_gamma_adjust() const{ + + return gamma_adjust; +} + +void BakedLight::set_bake_flag(BakeFlags p_flags,bool p_enable){ + + flags[p_flags]=p_enable; +} +bool BakedLight::get_bake_flag(BakeFlags p_flags) const{ + + return flags[p_flags]; +} + + + +void BakedLight::_bind_methods(){ + + + ObjectTypeDB::bind_method(_MD("set_mode","mode"),&BakedLight::set_mode); + ObjectTypeDB::bind_method(_MD("get_mode"),&BakedLight::get_mode); + + ObjectTypeDB::bind_method(_MD("set_octree","octree"),&BakedLight::set_octree); + ObjectTypeDB::bind_method(_MD("get_octree"),&BakedLight::get_octree); + + ObjectTypeDB::bind_method(_MD("add_lightmap","texture:Texture","id"),&BakedLight::add_lightmap); + ObjectTypeDB::bind_method(_MD("erase_lightmap","id"),&BakedLight::erase_lightmap); + ObjectTypeDB::bind_method(_MD("clear_lightmaps"),&BakedLight::clear_lightmaps); + + ObjectTypeDB::bind_method(_MD("_set_lightmap_data","lightmap_data"),&BakedLight::_set_lightmap_data); + ObjectTypeDB::bind_method(_MD("_get_lightmap_data"),&BakedLight::_get_lightmap_data); + + ObjectTypeDB::bind_method(_MD("set_cell_subdivision","cell_subdivision"),&BakedLight::set_cell_subdivision); + ObjectTypeDB::bind_method(_MD("get_cell_subdivision"),&BakedLight::get_cell_subdivision); + + ObjectTypeDB::bind_method(_MD("set_initial_lattice_subdiv","cell_subdivision"),&BakedLight::set_initial_lattice_subdiv); + ObjectTypeDB::bind_method(_MD("get_initial_lattice_subdiv","cell_subdivision"),&BakedLight::get_initial_lattice_subdiv); + + ObjectTypeDB::bind_method(_MD("set_plot_size","plot_size"),&BakedLight::set_plot_size); + ObjectTypeDB::bind_method(_MD("get_plot_size"),&BakedLight::get_plot_size); + + ObjectTypeDB::bind_method(_MD("set_bounces","bounces"),&BakedLight::set_bounces); + ObjectTypeDB::bind_method(_MD("get_bounces"),&BakedLight::get_bounces); + + ObjectTypeDB::bind_method(_MD("set_cell_extra_margin","cell_extra_margin"),&BakedLight::set_cell_extra_margin); + ObjectTypeDB::bind_method(_MD("get_cell_extra_margin"),&BakedLight::get_cell_extra_margin); + + ObjectTypeDB::bind_method(_MD("set_edge_damp","edge_damp"),&BakedLight::set_edge_damp); + ObjectTypeDB::bind_method(_MD("get_edge_damp"),&BakedLight::get_edge_damp); + + ObjectTypeDB::bind_method(_MD("set_normal_damp","normal_damp"),&BakedLight::set_normal_damp); + ObjectTypeDB::bind_method(_MD("get_normal_damp"),&BakedLight::get_normal_damp); + + ObjectTypeDB::bind_method(_MD("set_energy_multiplier","energy_multiplier"),&BakedLight::set_energy_multiplier); + ObjectTypeDB::bind_method(_MD("get_energy_multiplier"),&BakedLight::get_energy_multiplier); + + ObjectTypeDB::bind_method(_MD("set_gamma_adjust","gamma_adjust"),&BakedLight::set_gamma_adjust); + ObjectTypeDB::bind_method(_MD("get_gamma_adjust"),&BakedLight::get_gamma_adjust); + + ObjectTypeDB::bind_method(_MD("set_bake_flag","flag","enabled"),&BakedLight::set_bake_flag); + ObjectTypeDB::bind_method(_MD("get_bake_flag","flag"),&BakedLight::get_bake_flag); + + ADD_PROPERTY( PropertyInfo(Variant::INT,"mode/mode",PROPERTY_HINT_ENUM,"Octree,Lightmaps"),_SCS("set_mode"),_SCS("get_mode")); + + ADD_PROPERTY( PropertyInfo(Variant::INT,"baking/cell_subdiv",PROPERTY_HINT_RANGE,"4,14,1"),_SCS("set_cell_subdivision"),_SCS("get_cell_subdivision")); + ADD_PROPERTY( PropertyInfo(Variant::INT,"baking/lattice_subdiv",PROPERTY_HINT_RANGE,"1,5,1"),_SCS("set_initial_lattice_subdiv"),_SCS("get_initial_lattice_subdiv")); + ADD_PROPERTY( PropertyInfo(Variant::INT,"baking/light_bounces",PROPERTY_HINT_RANGE,"0,3,1"),_SCS("set_bounces"),_SCS("get_bounces")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"baking/plot_size",PROPERTY_HINT_RANGE,"1.0,16.0,0.01"),_SCS("set_plot_size"),_SCS("get_plot_size")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"baking/energy_mult",PROPERTY_HINT_RANGE,"0.01,4096.0,0.01"),_SCS("set_energy_multiplier"),_SCS("get_energy_multiplier")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"baking/gamma_adjust",PROPERTY_HINT_EXP_EASING),_SCS("set_gamma_adjust"),_SCS("get_gamma_adjust")); + ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"baking_flags/diffuse"),_SCS("set_bake_flag"),_SCS("get_bake_flag"),BAKE_DIFFUSE); + ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"baking_flags/specular"),_SCS("set_bake_flag"),_SCS("get_bake_flag"),BAKE_SPECULAR); + ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"baking_flags/translucent"),_SCS("set_bake_flag"),_SCS("get_bake_flag"),BAKE_TRANSLUCENT); + ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"baking_flags/conserve_energy"),_SCS("set_bake_flag"),_SCS("get_bake_flag"),BAKE_CONSERVE_ENERGY); + + ADD_PROPERTY( PropertyInfo(Variant::RAW_ARRAY,"octree",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_octree"),_SCS("get_octree")); + ADD_PROPERTY( PropertyInfo(Variant::ARRAY,"lightmaps",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_lightmap_data"),_SCS("_get_lightmap_data")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"advanced/cell_margin",PROPERTY_HINT_RANGE,"0.01,0.8,0.01"),_SCS("set_cell_extra_margin"),_SCS("get_cell_extra_margin")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"advanced/edge_damp",PROPERTY_HINT_RANGE,"0.0,8.0,0.1"),_SCS("set_edge_damp"),_SCS("get_edge_damp")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"advanced/normal_damp",PROPERTY_HINT_RANGE,"0.0,1.0,0.01"),_SCS("set_normal_damp"),_SCS("get_normal_damp")); + + BIND_CONSTANT( MODE_OCTREE ); + BIND_CONSTANT( MODE_LIGHTMAPS ); + + BIND_CONSTANT( BAKE_DIFFUSE ); + BIND_CONSTANT( BAKE_SPECULAR ); + BIND_CONSTANT( BAKE_TRANSLUCENT ); + BIND_CONSTANT( BAKE_CONSERVE_ENERGY ); + BIND_CONSTANT( BAKE_MAX ); + + +} + + +BakedLight::BakedLight() { + + cell_subdiv=8; + lattice_subdiv=4; + plot_size=2.5; + bounces=1; + energy_multiply=1.0; + gamma_adjust=1.0; + cell_extra_margin=0.05; + edge_damp=0.0; + normal_damp=0.0; + + flags[BAKE_DIFFUSE]=true; + flags[BAKE_SPECULAR]=false; + flags[BAKE_TRANSLUCENT]=true; + flags[BAKE_CONSERVE_ENERGY]=false; + + mode=MODE_OCTREE; + baked_light=VS::get_singleton()->baked_light_create(); +} + +BakedLight::~BakedLight() { + + VS::get_singleton()->free(baked_light); +} diff --git a/scene/resources/baked_light.h b/scene/resources/baked_light.h new file mode 100644 index 0000000000..8b50f6e0d3 --- /dev/null +++ b/scene/resources/baked_light.h @@ -0,0 +1,106 @@ +#ifndef BAKED_LIGHT_H +#define BAKED_LIGHT_H + +#include "resource.h" +#include "scene/resources/texture.h" + +class BakedLight : public Resource { + + OBJ_TYPE( BakedLight, Resource); +public: + enum Mode { + + MODE_OCTREE, + MODE_LIGHTMAPS + }; + + enum BakeFlags { + BAKE_DIFFUSE, + BAKE_SPECULAR, + BAKE_TRANSLUCENT, + BAKE_CONSERVE_ENERGY, + BAKE_MAX + }; + +private: + + RID baked_light; + Mode mode; + Map > lightmaps; + + //bake vars + int cell_subdiv; + int lattice_subdiv; + float plot_size; + float energy_multiply; + float gamma_adjust; + float cell_extra_margin; + float edge_damp; + float normal_damp; + int bounces; + bool flags[BAKE_MAX]; + + + + void _update_lightmaps(); + + Array _get_lightmap_data() const; + void _set_lightmap_data(Array p_array); + static void _bind_methods(); + +public: + + void set_cell_subdivision(int p_subdiv); + int get_cell_subdivision() const; + + void set_initial_lattice_subdiv(int p_size); + int get_initial_lattice_subdiv() const; + + void set_plot_size(float p_size); + float get_plot_size() const; + + void set_bounces(int p_size); + int get_bounces() const; + + void set_energy_multiplier(float p_multiplier); + float get_energy_multiplier() const; + + void set_gamma_adjust(float p_adjust); + float get_gamma_adjust() const; + + void set_cell_extra_margin(float p_margin); + float get_cell_extra_margin() const; + + void set_edge_damp(float p_margin); + float get_edge_damp() const; + + void set_normal_damp(float p_margin); + float get_normal_damp() const; + + void set_bake_flag(BakeFlags p_flags,bool p_enable); + bool get_bake_flag(BakeFlags p_flags) const; + + + void set_mode(Mode p_mode); + Mode get_mode() const; + + void set_octree(const DVector& p_octree); + DVector get_octree() const; + + void add_lightmap(const Ref p_texture,int p_id); + void erase_lightmap(int p_id); + void get_lightmaps(List *r_lightmaps); + Ref get_lightmap_texture(int p_id); + void clear_lightmaps(); + + virtual RID get_rid() const; + + BakedLight(); + ~BakedLight(); +}; + + +VARIANT_ENUM_CAST(BakedLight::Mode); +VARIANT_ENUM_CAST(BakedLight::BakeFlags); + +#endif // BAKED_LIGHT_H diff --git a/scene/scene_string_names.cpp b/scene/scene_string_names.cpp index a8e4c80f89..40792f5139 100644 --- a/scene/scene_string_names.cpp +++ b/scene/scene_string_names.cpp @@ -140,4 +140,8 @@ SceneStringNames::SceneStringNames() { _im_update = StaticCString::create("_im_update"); _queue_update = StaticCString::create("_queue_update"); + baked_light_changed = StaticCString::create("baked_light_changed"); + _baked_light_changed = StaticCString::create("_baked_light_changed"); + + } diff --git a/scene/scene_string_names.h b/scene/scene_string_names.h index 2286712250..866c0ea387 100644 --- a/scene/scene_string_names.h +++ b/scene/scene_string_names.h @@ -148,6 +148,9 @@ public: StringName _im_update; StringName _queue_update; + StringName baked_light_changed; + StringName _baked_light_changed; + }; diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index a3cdff9859..0aa7fc2650 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -302,6 +302,11 @@ public: virtual void multimesh_set_visible_instances(RID p_multimesh,int p_visible)=0; virtual int multimesh_get_visible_instances(RID p_multimesh) const=0; + /* BAKED LIGHT */ + + + + /* IMMEDIATE API */ virtual RID immediate_create()=0; @@ -490,6 +495,20 @@ public: typedef Map ParamOverrideMap; + struct BakedLightData { + + VS::BakedLightMode mode; + RID octree_texture; + float color_multiplier; //used for both lightmaps and octree + Transform octree_transform; + Map lightmaps; + //cache + + float octree_lattice_size; + float octree_lattice_divide; + int octree_steps; + Vector2 octree_tex_pixel_size; + }; struct InstanceData { @@ -498,6 +517,8 @@ public: RID material_override; Vector light_instances; Vector morph_values; + BakedLightData *baked_light; + Transform *baked_light_octree_xform; bool mirror :8; bool depth_scale :8; bool billboard :8; diff --git a/servers/visual/visual_server_raster.cpp b/servers/visual/visual_server_raster.cpp index bffc1c43fe..519e697ab2 100644 --- a/servers/visual/visual_server_raster.cpp +++ b/servers/visual/visual_server_raster.cpp @@ -31,6 +31,7 @@ #include "globals.h" #include "default_mouse_cursor.xpm" #include "sort.h" +#include "io/marshalls.h" // careful, these may run in different threads than the visual server BalloonAllocator<> *VisualServerRaster::OctreeAllocator::allocator=NULL; @@ -921,6 +922,7 @@ void VisualServerRaster::room_set_bounds(RID p_room, const BSP_Tree& p_bounds) { Room *room = room_owner.get(p_room); ERR_FAIL_COND(!room); room->bounds=p_bounds; + _dependency_queue_update(p_room,true); } @@ -1032,6 +1034,138 @@ float VisualServerRaster::portal_get_connect_range(RID p_portal) const { } +RID VisualServerRaster::baked_light_create() { + + BakedLight *baked_light = memnew( BakedLight ); + ERR_FAIL_COND_V(!baked_light,RID()); + baked_light->data.mode=BAKED_LIGHT_OCTREE; + + baked_light->data.octree_lattice_size=0; + baked_light->data.octree_lattice_divide=0; + baked_light->data.octree_steps=1; + + return baked_light_owner.make_rid( baked_light ); + +} + +void VisualServerRaster::baked_light_set_mode(RID p_baked_light,BakedLightMode p_mode){ + + VS_CHANGED; + BakedLight *baked_light = baked_light_owner.get(p_baked_light); + ERR_FAIL_COND(!baked_light); + baked_light->data.mode=p_mode; + baked_light->data.color_multiplier=1.0; + _dependency_queue_update(p_baked_light,true); + + +} + +VisualServer::BakedLightMode VisualServerRaster::baked_light_get_mode(RID p_baked_light) const{ + + const BakedLight *baked_light = baked_light_owner.get(p_baked_light); + ERR_FAIL_COND_V(!baked_light,BAKED_LIGHT_OCTREE); + return baked_light->data.mode; + +} + +void VisualServerRaster::baked_light_set_octree(RID p_baked_light,const DVector p_octree){ + + VS_CHANGED; + BakedLight *baked_light = baked_light_owner.get(p_baked_light); + ERR_FAIL_COND(!baked_light); + + if (p_octree.size()==0) { + if (baked_light->data.octree_texture.is_valid()) + rasterizer->free(baked_light->data.octree_texture); + baked_light->data.octree_texture=RID(); + baked_light->octree_aabb=AABB(); + baked_light->octree_tex_size=Size2(); + } else { + + int tex_w; + int tex_h; + bool is16; + { + DVector::Read r=p_octree.read(); + tex_w = decode_uint32(&r[0]); + tex_h = decode_uint32(&r[4]); + print_line("TEX W: "+itos(tex_w)+" TEX H:"+itos(tex_h)+" LEN: "+itos(p_octree.size())); + is16=decode_uint32(&r[8]); + baked_light->data.octree_lattice_size=decode_float(&r[12]); + baked_light->data.octree_lattice_divide=tex_w/4.0; + print_line("LATTICE SIZE: "+rtos(baked_light->data.octree_lattice_size)); + print_line("LATTICE DIVIDE: "+rtos(baked_light->data.octree_lattice_divide)); + baked_light->data.octree_steps=decode_uint32(&r[16]); + baked_light->data.octree_tex_pixel_size.x=1.0/tex_w; + baked_light->data.octree_tex_pixel_size.y=1.0/tex_h; + + + baked_light->octree_aabb.pos.x=decode_float(&r[32]); + baked_light->octree_aabb.pos.y=decode_float(&r[36]); + baked_light->octree_aabb.pos.z=decode_float(&r[40]); + baked_light->octree_aabb.size.x=decode_float(&r[44]); + baked_light->octree_aabb.size.y=decode_float(&r[48]); + baked_light->octree_aabb.size.z=decode_float(&r[52]); + + + } + + if (baked_light->data.octree_texture.is_valid()) { + if (tex_w!=baked_light->octree_tex_size.x || tex_h!=baked_light->octree_tex_size.y) { + + rasterizer->free(baked_light->data.octree_texture); + baked_light->data.octree_texture=RID(); + } + } + + if (!baked_light->data.octree_texture.is_valid()) { + baked_light->data.octree_texture=rasterizer->texture_create(); + rasterizer->texture_allocate(baked_light->data.octree_texture,tex_w,tex_h,Image::FORMAT_RGBA,TEXTURE_FLAG_FILTER); + } + + Image img(tex_w,tex_h,0,Image::FORMAT_RGBA,p_octree); + rasterizer->texture_set_data(baked_light->data.octree_texture,img); + + } + + + _dependency_queue_update(p_baked_light,true); + +} + +DVector VisualServerRaster::baked_light_get_octree(RID p_baked_light) const{ + + + BakedLight *baked_light = baked_light_owner.get(p_baked_light); + ERR_FAIL_COND_V(!baked_light,DVector()); + + if (rasterizer->is_texture(baked_light->data.octree_texture)) { + + Image img = rasterizer->texture_get_data(baked_light->data.octree_texture); + return img.get_data(); + } else { + return DVector(); + } +} + +void VisualServerRaster::baked_light_add_lightmap(RID p_baked_light,const RID p_texture,int p_id){ + + VS_CHANGED; + BakedLight *baked_light = baked_light_owner.get(p_baked_light); + ERR_FAIL_COND(!baked_light); + baked_light->data.lightmaps.insert(p_id,p_texture); + +} +void VisualServerRaster::baked_light_clear_lightmaps(RID p_baked_light){ + + VS_CHANGED; + BakedLight *baked_light = baked_light_owner.get(p_baked_light); + ERR_FAIL_COND(!baked_light); + baked_light->data.lightmaps.clear(); + +} + + /* CAMERA API */ RID VisualServerRaster::camera_create() { @@ -1710,6 +1844,23 @@ void VisualServerRaster::instance_set_base(RID p_instance, RID p_base) { } + if (instance->baked_light_info) { + + while(instance->baked_light_info->owned_instances.size()) { + + Instance *owned=instance->baked_light_info->owned_instances.front()->get(); + owned->baked_light=NULL; + owned->data.baked_light=NULL; + owned->data.baked_light_octree_xform=NULL; + owned->BLE=NULL; + instance->baked_light_info->owned_instances.pop_front(); + } + + memdelete(instance->baked_light_info); + instance->baked_light_info=NULL; + + } + if (instance->scenario && instance->octree_id) { instance->scenario->octree.erase( instance->octree_id ); instance->octree_id=0; @@ -1796,6 +1947,14 @@ void VisualServerRaster::instance_set_base(RID p_instance, RID p_base) { instance->base_type=INSTANCE_PORTAL; instance->portal_info = memnew(Instance::PortalInfo); instance->portal_info->portal=portal_owner.get(p_base); + } else if (baked_light_owner.owns(p_base)) { + + instance->base_type=INSTANCE_BAKED_LIGHT; + instance->baked_light_info=memnew(Instance::BakedLightInfo); + instance->baked_light_info->baked_light=baked_light_owner.get(p_base); + + //instance->portal_info = memnew(Instance::PortalInfo); + //instance->portal_info->portal=portal_owner.get(p_base); } else { ERR_EXPLAIN("Invalid base RID for instance!") ERR_FAIL(); @@ -2365,6 +2524,68 @@ float VisualServerRaster::instance_geometry_get_draw_range_max(RID p_instance) c } + +void VisualServerRaster::instance_geometry_set_baked_light(RID p_instance,RID p_baked_light) { + + VS_CHANGED; + Instance *instance = instance_owner.get( p_instance ); + ERR_FAIL_COND( !instance ); + + + if (instance->baked_light) { + + + instance->baked_light->baked_light_info->owned_instances.erase(instance->BLE); + instance->BLE=NULL; + instance->baked_light=NULL; + instance->data.baked_light=NULL; + instance->data.baked_light_octree_xform=NULL; + + } + + if (!p_baked_light.is_valid()) + return; + Instance *bl_instance = instance_owner.get( p_baked_light ); + ERR_FAIL_COND( !bl_instance ); + ERR_FAIL_COND( bl_instance->base_type!=INSTANCE_BAKED_LIGHT ); + + instance->baked_light=bl_instance; + instance->BLE=bl_instance->baked_light_info->owned_instances.push_back(instance); + instance->data.baked_light=&bl_instance->baked_light_info->baked_light->data; + instance->data.baked_light_octree_xform=&bl_instance->baked_light_info->affine_inverse; + +} + +RID VisualServerRaster::instance_geometry_get_baked_light(RID p_instance) const{ + + const Instance *instance = instance_owner.get( p_instance ); + ERR_FAIL_COND_V( !instance,RID() ); + if (instance->baked_light) + instance->baked_light->self; + return RID(); + +} + +void VisualServerRaster::instance_geometry_set_baked_light_texture_index(RID p_instance,int p_tex_id){ + + VS_CHANGED; + Instance *instance = instance_owner.get( p_instance ); + ERR_FAIL_COND( !instance ); + + instance->lightmap_texture_index=p_tex_id; + + +} +int VisualServerRaster::instance_geometry_get_baked_light_texture_index(RID p_instance) const{ + + const Instance *instance = instance_owner.get( p_instance ); + ERR_FAIL_COND_V( !instance,0 ); + + return instance->lightmap_texture_index; + +} + + void VisualServerRaster::_update_instance(Instance *p_instance) { p_instance->version++; @@ -2385,7 +2606,7 @@ void VisualServerRaster::_update_instance(Instance *p_instance) { } - if (p_instance->base_type&INSTANCE_GEOMETRY_MASK) { + if ((1<base_type)&INSTANCE_GEOMETRY_MASK) { //make sure lights are updated InstanceSet::Element *E=p_instance->lights.front(); @@ -2395,13 +2616,20 @@ void VisualServerRaster::_update_instance(Instance *p_instance) { E=E->next(); } - } - - if (p_instance->base_type == INSTANCE_ROOM) { + } else if (p_instance->base_type == INSTANCE_ROOM) { p_instance->room_info->affine_inverse=p_instance->data.transform.affine_inverse(); + } else if (p_instance->base_type == INSTANCE_BAKED_LIGHT) { + + Transform scale; + scale.basis.scale(p_instance->baked_light_info->baked_light->octree_aabb.size); + scale.origin=p_instance->baked_light_info->baked_light->octree_aabb.pos; + //print_line("scale: "+scale); + p_instance->baked_light_info->affine_inverse=(p_instance->data.transform*scale).affine_inverse(); } + + p_instance->data.mirror = p_instance->data.transform.basis.determinant() < 0.0; AABB new_aabb; @@ -2463,7 +2691,7 @@ void VisualServerRaster::_update_instance(Instance *p_instance) { if (p_instance->base_type == INSTANCE_LIGHT) { - pairable_mask=INSTANCE_GEOMETRY_MASK; + pairable_mask=p_instance->light_info->enabled?INSTANCE_GEOMETRY_MASK:0; pairable=true; } @@ -2578,6 +2806,13 @@ void VisualServerRaster::_update_instance_aabb(Instance *p_instance) { } } break; + case VisualServer::INSTANCE_BAKED_LIGHT: { + + BakedLight *baked_light = baked_light_owner.get( p_instance->base_rid ); + ERR_FAIL_COND(!baked_light); + new_aabb=baked_light->octree_aabb; + + } break; default: {} } @@ -2607,6 +2842,33 @@ void VisualServerRaster::_update_instances() { } } +void VisualServerRaster::instance_light_set_enabled(RID p_instance,bool p_enabled) { + + VS_CHANGED; + Instance *instance = instance_owner.get( p_instance ); + ERR_FAIL_COND( !instance ); + ERR_FAIL_COND( instance->base_type!=INSTANCE_LIGHT ); + + if (p_enabled==instance->light_info->enabled) + return; + + instance->light_info->enabled=p_enabled; + if (light_get_type(instance->base_rid)!=VS::LIGHT_DIRECTIONAL && instance->octree_id && instance->scenario) + instance->scenario->octree.set_pairable(instance->octree_id,p_enabled,1<base_type!=INSTANCE_LIGHT,false ); + + return instance->light_info->enabled; +} + /****** CANVAS *********/ RID VisualServerRaster::canvas_create() { @@ -3330,6 +3592,13 @@ void VisualServerRaster::black_bars_set_margins(int p_left, int p_top, int p_rig black_margin[MARGIN_BOTTOM]=p_bottom; } +void VisualServerRaster::black_bars_set_images(RID p_left, RID p_top, RID p_right, RID p_bottom) { + + black_image[MARGIN_LEFT]=p_left; + black_image[MARGIN_TOP]=p_top; + black_image[MARGIN_RIGHT]=p_right; + black_image[MARGIN_BOTTOM]=p_bottom; +} void VisualServerRaster::_free_attached_instances(RID p_rid,bool p_free_scenario) { @@ -3414,6 +3683,17 @@ void VisualServerRaster::free( RID p_rid ) { portal_owner.free(p_rid); memdelete(portal); + } else if (baked_light_owner.owns(p_rid)) { + + _free_attached_instances(p_rid); + + BakedLight *baked_light = baked_light_owner.get(p_rid); + ERR_FAIL_COND(!baked_light); + if (baked_light->data.octree_texture.is_valid()) + rasterizer->free(baked_light->data.octree_texture); + baked_light_owner.free(p_rid); + memdelete(baked_light); + } else if (camera_owner.owns(p_rid)) { // delete te camera @@ -3464,8 +3744,9 @@ void VisualServerRaster::free( RID p_rid ) { instance_set_room(p_rid,RID()); instance_set_scenario(p_rid,RID()); + instance_geometry_set_baked_light(p_rid,RID()); instance_set_base(p_rid,RID()); - + instance_owner.free(p_rid); memdelete(instance); @@ -5101,7 +5382,7 @@ void VisualServerRaster::_render_camera(Viewport *p_viewport,Camera *p_camera, S Instance *light = E->get().is_valid()?instance_owner.get(E->get()):NULL; - if (rasterizer->light_has_shadow(light->base_rid)) { + if (light && light->light_info->enabled && rasterizer->light_has_shadow(light->base_rid)) { //rasterizer->light_instance_set_active_hint(light->light_info->instance); _light_instance_update_shadow(light,p_scenario,p_camera,cull_range); } @@ -5190,6 +5471,9 @@ void VisualServerRaster::_render_camera(Viewport *p_viewport,Camera *p_camera, S Instance *light = E->get().is_valid()?instance_owner.get(E->get()):NULL; ERR_CONTINUE(!light); + if (!light->light_info->enabled) + continue; + rasterizer->add_light(light->light_info->instance); light->light_info->last_add_pass=render_pass; } @@ -5694,9 +5978,16 @@ void VisualServerRaster::_draw_cursors_and_margins() { rasterizer->canvas_draw_rect(Rect2(cursors[i].pos, size), 0, Rect2(), tex, Color(1, 1, 1, 1)); }; - if (black_margin[MARGIN_LEFT]) + if (black_image[MARGIN_LEFT].is_valid()) { + Size2 sz(rasterizer->texture_get_width(black_image[MARGIN_LEFT]),rasterizer->texture_get_height(black_image[MARGIN_LEFT])); + rasterizer->canvas_draw_rect(Rect2(0,0,black_margin[MARGIN_LEFT],window_h),0,Rect2(0,0,sz.x,sz.y),black_image[MARGIN_LEFT],Color(1,1,1)); + } else if (black_margin[MARGIN_LEFT]) rasterizer->canvas_draw_rect(Rect2(0,0,black_margin[MARGIN_LEFT],window_h),0,Rect2(0,0,1,1),RID(),Color(0,0,0)); - if (black_margin[MARGIN_RIGHT]) + + if (black_image[MARGIN_RIGHT].is_valid()) { + Size2 sz(rasterizer->texture_get_width(black_image[MARGIN_RIGHT]),rasterizer->texture_get_height(black_image[MARGIN_RIGHT])); + rasterizer->canvas_draw_rect(Rect2(window_w-black_margin[MARGIN_RIGHT],0,black_margin[MARGIN_RIGHT],window_h),0,Rect2(0,0,sz.x,sz.y),black_image[MARGIN_RIGHT],Color(1,1,1)); + } else if (black_margin[MARGIN_RIGHT]) rasterizer->canvas_draw_rect(Rect2(window_w-black_margin[MARGIN_RIGHT],0,black_margin[MARGIN_RIGHT],window_h),0,Rect2(0,0,1,1),RID(),Color(0,0,0)); if (black_margin[MARGIN_TOP]) rasterizer->canvas_draw_rect(Rect2(0,0,window_w,black_margin[MARGIN_TOP]),0,Rect2(0,0,1,1),RID(),Color(0,0,0)); diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index f6ef4ba6d5..ddc30bb2ee 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -87,6 +87,14 @@ class VisualServerRaster : public VisualServer { Portal() { enabled=true; disable_distance=50; disable_color=Color(); connect_range=0.8; } }; + struct BakedLight { + + Rasterizer::BakedLightData data; + AABB octree_aabb; + Size2i octree_tex_size; + + }; + struct Camera { @@ -149,6 +157,7 @@ class VisualServerRaster : public VisualServer { float draw_range_begin; float draw_range_end; float extra_margin; + int lightmap_texture_index; Rasterizer::InstanceData data; @@ -158,6 +167,8 @@ class VisualServerRaster : public VisualServer { Set valid_auto_rooms; Instance *room; List::Element *RE; + Instance *baked_light; + List::Element *BLE; bool exterior; uint64_t last_render_pass; @@ -205,6 +216,7 @@ class VisualServerRaster : public VisualServer { uint64_t last_add_pass; List::Element *D; // directional light in scenario InstanceSet affected; + bool enabled; float dtc; //distance to camera, used for sorting @@ -213,8 +225,16 @@ class VisualServerRaster : public VisualServer { D=NULL; light_set_index=-1; last_add_pass=0; + enabled=true; } }; + + struct BakedLightInfo { + + BakedLight *baked_light; + Transform affine_inverse; + List owned_instances; + }; struct ParticlesInfo { @@ -226,6 +246,7 @@ class VisualServerRaster : public VisualServer { LightInfo *light_info; ParticlesInfo *particles_info; PortalInfo * portal_info; + BakedLightInfo * baked_light_info; Instance() { @@ -244,6 +265,8 @@ class VisualServerRaster : public VisualServer { data.depth_scale=false; data.billboard=false; data.billboard_y=false; + data.baked_light=NULL; + data.baked_light_octree_xform=NULL; version=1; room_info=NULL; room=NULL; @@ -255,6 +278,10 @@ class VisualServerRaster : public VisualServer { draw_range_end=0; extra_margin=0; visible_in_all_rooms=false; + lightmap_texture_index=-1; + baked_light=NULL; + baked_light_info=NULL; + BLE=NULL; light_cache_dirty=true; @@ -270,6 +297,8 @@ class VisualServerRaster : public VisualServer { memdelete(room_info); if (portal_info) memdelete(portal_info); + if (baked_light_info) + memdelete(baked_light_info); }; }; @@ -570,6 +599,7 @@ class VisualServerRaster : public VisualServer { bool light_discard_enabled; bool shadows_enabled; int black_margin[4]; + RID black_image[4]; Vector aabb_random_points; Vector transformed_aabb_random_points; @@ -596,7 +626,9 @@ class VisualServerRaster : public VisualServer { mutable RID_Owner room_owner; mutable RID_Owner portal_owner; - + + mutable RID_Owner baked_light_owner; + mutable RID_Owner camera_owner; mutable RID_Owner viewport_owner; @@ -902,8 +934,19 @@ public: virtual void portal_set_connect_range(RID p_portal, float p_range); virtual float portal_get_connect_range(RID p_portal) const; + /* BAKED LIGHT */ + + virtual RID baked_light_create(); + + virtual void baked_light_set_mode(RID p_baked_light,BakedLightMode p_mode); + virtual BakedLightMode baked_light_get_mode(RID p_baked_light) const; + + virtual void baked_light_set_octree(RID p_baked_light,const DVector p_octree); + virtual DVector baked_light_get_octree(RID p_baked_light) const; + + virtual void baked_light_add_lightmap(RID p_baked_light,const RID p_texture,int p_id); + virtual void baked_light_clear_lightmaps(RID p_baked_light); - /* CAMERA API */ virtual RID camera_create(); @@ -1036,6 +1079,15 @@ public: virtual float instance_geometry_get_draw_range_max(RID p_instance) const; virtual float instance_geometry_get_draw_range_min(RID p_instance) const; + virtual void instance_geometry_set_baked_light(RID p_instance,RID p_baked_light); + virtual RID instance_geometry_get_baked_light(RID p_instance) const; + + virtual void instance_geometry_set_baked_light_texture_index(RID p_instance,int p_tex_id); + virtual int instance_geometry_get_baked_light_texture_index(RID p_instance) const; + + virtual void instance_light_set_enabled(RID p_instance,bool p_enabled); + virtual bool instance_light_is_enabled(RID p_instance) const; + /* CANVAS (2D) */ virtual RID canvas_create(); @@ -1093,6 +1145,7 @@ public: /* BLACK BARS */ virtual void black_bars_set_margins(int p_left, int p_top, int p_right, int p_bottom); + virtual void black_bars_set_images(RID p_left, RID p_top, RID p_right, RID p_bottom); /* FREE */ diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h index cfc4bd8605..0b7721cf8b 100644 --- a/servers/visual/visual_server_wrap_mt.h +++ b/servers/visual/visual_server_wrap_mt.h @@ -879,6 +879,17 @@ public: FUNC1RC(float,portal_get_connect_range,RID); + FUNC0R(RID,baked_light_create); + FUNC2(baked_light_set_mode,RID,BakedLightMode); + FUNC1RC(BakedLightMode,baked_light_get_mode,RID); + + FUNC2(baked_light_set_octree,RID,DVector); + FUNC1RC(DVector,baked_light_get_octree,RID); + + + FUNC3(baked_light_add_lightmap,RID,RID,int); + FUNC1(baked_light_clear_lightmaps,RID); + /* CAMERA API */ @@ -1014,6 +1025,14 @@ public: FUNC1RC(float,instance_geometry_get_draw_range_max,RID); FUNC1RC(float,instance_geometry_get_draw_range_min,RID); + FUNC2(instance_geometry_set_baked_light,RID, RID ); + FUNC1RC(RID,instance_geometry_get_baked_light,RID); + + FUNC2(instance_geometry_set_baked_light_texture_index,RID, int); + FUNC1RC(int,instance_geometry_get_baked_light_texture_index,RID); + + FUNC2(instance_light_set_enabled,RID,bool); + FUNC1RC(bool,instance_light_is_enabled,RID); /* CANVAS (2D) */ @@ -1076,6 +1095,7 @@ public: /* BLACK BARS */ FUNC4(black_bars_set_margins,int , int , int , int ); + FUNC4(black_bars_set_images,RID , RID , RID , RID ); /* FREE */ diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp index 08cc57e307..d2b55092d6 100644 --- a/servers/visual_server.cpp +++ b/servers/visual_server.cpp @@ -145,6 +145,7 @@ RID VisualServer::_make_test_cube() { tangents.push_back( normal_points[m_idx][0] );\ tangents.push_back( 1.0 );\ uvs.push_back( Vector3(uv_points[m_idx*2+0],uv_points[m_idx*2+1],0) );\ + print_line(itos( (face_points[m_idx][0]>0?1:0)|(face_points[m_idx][1]>0?2:0)|(face_points[m_idx][2]>0?4:0)));\ vtx_idx++;\ for (int i=0;i<6;i++) { @@ -527,6 +528,7 @@ void VisualServer::_bind_methods() { ObjectTypeDB::bind_method(_MD("cursor_set_pos"),&VisualServer::cursor_set_pos); ObjectTypeDB::bind_method(_MD("black_bars_set_margins","left","top","right","bottom"),&VisualServer::black_bars_set_margins); + ObjectTypeDB::bind_method(_MD("black_bars_set_images","left","top","right","bottom"),&VisualServer::black_bars_set_images); ObjectTypeDB::bind_method(_MD("make_sphere_mesh"),&VisualServer::make_sphere_mesh); ObjectTypeDB::bind_method(_MD("mesh_add_surface_from_planes"),&VisualServer::mesh_add_surface_from_planes); diff --git a/servers/visual_server.h b/servers/visual_server.h index e5d1e75702..f01685890f 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -576,6 +576,23 @@ public: virtual float portal_get_connect_range(RID p_portal) const =0; + /* BAKED LIGHT API */ + + virtual RID baked_light_create()=0; + enum BakedLightMode { + BAKED_LIGHT_OCTREE, + BAKED_LIGHT_LIGHTMAPS + }; + + virtual void baked_light_set_mode(RID p_baked_light,BakedLightMode p_mode)=0; + virtual BakedLightMode baked_light_get_mode(RID p_baked_light) const=0; + + virtual void baked_light_set_octree(RID p_baked_light,const DVector p_octree)=0; + virtual DVector baked_light_get_octree(RID p_baked_light) const=0; + + virtual void baked_light_add_lightmap(RID p_baked_light,const RID p_texture,int p_id)=0; + virtual void baked_light_clear_lightmaps(RID p_baked_light)=0; + /* CAMERA API */ @@ -792,6 +809,7 @@ public: INSTANCE_LIGHT, INSTANCE_ROOM, INSTANCE_PORTAL, + INSTANCE_BAKED_LIGHT, INSTANCE_GEOMETRY_MASK=(1<get("texture_import/filter")) + if (Globals::get_singleton()->get("image_loader/filter")) flags|=EditorTextureImportPlugin::IMAGE_FLAG_FILTER; - if (!Globals::get_singleton()->get("texture_import/gen_mipmaps")) + if (!Globals::get_singleton()->get("image_loader/gen_mipmaps")) flags|=EditorTextureImportPlugin::IMAGE_FLAG_NO_MIPMAPS; - if (!Globals::get_singleton()->get("texture_import/repeat")) + if (!Globals::get_singleton()->get("image_loader/repeat")) flags|=EditorTextureImportPlugin::IMAGE_FLAG_REPEAT; flags|=EditorTextureImportPlugin::IMAGE_FLAG_FIX_BORDER_ALPHA; @@ -1533,6 +1533,26 @@ void EditorImportExport::load_config() { } + if (cf->has_section("script")) { + + if (cf->has_section_key("script","action")) { + + String action = cf->get_value("script","action"); + if (action=="compile") + script_action=SCRIPT_ACTION_COMPILE; + else if (action=="encrypt") + script_action=SCRIPT_ACTION_ENCRYPT; + else + script_action=SCRIPT_ACTION_NONE; + + } + + if (cf->has_section_key("script","encrypt_key")) { + + script_key = cf->get_value("script","encrypt_key"); + } + } + } @@ -1634,10 +1654,39 @@ void EditorImportExport::save_config() { cf->set_value("image_group_files","files",igfsave); } + switch(script_action) { + case SCRIPT_ACTION_NONE: cf->set_value("script","action","none"); break; + case SCRIPT_ACTION_COMPILE: cf->set_value("script","action","compile"); break; + case SCRIPT_ACTION_ENCRYPT: cf->set_value("script","action","encrypt"); break; + } + + cf->set_value("script","encrypt_key",script_key); + cf->save("res://export.cfg"); } + +void EditorImportExport::script_set_action(ScriptAction p_action) { + + script_action=p_action; +} + +EditorImportExport::ScriptAction EditorImportExport::script_get_action() const{ + + return script_action; +} + +void EditorImportExport::script_set_encryption_key(const String& p_key){ + + script_key=p_key; +} +String EditorImportExport::script_get_encryption_key() const{ + + return script_key; +} + + void EditorImportExport::_bind_methods() { ObjectTypeDB::bind_method(_MD("image_export_group_create"),&EditorImportExport::image_export_group_create); @@ -1649,6 +1698,11 @@ void EditorImportExport::_bind_methods() { ObjectTypeDB::bind_method(_MD("image_export_group_get_make_atlas"),&EditorImportExport::image_export_group_get_make_atlas); ObjectTypeDB::bind_method(_MD("image_export_group_get_shrink"),&EditorImportExport::image_export_group_get_shrink); ObjectTypeDB::bind_method(_MD("image_add_to_export_group"),&EditorImportExport::image_add_to_export_group); + ObjectTypeDB::bind_method(_MD("script_set_action"),&EditorImportExport::script_set_action); + ObjectTypeDB::bind_method(_MD("script_set_encryption_key"),&EditorImportExport::script_set_encryption_key); + ObjectTypeDB::bind_method(_MD("script_get_action"),&EditorImportExport::script_get_action); + ObjectTypeDB::bind_method(_MD("script_get_encryption_key"),&EditorImportExport::script_get_encryption_key); + } EditorImportExport::EditorImportExport() { @@ -1659,6 +1713,9 @@ EditorImportExport::EditorImportExport() { image_action_compress_quality=0.7; image_formats.insert("png"); image_shrink=1; + + script_action=SCRIPT_ACTION_COMPILE; + } diff --git a/tools/editor/editor_import_export.h b/tools/editor/editor_import_export.h index 0f9068f8b3..8305e3c88c 100644 --- a/tools/editor/editor_import_export.h +++ b/tools/editor/editor_import_export.h @@ -227,6 +227,11 @@ public: IMAGE_ACTION_COMPRESS_RAM, }; + enum ScriptAction { + SCRIPT_ACTION_NONE, + SCRIPT_ACTION_COMPILE, + SCRIPT_ACTION_ENCRYPT + }; protected: @@ -254,6 +259,9 @@ protected: Map image_group_files; Vector diff_packs; + ScriptAction script_action; + String script_key; + static EditorImportExport* singleton; static void _bind_methods(); @@ -316,6 +324,11 @@ public: Set& get_image_formats() { return image_formats; } + void script_set_action(ScriptAction p_action); + ScriptAction script_get_action() const; + + void script_set_encryption_key(const String& p_key); + String script_get_encryption_key() const; void load_config(); void save_config(); @@ -324,5 +337,6 @@ public: }; VARIANT_ENUM_CAST(EditorImportExport::ImageAction); +VARIANT_ENUM_CAST(EditorImportExport::ScriptAction); #endif // EDITOR_IMPORT_EXPORT_H diff --git a/tools/editor/icons/icon_bake.png b/tools/editor/icons/icon_bake.png new file mode 100644 index 0000000000000000000000000000000000000000..b1b0f941da74066ab510c2a82a4983b7c9833463 GIT binary patch literal 419 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b z3=G`DAk4@xYmNj^kiEpy*OmPq8@qr$o1mV`IiQeaiEBiObAE1aYF-J0b5UwyNotBh zd1gt5g1e`0KzJjcI0FMCx2KC^h{frnlQw!eI|{g-*E{c^lCbw`gMoZP;`)w`|4L>X zyIXxlxE)XAFA+NE^@r8Eb?vpZdIuKMUpdcOH|()-Vb#}}9-H>=&P>@K+)HMJN8S6S z`7Ew$=l!X{H*04k-DCPDmeh8@>cf;IJN-}Z8#N8SeJfylBjPB&=pn-m5njF>M*GBg zr4Q&e7+Zgx^zL0l?t^PwCN<1&y4kLC$S~<2$X5K2mwS%u+ksgbGp6tzQ+p&`-X`^f z!LBhhfki=TPP~q~R9_>zLr%k4!3Tmnw#=|xwJGzW!B)B(fmypZh z+d+*YpEW<^+`q;)JxOj0rwk)=^qgIX9dcRydY&^)o`3EEH;24`k2G(~5n$Lcc)I$z JtaD0e0svV`o;?5n literal 0 HcmV?d00001 diff --git a/tools/editor/icons/icon_reload.png b/tools/editor/icons/icon_reload.png index a79cd1154601e9180b1cc1b6fc1f607db7bcf4de..07f53efb56ea9659a02f914017f9be03da85595a 100644 GIT binary patch delta 499 zcmV_C zX>@2HM@dakSAh-}0004>NklK7fG;h8vie z>f%CW1V`QO>Z_kZPJ z7kBX+2mS7Y*Vk|jyLf^dy^Rx`$2*jiu-tRK|AP|@a+BdY7TN*X)AECz817nt+f!>SR%(yS ydGMxOqyO@v;xIn$2Y4918+zm_e{sqee{1jQIe1ZqxT^dB0000cast_to()->set_flag(GeometryInstance::FLAG_USE_BAKED_LIGHT,true); } } break; case Collada::Node::TYPE_SKELETON: { diff --git a/tools/editor/io_plugins/editor_texture_import_plugin.cpp b/tools/editor/io_plugins/editor_texture_import_plugin.cpp index 4da712c7b3..5d45594246 100644 --- a/tools/editor/io_plugins/editor_texture_import_plugin.cpp +++ b/tools/editor/io_plugins/editor_texture_import_plugin.cpp @@ -732,6 +732,7 @@ Error EditorTextureImportPlugin::import2(const String& p_path, const Refhas_option("shrink")) shrink=from->get_option("shrink"); @@ -1073,11 +1074,11 @@ Vector EditorTextureImportPlugin::custom_export(const String& p_path, c int flags=0; - if (Globals::get_singleton()->get("texture_import/filter")) + if (Globals::get_singleton()->get("image_loader/filter")) flags|=IMAGE_FLAG_FILTER; - if (!Globals::get_singleton()->get("texture_import/gen_mipmaps")) + if (!Globals::get_singleton()->get("image_loader/gen_mipmaps")) flags|=IMAGE_FLAG_NO_MIPMAPS; - if (!Globals::get_singleton()->get("texture_import/repeat")) + if (!Globals::get_singleton()->get("image_loader/repeat")) flags|=IMAGE_FLAG_REPEAT; flags|=IMAGE_FLAG_FIX_BORDER_ALPHA; @@ -1102,11 +1103,11 @@ Vector EditorTextureImportPlugin::custom_export(const String& p_path, c int flags=0; - if (Globals::get_singleton()->get("texture_import/filter")) + if (Globals::get_singleton()->get("image_loader/filter")) flags|=IMAGE_FLAG_FILTER; - if (!Globals::get_singleton()->get("texture_import/gen_mipmaps")) + if (!Globals::get_singleton()->get("image_loader/gen_mipmaps")) flags|=IMAGE_FLAG_NO_MIPMAPS; - if (!Globals::get_singleton()->get("texture_import/repeat")) + if (!Globals::get_singleton()->get("image_loader/repeat")) flags|=IMAGE_FLAG_REPEAT; flags|=IMAGE_FLAG_FIX_BORDER_ALPHA; @@ -1147,10 +1148,13 @@ Vector EditorTextureImportPlugin::custom_export(const String& p_path, c MD5Update(&ctx,&shrink,1); MD5Final(&ctx); + + uint64_t sd=0; String smd5; String md5 = String::md5(ctx.digest); + print_line(p_path+" MD5: "+md5+" FLAGS: "+itos(flags)); String tmp_path = EditorSettings::get_singleton()->get_settings_path().plus_file("tmp/"); diff --git a/tools/editor/plugins/baked_light_baker.cpp b/tools/editor/plugins/baked_light_baker.cpp new file mode 100644 index 0000000000..ae5746321a --- /dev/null +++ b/tools/editor/plugins/baked_light_baker.cpp @@ -0,0 +1,1765 @@ + +#include "baked_light_baker.h" +#include +#include +#include "io/marshalls.h" +#include "tools/editor/editor_node.h" + + +BakedLightBaker::MeshTexture* BakedLightBaker::_get_mat_tex(const Ref& p_tex) { + + if (!tex_map.has(p_tex)) { + + Ref imgtex=p_tex; + if (imgtex.is_null()) + return NULL; + Image image=imgtex->get_data(); + if (image.empty()) + return NULL; + + if (image.get_format()!=Image::FORMAT_RGBA) { + if (image.get_format()>Image::FORMAT_INDEXED_ALPHA) { + Error err = image.decompress(); + if (err) + return NULL; + } + + if (image.get_format()!=Image::FORMAT_RGBA) + image.convert(Image::FORMAT_RGBA); + } + + DVector dvt=image.get_data(); + DVector::Read r=dvt.read(); + MeshTexture mt; + mt.tex_w=image.get_width(); + mt.tex_h=image.get_height(); + int len = image.get_width()*image.get_height()*4; + mt.tex.resize(len); + copymem(mt.tex.ptr(),r.ptr(),len); + + textures.push_back(mt); + tex_map[p_tex]=&textures.back()->get(); + } + + return tex_map[p_tex]; +} + + +void BakedLightBaker::_add_mesh(const Ref& p_mesh,const Ref& p_mat_override,const Transform& p_xform) { + + + for(int i=0;iget_surface_count();i++) { + + if (p_mesh->surface_get_primitive_type(i)!=Mesh::PRIMITIVE_TRIANGLES) + continue; + Ref mat = p_mat_override.is_valid()?p_mat_override:p_mesh->surface_get_material(i); + + MeshMaterial *matptr=NULL; + + if (mat.is_valid()) { + + if (!mat_map.has(mat)) { + + MeshMaterial mm; + + Ref fm = mat; + if (fm.is_valid()) { + //fixed route + mm.diffuse.color=fm->get_parameter(FixedMaterial::PARAM_DIFFUSE); + mm.diffuse.tex=_get_mat_tex(fm->get_texture(FixedMaterial::PARAM_DIFFUSE)); + mm.specular.color=fm->get_parameter(FixedMaterial::PARAM_SPECULAR); + mm.specular.tex=_get_mat_tex(fm->get_texture(FixedMaterial::PARAM_SPECULAR)); + } else { + + mm.diffuse.color=Color(1,1,1,1); + mm.diffuse.tex=NULL; + mm.specular.color=Color(0,0,0,1); + mm.specular.tex=NULL; + } + + materials.push_back(mm); + mat_map[mat]=&materials.back()->get(); + + } + + matptr=mat_map[mat]; + + } + + + int facecount=0; + + + if (p_mesh->surface_get_format(i)&Mesh::ARRAY_FORMAT_INDEX) { + + facecount=p_mesh->surface_get_array_index_len(i); + } else { + + facecount=p_mesh->surface_get_array_len(i); + } + + ERR_CONTINUE((facecount==0 || (facecount%3)!=0)); + + facecount/=3; + + int tbase=triangles.size(); + triangles.resize(facecount+tbase); + + + Array a = p_mesh->surface_get_arrays(i); + + DVector vertices = a[Mesh::ARRAY_VERTEX]; + DVector::Read vr=vertices.read(); + DVector uv; + DVector::Read uvr; + DVector normal; + DVector::Read normalr; + bool read_uv=false; + bool read_normal=false; + + if (p_mesh->surface_get_format(i)&Mesh::ARRAY_FORMAT_TEX_UV) { + + uv=a[Mesh::ARRAY_TEX_UV]; + uvr=uv.read(); + read_uv=true; + } + + if (p_mesh->surface_get_format(i)&Mesh::ARRAY_FORMAT_NORMAL) { + + normal=a[Mesh::ARRAY_NORMAL]; + normalr=normal.read(); + read_normal=true; + } + + Matrix3 normal_xform = p_xform.basis.inverse().transposed(); + + + if (p_mesh->surface_get_format(i)&Mesh::ARRAY_FORMAT_INDEX) { + + DVector indices = a[Mesh::ARRAY_INDEX]; + DVector::Read ir = indices.read(); + + for(int i=0;icast_to()) { + + MeshInstance *meshi=p_node->cast_to(); + Ref mesh=meshi->get_mesh(); + if (mesh.is_valid()) { + _add_mesh(mesh,meshi->get_material_override(),base_inv * meshi->get_global_transform()); + } + } else if (p_node->cast_to()) { + + Light *dl=p_node->cast_to(); + + if (dl->get_bake_mode()!=Light::BAKE_MODE_DISABLED) { + + + LightData dirl; + dirl.type=VS::LightType(dl->get_light_type()); + dirl.diffuse=dl->get_color(DirectionalLight::COLOR_DIFFUSE); + dirl.specular=dl->get_color(DirectionalLight::COLOR_SPECULAR); + dirl.energy=dl->get_parameter(DirectionalLight::PARAM_ENERGY); + dirl.pos=dl->get_global_transform().origin; + dirl.up=dl->get_global_transform().basis.get_axis(1).normalized(); + dirl.left=dl->get_global_transform().basis.get_axis(0).normalized(); + dirl.dir=-dl->get_global_transform().basis.get_axis(2).normalized(); + dirl.spot_angle=dl->get_parameter(DirectionalLight::PARAM_SPOT_ANGLE); + dirl.spot_attenuation=dl->get_parameter(DirectionalLight::PARAM_SPOT_ATTENUATION); + dirl.attenuation=dl->get_parameter(DirectionalLight::PARAM_ATTENUATION); + dirl.radius=dl->get_parameter(DirectionalLight::PARAM_RADIUS); + dirl.bake_direct=dl->get_bake_mode()==Light::BAKE_MODE_FULL; + dirl.rays_thrown=0; + lights.push_back(dirl); + } + + } else if (p_node->cast_to()){ + + Spatial *sp = p_node->cast_to(); + + Array arr = p_node->call("_get_baked_light_meshes"); + for(int i=0;i mesh=arr[i+1]; + _add_mesh(mesh,Ref(),base_inv * (sp->get_global_transform() * xform)); + } + } + + for(int i=0;iget_child_count();i++) { + + _parse_geometry(p_node->get_child(i)); + } +} + + +void BakedLightBaker::_fix_lights() { + + + total_light_area=0; + for(int i=0;iup_max) + up_max=up_d; + if (up_dleft_max) + left_max=left_d; + if (left_ddir_max) + dir_max=dir_d; + if (dir_dmax_depth) { + max_depth=p_depth; + } + + if (p_size==1) { + + return p_children[0]; + } else if (p_size==0) { + + return NULL; + } + + + AABB aabb; + aabb=p_children[0]->aabb; + for(int i=1;iaabb); + } + + int li=aabb.get_longest_axis_index(); + + switch(li) { + + case Vector3::AXIS_X: { + SortArray sort_x; + sort_x.nth_element(0,p_size,p_size/2,p_children); + //sort_x.sort(&p_bb[p_from],p_size); + } break; + case Vector3::AXIS_Y: { + SortArray sort_y; + sort_y.nth_element(0,p_size,p_size/2,p_children); + //sort_y.sort(&p_bb[p_from],p_size); + } break; + case Vector3::AXIS_Z: { + SortArray sort_z; + sort_z.nth_element(0,p_size,p_size/2,p_children); + //sort_z.sort(&p_bb[p_from],p_size); + + } break; + } + + + BVH* left = _parse_bvh(p_children,p_size/2,p_depth+1,max_depth); + BVH* right = _parse_bvh(&p_children[p_size/2],p_size-p_size/2,p_depth+1,max_depth); + + BVH *_new = memnew(BVH); + _new->aabb=aabb; + _new->center=aabb.pos+aabb.size*0.5; + _new->children[0]=left; + _new->children[1]=right; + _new->leaf=NULL; + + return _new; +} + +void BakedLightBaker::_make_bvh() { + + Vector bases; + bases.resize(triangles.size()); + int max_depth=0; + for(int i=0;ileaf=&triangles[i]; + bases[i]->aabb.pos=triangles[i].vertices[0]; + bases[i]->aabb.expand_to(triangles[i].vertices[1]); + bases[i]->aabb.expand_to(triangles[i].vertices[2]); + triangles[i].aabb=bases[i]->aabb; + bases[i]->center=bases[i]->aabb.pos+bases[i]->aabb.size*0.5; + } + + bvh=_parse_bvh(bases.ptr(),bases.size(),1,max_depth); + ray_stack = memnew_arr(uint32_t,max_depth); + bvh_stack = memnew_arr(BVH*,max_depth); +} + +void BakedLightBaker::_octree_insert(int p_octant,Triangle* p_triangle, int p_depth) { + + + + + uint32_t *stack=octant_stack; + uint32_t *ptr_stack=octantptr_stack; + Octant *octants=octant_pool.ptr(); + + stack[0]=0; + ptr_stack[0]=0; + + int stack_pos=0; + + + while(true) { + + Octant *octant=&octants[ptr_stack[stack_pos]]; + if (stack[stack_pos]<8) { + + int i = stack[stack_pos]; + stack[stack_pos]++; + + + + //fit_aabb=fit_aabb.grow(bvh->aabb.size.x*0.0001); + + int child_idx =octant->children[i]; + bool encloses; + if (!child_idx) { + + AABB aabb=octant->aabb; + aabb.size*=0.5; + if (i&1) + aabb.pos.x+=aabb.size.x; + if (i&2) + aabb.pos.y+=aabb.size.y; + if (i&4) + aabb.pos.z+=aabb.size.z; + + aabb.grow_by(cell_size*octree_extra_margin); + if (!aabb.intersects(p_triangle->aabb)) + continue; + encloses=aabb.grow(cell_size*-octree_extra_margin*2.0).encloses(p_triangle->aabb); + if (!encloses && !Face3(p_triangle->vertices[0],p_triangle->vertices[1],p_triangle->vertices[2]).intersects_aabb2(aabb)) + continue; + } else { + + Octant *child=&octants[child_idx]; + AABB aabb=child->aabb; + aabb.grow_by(cell_size*octree_extra_margin); + if (!aabb.intersects(p_triangle->aabb)) + continue; + encloses=aabb.grow(cell_size*-octree_extra_margin*2.0).encloses(p_triangle->aabb); + if (!encloses && !Face3(p_triangle->vertices[0],p_triangle->vertices[1],p_triangle->vertices[2]).intersects_aabb2(aabb)) + continue; + + } + + if (encloses) + stack[stack_pos]=8; // quick and dirty opt + + if (!child_idx) { + + + if (octant_pool_size==octant_pool.size()) { + octant_pool.resize(octant_pool_size+OCTANT_POOL_CHUNK); + octants=octant_pool.ptr(); + octant=&octants[ptr_stack[stack_pos]]; + } + child_idx=octant_pool_size++; + octant->children[i]=child_idx; + Octant *child=&octants[child_idx]; + + child->aabb=octant->aabb; + child->texture_x=0; + child->texture_y=0; + + child->aabb.size*=0.5; + if (i&1) + child->aabb.pos.x+=child->aabb.size.x; + if (i&2) + child->aabb.pos.y+=child->aabb.size.y; + if (i&4) + child->aabb.pos.z+=child->aabb.size.z; + + + + if (stack_pos==octree_depth-1) { + child->leaf=true; + child->offset[0]=child->aabb.pos.x+child->aabb.size.x*0.5; + child->offset[1]=child->aabb.pos.y+child->aabb.size.y*0.5; + child->offset[2]=child->aabb.pos.z+child->aabb.size.z*0.5; + child->next_leaf=leaf_list; + + for(int ci=0;ci<8;ci++) { + child->normal_accum[ci][0]=0; + child->normal_accum[ci][1]=0; + child->normal_accum[ci][2]=0; + } + + child->bake_neighbour=0; + child->first_neighbour=true; + leaf_list=child_idx; + cell_count++; + + int lz = lights.size(); + child->light = memnew_arr(OctantLight,lz); + + for(int li=0;lilight[li].accum[ci][0]=0; + child->light[li].accum[ci][1]=0; + child->light[li].accum[ci][2]=0; + } + } + + child->parent=ptr_stack[stack_pos]; + + } else { + + child->leaf=false; + for(int j=0;j<8;j++) { + child->children[j]=0; + } + } + } + + if (!octants[child_idx].leaf) { + stack_pos++; + stack[stack_pos]=0; + ptr_stack[stack_pos]=child_idx; + } else { + + Octant *child=&octants[child_idx]; + + Vector3 n = Plane(p_triangle->vertices[0],p_triangle->vertices[1],p_triangle->vertices[2]).normal; + + + for(int ci=0;ci<8;ci++) { + + Vector3 pos = child->aabb.pos; + + if (ci&1) + pos.x+=child->aabb.size.x; + if (ci&2) + pos.y+=child->aabb.size.y; + if (ci&4) + pos.z+=child->aabb.size.z; + + + pos.x=floor((pos.x+cell_size*0.5)/cell_size); + pos.y=floor((pos.y+cell_size*0.5)/cell_size); + pos.z=floor((pos.z+cell_size*0.5)/cell_size); + + Map::Element *E=endpoint_normal.find(pos); + if (!E) { + endpoint_normal[pos]=n; + } else { + E->get()+=n; + } + + } + + } + + + } else { + stack_pos--; + if (stack_pos<0) + break; + } + } + + +} + + +void BakedLightBaker::_make_octree() { + + + AABB base = bvh->aabb; + float lal=base.get_longest_axis_size(); + //must be square because we want square blocks + base.size.x=lal; + base.size.y=lal; + base.size.z=lal; + base.grow_by(lal*0.001); //for precision + octree_aabb=base; + + cell_size=base.size.x; + for(int i=0;ileaf=false; + root->aabb=octree_aabb; + root->parent=-1; + for(int i=0;i<8;i++) + root->children[i]=0; + + EditorProgress ep("bake_octree","Parsing "+itos(triangles.size())+" Triangles:",triangles.size()); + + for(int i=0;iaabb.pos; + + if (ci&1) + pos.x+=oct->aabb.size.x; + if (ci&2) + pos.y+=oct->aabb.size.y; + if (ci&4) + pos.z+=oct->aabb.size.z; + + + pos.x=floor((pos.x+cell_size*0.5)/cell_size); + pos.y=floor((pos.y+cell_size*0.5)/cell_size); + pos.z=floor((pos.z+cell_size*0.5)/cell_size); + + Map::Element *E=endpoint_normal.find(pos); + if (!E) { + //? + print_line("lolwut?"); + } else { + Vector3 n = E->get().normalized(); + oct->normal_accum[ci][0]=n.x; + oct->normal_accum[ci][1]=n.y; + oct->normal_accum[ci][2]=n.z; + + } + + } + + oct_idx=oct->next_leaf; + } + } + + +} + + + + + +void BakedLightBaker::_plot_light(int p_light_index, const Vector3& p_plot_pos, const AABB& p_plot_aabb, const Color& p_light, const Plane& p_plane) { + + //stackless version + + uint32_t *stack=octant_stack; + uint32_t *ptr_stack=octantptr_stack; + Octant *octants=octant_pool.ptr(); + + stack[0]=0; + ptr_stack[0]=0; + + int stack_pos=0; + + + while(true) { + + Octant &octant=octants[ptr_stack[stack_pos]]; + + if (octant.leaf) { + + + + //if (p_plane.normal.dot(octant.aabb.get_support(p_plane.normal)) < p_plane.d-CMP_EPSILON) { //octants behind are no go + + + + float r=cell_size*plot_size; + for(int i=0;i<8;i++) { + Vector3 pos=octant.aabb.pos; + if (i&1) + pos.x+=octant.aabb.size.x; + if (i&2) + pos.y+=octant.aabb.size.y; + if (i&4) + pos.z+=octant.aabb.size.z; + + + + float d = p_plot_pos.distance_to(pos); + + if (d<=r) { + + + float intensity = 1.0 - (d/r)*(d/r); //not gauss but.. + float damp = Math::abs(p_plane.normal.dot(Vector3(octant.normal_accum[i][0],octant.normal_accum[i][1],octant.normal_accum[i][2]))); + intensity*=pow(damp,edge_damp); + //intensity*=1.0-Math::abs(p_plane.distance_to(pos))/(plot_size*cell_size); + octant.light[p_light_index].accum[i][0]+=p_light.r*intensity; + octant.light[p_light_index].accum[i][1]+=p_light.g*intensity; + octant.light[p_light_index].accum[i][2]+=p_light.b*intensity; + } + } + + stack_pos--; + } else if (stack[stack_pos]<8) { + + int i = stack[stack_pos]; + stack[stack_pos]++; + + if (!octant.children[i]) { + continue; + } + + Octant &child=octants[octant.children[i]]; + + if (!child.aabb.intersects(p_plot_aabb)) + continue; + + if (child.aabb.encloses(p_plot_aabb)) { + stack[stack_pos]=8; //don't test the rest + } + + stack_pos++; + stack[stack_pos]=0; + ptr_stack[stack_pos]=octant.children[i]; + } else { + stack_pos--; + if (stack_pos<0) + break; + } + } + + +} + + +float BakedLightBaker::_throw_ray(int p_light_index,const Vector3& p_begin, const Vector3& p_end,float p_rest,const Color& p_light,float *p_att_curve,float p_att_pos,int p_att_curve_len,int p_bounces,bool p_first_bounce) { + + + uint32_t* stack = ray_stack; + BVH **bstack = bvh_stack; + + enum { + TEST_AABB_BIT=0, + VISIT_LEFT_BIT=1, + VISIT_RIGHT_BIT=2, + VISIT_DONE_BIT=3, + + + }; + + Vector3 n = (p_end-p_begin); + float len=n.length(); + if (len==0) + return 0; + n/=len; + + + real_t d=1e10; + bool inters=false; + Vector3 r_normal; + Vector3 r_point; + Vector3 end=p_end; + + Triangle *triangle=NULL; + + //for(int i=0;ivertices[0],b.leaf->vertices[1],b.leaf->vertices[2]); + + + Vector3 res; + + if (f3.intersects_segment(p_begin,end,&res)) { + + + float nd = n.dot(res); + if (ndget_uv_and_normal(r_point,uv,r_normal); + + } else { + + } + + if (n.dot(r_normal)>0) + r_normal=-r_normal; + + + //ok... + Color diffuse_at_point(0.8,0.8,0.8); + Color specular_at_point(0.0,0.0,0.0); + + if (triangle->material) { + + //triangle->get_uv(r_point); + diffuse_at_point=triangle->material->diffuse.get_color(uv); + specular_at_point=triangle->material->specular.get_color(uv); + } + + float dist = p_begin.distance_to(r_point); + + AABB aabb; + aabb.pos=r_point; + aabb.pos-=Vector3(1,1,1)*cell_size*plot_size; + aabb.size=Vector3(2,2,2)*cell_size*plot_size; + + Color res_light=p_light; + float att=1.0; + float dp=(1.0-normal_damp)*n.dot(-r_normal)+normal_damp; + + if (p_att_curve) { + + p_att_pos+=dist; + int cpos = Math::fast_ftoi((p_att_pos/p_att_curve_len)*ATTENUATION_CURVE_LEN); + cpos=CLAMP(cpos,0,ATTENUATION_CURVE_LEN-1); + att=p_att_curve[cpos]; + } + + + res_light.r*=dp; + res_light.g*=dp; + res_light.b*=dp; + + //light is plotted before multiplication with diffuse, this way + //the multiplication can happen with more detail in the shader + + + float ret=1e6; + + if (p_bounces>0) { + + + p_rest-=dist; + if (p_restCMP_EPSILON || diffuse_at_point.g>CMP_EPSILON || diffuse_at_point.b>CMP_EPSILON)) { + //diffuse bounce + + Vector3 c1=r_normal.cross(n).normalized(); + Vector3 c2=r_normal.cross(c1).normalized(); + double r1 = double(rand())/RAND_MAX; + double r2 = double(rand())/RAND_MAX; + double r3 = double(rand())/RAND_MAX; +#if 0 + Vector3 next = - ((c1*(r1-0.5)) + (c2*(r2-0.5)) + (r_normal*(r3-0.5))).normalized()*0.5 + r_normal*0.5; + + if (next==Vector3()) + next=r_normal; + Vector3 rn=next.normalized(); + +#else + Vector3 rn = ((c1*(r1-0.5)) + (c2*(r2-0.5)) + (r_normal*r3*0.5)).normalized(); +#endif + + + ret=_throw_ray(p_light_index,r_point,r_point+rn*p_rest,p_rest,diffuse_at_point,p_att_curve,p_att_pos,p_att_curve_len,p_bounces-1); + } + + if (use_specular && (specular_at_point.r>CMP_EPSILON || specular_at_point.g>CMP_EPSILON || specular_at_point.b>CMP_EPSILON)) { + //specular bounce + + //Vector3 c1=r_normal.cross(n).normalized(); + //Vector3 c2=r_normal.cross(c1).normalized(); + + Vector3 rn = n - r_normal *r_normal.dot(n) * 2.0; + + _throw_ray(p_light_index,r_point,r_point+rn*p_rest,p_rest,specular_at_point,p_att_curve,p_att_pos,p_att_curve_len,p_bounces-1); + } + } + + //specular later +// _plot_light_point(r_point,octree,octree_aabb,p_light); + + + Color plot_light=res_light; + plot_light.r*=att; + plot_light.g*=att; + plot_light.b*=att; + + if (!p_first_bounce) { + + + float r = plot_size * cell_size; + if (ret octant_hashing; + octant_hashing.resize(octant_pool_size); + Vector hash_table; + int hash_table_size=Math::larger_prime(16384); + hash_table.resize(hash_table_size); + uint32_t*hashptr = hash_table.ptr(); + OctantHash*octhashptr = octant_hashing.ptr(); + + for(int i=0;iaabb.pos - octree_aabb.pos; //make sure is always positive + base=int((pos.x+cell_size*0.5)/cell_size); + base<<=16; + base|=int((pos.y+cell_size*0.5)/cell_size); + base<<=16; + base|=int((pos.z+cell_size*0.5)/cell_size); + + uint32_t hash = HashMapHahserDefault::hash(base); + uint32_t idx = hash % hash_table_size; + octhashptr[oct_idx].next=hashptr[idx]; + octhashptr[oct_idx].hash=hash; + octhashptr[oct_idx].value=base; + hashptr[idx]=oct_idx; + + oct_idx=oct->next_leaf; + + } + + //step 2 find neighbours + oct_idx=leaf_list; + int neighbours=0; + + + while(oct_idx) { + + BakedLightBaker::Octant *oct = &octants[oct_idx]; + Vector3 pos = oct->aabb.pos - octree_aabb.pos; //make sure is always positive + pos.x+=cell_size; + uint64_t base=0; + base=int((pos.x+cell_size*0.5)/cell_size); + base<<=16; + base|=int((pos.y+cell_size*0.5)/cell_size); + base<<=16; + base|=int((pos.z+cell_size*0.5)/cell_size); + + uint32_t hash = HashMapHahserDefault::hash(base); + uint32_t idx = hash % hash_table_size; + + uint32_t bucket = hashptr[idx]; + + while(bucket) { + + if (octhashptr[bucket].value==base) { + + oct->bake_neighbour=bucket; + octants[bucket].first_neighbour=false; + neighbours++; + break; + } + + bucket = octhashptr[bucket].next; + } + + oct_idx=oct->next_leaf; + + } + + print_line("octant with neighbour: "+itos(neighbours)); + + } + + + //ok let's try to just create a texture + + { + + int otex_w=(1<texture_x=0; + oct->texture_y=0; + oct_idx=oct->next_leaf; + + } + + oct_idx=leaf_list; + + + print_line("begin at row "+itos(row)); + int longest_line_reused=0; + int col=0; + int processed=0; + + while(oct_idx) { + + BakedLightBaker::Octant *oct = &octants[oct_idx]; + if (oct->first_neighbour && oct->texture_x==0 && oct->texture_y==0) { + //was not processed + uint32_t current_idx=oct_idx; + int reused=0; + + while(current_idx) { + BakedLightBaker::Octant *o = &octants[current_idx]; + if (col+1 >= otex_w) { + col=0; + row+=4; + } + o->texture_x=col; + o->texture_y=row; + processed++; + + if (o->bake_neighbour) { + reused++; + } + col+=o->bake_neighbour ? 1 : 2; //reuse neighbour + current_idx=o->bake_neighbour; + } + + if (reused>longest_line_reused) { + longest_line_reused=reused; + } + } + oct_idx=oct->next_leaf; + } + + print_line("processed "+itos(processed)); + + print_line("longest reused: "+itos(longest_line_reused)); + + col=0; + row+=4; + print_line("end at row "+itos(row)); + + //put octree, no need for recursion, just loop backwards. + int regular_octants=0; + for(int i=octant_pool_size-1;i>=0;i--) { + + BakedLightBaker::Octant *oct = &octants[i]; + if (oct->leaf) //ignore leaf + continue; + if (oct->aabb.size.x>lattice_cell_size.x*1.1) { //bigger than latice, skip + oct->texture_x=0; + oct->texture_y=0; + } else if (oct->aabb.size.x>lattice_cell_size.x*0.8) { + //this is the initial lattice + Vector3 pos = oct->aabb.pos - octree_aabb.pos; //make sure is always positive + int x = int((pos.x+lattice_cell_size.x*0.5)/lattice_cell_size.x); + int y = int((pos.y+lattice_cell_size.y*0.5)/lattice_cell_size.y); + int z = int((pos.z+lattice_cell_size.z*0.5)/lattice_cell_size.z); + //bug net + ERR_FAIL_INDEX(x,(1<texture_x=ofs%otex_w; + oct->texture_y=(ofs/otex_w)*4+4; + */ + + oct->texture_x=(x+(1<texture_y=4+y*4; + //print_line("pos: "+itos(x)+","+itos(y)+","+itos(z)+" - ofs"+itos(oct->texture_x)+","+itos(oct->texture_y)); + + + } else { + //an everyday regular octant + + if (col+2 > otex_w) { + col=0; + row+=4; + } + + oct->texture_x=col; + oct->texture_y=row; + col+=2; + regular_octants++; + + + } + } + print_line("octants end at row "+itos(row)+" totalling"+itos(regular_octants)); + + //ok evaluation. + + if (otex_w<=2048 && row>2048) { //too big upwards, try bigger texture + otex_w*=2; + continue; + } else { + baked_octree_texture_w=otex_w; + baked_octree_texture_h=row+4; + break; + } + + } + + + } + + + baked_octree_texture_h=nearest_power_of_2(baked_octree_texture_h); + print_line("RESULT! "+itos(baked_octree_texture_w)+","+itos(baked_octree_texture_h)); + +} + + + + + + + + +double BakedLightBaker::get_normalization(int p_light_idx) const { + + double nrg=0; + + const LightData &dl=lights[p_light_idx]; + double cell_area = cell_size*cell_size;; + //nrg+= /*dl.energy */ (dl.rays_thrown * cell_area / dl.area); + nrg=dl.rays_thrown * cell_area; + nrg*=(Math_PI*plot_size*plot_size)*0.5; // damping of radial linear gradient kernel + nrg*=dl.constant; + //nrg*=5; + print_line("CS: "+rtos(cell_size)); + + return nrg; +} + +void BakedLightBaker::throw_rays(int p_amount) { + + + + for(int i=0;i &p_light, Node* p_node) { + + if (baking) + return; + cell_count=0; + + base_inv=p_node->cast_to()->get_global_transform().affine_inverse(); + EditorProgress ep("bake","Light Baker Setup:",5); + baked_light=p_light; + lattice_size=baked_light->get_initial_lattice_subdiv(); + octree_depth=baked_light->get_cell_subdivision(); + plot_size=baked_light->get_plot_size(); + max_bounces=baked_light->get_bounces(); + use_diffuse=baked_light->get_bake_flag(BakedLight::BAKE_DIFFUSE); + use_specular=baked_light->get_bake_flag(BakedLight::BAKE_SPECULAR); + use_translucency=baked_light->get_bake_flag(BakedLight::BAKE_TRANSLUCENT); + + edge_damp=baked_light->get_edge_damp(); + normal_damp=baked_light->get_normal_damp(); + octree_extra_margin=baked_light->get_cell_extra_margin(); + + + + ep.step("Parsing Geometry",0); + _parse_geometry(p_node); + mat_map.clear(); + tex_map.clear(); + print_line("\ttotal triangles: "+itos(triangles.size())); + ep.step("Fixing Lights",1); + _fix_lights(); + ep.step("Making BVH",2); + _make_bvh(); + ep.step("Creating Light Octree",3); + _make_octree(); + ep.step("Creating Octree Texture",4); + _make_octree_texture(); + baking=true; + _start_thread(); + +} + + +void BakedLightBaker::update_octree_image(DVector &p_image) { + + + int len = baked_octree_texture_w*baked_octree_texture_h*4; + p_image.resize(len); + DVector::Write w = p_image.write(); + zeromem(w.ptr(),len); + float gamma = baked_light->get_gamma_adjust(); + float mult = baked_light->get_energy_multiplier(); + + for(int i=0;i norm_arr; + norm_arr.resize(lights.size()); + + for(int i=0;i>8; + iptr[1]=choct.texture_x&0xFF; + iptr[2]=choct.texture_y>>8; + iptr[3]=choct.texture_y&0xFF; + + } + } + + } + + +} + + +void BakedLightBaker::_free_bvh(BVH* p_bvh) { + + if (!p_bvh->leaf) { + if (p_bvh->children[0]) + _free_bvh(p_bvh->children[0]); + if (p_bvh->children[1]) + _free_bvh(p_bvh->children[1]); + } + + memdelete(p_bvh); + +} + + +bool BakedLightBaker::is_baking() { + + return baking; +} + +void BakedLightBaker::set_pause(bool p_pause){ + + if (paused==p_pause) + return; + + paused=p_pause; + + if (paused) { + _stop_thread(); + } else { + _start_thread(); + } +} +bool BakedLightBaker::is_paused() { + + return paused; + +} + +void BakedLightBaker::_bake_thread_func(void *arg) { + + BakedLightBaker *ble = (BakedLightBaker*)arg; + + ble->rays_at_snap_time=ble->total_rays; + ble->snap_time=OS::get_singleton()->get_ticks_usec(); + + while(!ble->bake_thread_exit) { + + ble->throw_rays(1000); + uint64_t t=OS::get_singleton()->get_ticks_usec(); + if (t-ble->snap_time>1000000) { + + double time = (t-ble->snap_time)/1000000.0; + + int rays=ble->total_rays-ble->rays_at_snap_time; + ble->rays_sec=int(rays/time); + ble->snap_time=OS::get_singleton()->get_ticks_usec(); + ble->rays_at_snap_time=ble->total_rays; + } + } + +} + +void BakedLightBaker::_start_thread() { + + if (thread!=NULL) + return; + bake_thread_exit=false; + thread=Thread::create(_bake_thread_func,this); + +} + +void BakedLightBaker::_stop_thread() { + + if (thread==NULL) + return; + bake_thread_exit=true; + Thread::wait_to_finish(thread); + thread=NULL; +} + +void BakedLightBaker::clear() { + + + + _stop_thread(); + + if (bvh) + _free_bvh(bvh); + + if (ray_stack) + memdelete_arr(ray_stack); + if (octant_stack) + memdelete_arr(octant_stack); + if (octantptr_stack) + memdelete_arr(octantptr_stack); + if (bvh_stack) + memdelete_arr(bvh_stack); + + for(int i=0;i(); + total_rays=0; + +} + +BakedLightBaker::BakedLightBaker() { + octree_depth=9; + lattice_size=4; + octant_pool.clear(); + octant_pool_size=0; + bvh=NULL; + leaf_list=0; + cell_count=0; + ray_stack=NULL; + bvh_stack=NULL; + octant_stack=NULL; + octantptr_stack=NULL; + plot_size=2.5; + max_bounces=2; + materials.clear(); + baked_octree_texture_w=0; + baked_octree_texture_h=0; + paused=false; + baking=false; + thread=NULL; + bake_thread_exit=false; + rays_at_snap_time=0; + snap_time=0; + rays_sec=0; + total_rays=0; + +} + +BakedLightBaker::~BakedLightBaker() { + + clear(); +} diff --git a/tools/editor/plugins/baked_light_baker.h b/tools/editor/plugins/baked_light_baker.h new file mode 100644 index 0000000000..99c8211eed --- /dev/null +++ b/tools/editor/plugins/baked_light_baker.h @@ -0,0 +1,316 @@ +#ifndef BAKED_LIGHT_BAKER_H +#define BAKED_LIGHT_BAKER_H + +#include "scene/3d/baked_light_instance.h" +#include "scene/3d/light.h" +#include "scene/3d/mesh_instance.h" +#include "os/thread.h" + +class BakedLightBaker { +public: + + enum { + + ATTENUATION_CURVE_LEN=256, + OCTANT_POOL_CHUNK=1000000 + }; + + struct OctantLight { + + double accum[8][3]; + }; + + struct Octant { + bool leaf; + AABB aabb; + uint16_t texture_x; + uint16_t texture_y; + float normal_accum[8][3]; + int parent; + union { + struct { + int next_leaf; + float offset[3]; + int bake_neighbour; + bool first_neighbour; + OctantLight *light; + }; + int children[8]; + }; + }; + + struct OctantHash { + + int next; + uint32_t hash; + uint64_t value; + + }; + + struct MeshTexture { + + Vector tex; + int tex_w,tex_h; + + _FORCE_INLINE_ void get_color(const Vector2& p_uv,Color& ret) { + + if (tex_w && tex_h) { + + int x = Math::fast_ftoi(Math::fposmod(p_uv.x,1.0)*tex_w); + int y = Math::fast_ftoi(Math::fposmod(p_uv.y,1.0)*tex_w); + x=CLAMP(x,0,tex_w-1); + y=CLAMP(y,0,tex_h-1); + const uint8_t*ptr = &tex[(y*tex_w+x)*4]; + ret.r*=ptr[0]/255.0; + ret.g*=ptr[1]/255.0; + ret.b*=ptr[2]/255.0; + ret.a*=ptr[3]/255.0; + } + } + + }; + + struct Param { + + Color color; + MeshTexture*tex; + _FORCE_INLINE_ Color get_color(const Vector2& p_uv) { + + Color ret=color; + if (tex) + tex->get_color(p_uv,ret); + return ret; + + } + + }; + + struct MeshMaterial { + + Param diffuse; + Param specular; + Param emission; + }; + + struct Triangle { + + AABB aabb; + Vector3 vertices[3]; + Vector2 uvs[3]; + Vector3 normals[3]; + MeshMaterial *material; + + _FORCE_INLINE_ Vector2 get_uv(const Vector3& p_pos) { + + Vector3 v0 = vertices[1] - vertices[0]; + Vector3 v1 = vertices[2] - vertices[0]; + Vector3 v2 = p_pos - vertices[0]; + + float d00 = v0.dot( v0); + float d01 = v0.dot( v1); + float d11 = v1.dot( v1); + float d20 = v2.dot( v0); + float d21 = v2.dot( v1); + float denom = (d00 * d11 - d01 * d01); + if (denom==0) + return uvs[0]; + float v = (d11 * d20 - d01 * d21) / denom; + float w = (d00 * d21 - d01 * d20) / denom; + float u = 1.0f - v - w; + + return uvs[0]*u + uvs[1]*v + uvs[2]*w; + } + + _FORCE_INLINE_ void get_uv_and_normal(const Vector3& p_pos,Vector2& r_uv,Vector3& r_normal) { + + Vector3 v0 = vertices[1] - vertices[0]; + Vector3 v1 = vertices[2] - vertices[0]; + Vector3 v2 = p_pos - vertices[0]; + + float d00 = v0.dot( v0); + float d01 = v0.dot( v1); + float d11 = v1.dot( v1); + float d20 = v2.dot( v0); + float d21 = v2.dot( v1); + float denom = (d00 * d11 - d01 * d01); + if (denom==0) { + r_normal=normals[0]; + r_uv=uvs[0]; + return; + } + float v = (d11 * d20 - d01 * d21) / denom; + float w = (d00 * d21 - d01 * d20) / denom; + float u = 1.0f - v - w; + + r_uv=uvs[0]*u + uvs[1]*v + uvs[2]*w; + r_normal=(normals[0]*u+normals[1]*v+normals[2]*w).normalized(); + } + }; + + + struct BVH { + + AABB aabb; + Vector3 center; + Triangle *leaf; + BVH*children[2]; + }; + + + struct BVHCmpX { + + bool operator()(const BVH* p_left, const BVH* p_right) const { + + return p_left->center.x < p_right->center.x; + } + }; + + struct BVHCmpY { + + bool operator()(const BVH* p_left, const BVH* p_right) const { + + return p_left->center.y < p_right->center.y; + } + }; + struct BVHCmpZ { + + bool operator()(const BVH* p_left, const BVH* p_right) const { + + return p_left->center.z < p_right->center.z; + } + }; + + + struct LightData { + + VS::LightType type; + + Vector3 pos; + Vector3 up; + Vector3 left; + Vector3 dir; + Color diffuse; + Color specular; + float energy; + float length; + int rays_thrown; + + float radius; + float attenuation; + float spot_angle; + float spot_attenuation; + float area; + + float constant; + + bool bake_direct; + + Vector attenuation_table; + + }; + + + Vector lights; + + List materials; + List textures; + + AABB octree_aabb; + Vector octant_pool; + int octant_pool_size; + BVH*bvh; + Vector triangles; + Transform base_inv; + int leaf_list; + int octree_depth; + int cell_count; + uint32_t *ray_stack; + uint32_t *octant_stack; + uint32_t *octantptr_stack; + Map endpoint_normal; + BVH **bvh_stack; + float cell_size; + float plot_size; //multiplied by cell size + float octree_extra_margin; + + int max_bounces; + uint64_t total_rays; + bool use_diffuse; + bool use_specular; + bool use_translucency; + + + int baked_octree_texture_w; + int baked_octree_texture_h; + int lattice_size; + float edge_damp; + float normal_damp; + + bool paused; + bool baking; + + Map,MeshMaterial*> mat_map; + Map,MeshTexture*> tex_map; + + + + MeshTexture* _get_mat_tex(const Ref& p_tex); + void _add_mesh(const Ref& p_mesh,const Ref& p_mat_override,const Transform& p_xform); + void _parse_geometry(Node* p_node); + BVH* _parse_bvh(BVH** p_children,int p_size,int p_depth,int& max_depth); + void _make_bvh(); + void _make_octree(); + void _make_octree_texture(); + void _octree_insert(int p_octant, Triangle* p_triangle, int p_depth); + + + void _free_bvh(BVH* p_bvh); + + void _fix_lights(); + + Ref baked_light; + + + //void _plot_light(const Vector3& p_plot_pos,const AABB& p_plot_aabb,const Color& p_light,int p_octant=0); + void _plot_light(int p_light_index,const Vector3& p_plot_pos,const AABB& p_plot_aabb,const Color& p_light,const Plane& p_plane); + //void _plot_light_point(const Vector3& p_plot_pos, Octant *p_octant, const AABB& p_aabb,const Color& p_light); + + float _throw_ray(int p_light_index,const Vector3& p_begin, const Vector3& p_end,float p_rest,const Color& p_light,float *p_att_curve,float p_att_pos,int p_att_curve_len,int p_bounces,bool p_first_bounce=false); + + + float total_light_area; + uint64_t rays_at_snap_time; + uint64_t snap_time; + int rays_sec; + + + Thread *thread; + bool bake_thread_exit; + static void _bake_thread_func(void *arg); + + void _start_thread(); + void _stop_thread(); +public: + + + void throw_rays(int p_amount); + double get_normalization(int p_light_idx) const; + + void bake(const Ref& p_light,Node *p_base); + bool is_baking(); + void set_pause(bool p_pause); + bool is_paused(); + int get_rays_sec() { return rays_sec; } + + void update_octree_image(DVector &p_image); + + Ref get_baked_light() { return baked_light; } + + void clear(); + + BakedLightBaker(); + ~BakedLightBaker(); + +}; + +#endif // BAKED_LIGHT_BAKER_H diff --git a/tools/editor/plugins/baked_light_editor_plugin.cpp b/tools/editor/plugins/baked_light_editor_plugin.cpp index 77f9d1ed78..4d84b95900 100644 --- a/tools/editor/plugins/baked_light_editor_plugin.cpp +++ b/tools/editor/plugins/baked_light_editor_plugin.cpp @@ -1,831 +1,19 @@ #include "baked_light_editor_plugin.h" #include "scene/gui/box_container.h" #include "scene/3d/mesh_instance.h" -#include "scene/3d/light.h" +#include "io/marshalls.h" +#include "io/resource_saver.h" -class BakedLightBaker { -public: - - enum { - - ATTENUATION_CURVE_LEN=256 - }; - - struct Octant { - bool leaf; - union { - struct { - float light_accum[3]; - float surface_area; - Octant *next_leaf; - float offset[3]; - }; - Octant* children[8]; - }; - }; - - struct Triangle { - - Vector3 vertices[3]; - Vector2 uv[3]; - }; - - - struct BVH { - - AABB aabb; - Vector3 center; - Triangle *leaf; - BVH*children[2]; - }; - - - struct BVHCmpX { - - bool operator()(const BVH* p_left, const BVH* p_right) const { - - return p_left->center.x < p_right->center.x; - } - }; - - struct BVHCmpY { - - bool operator()(const BVH* p_left, const BVH* p_right) const { - - return p_left->center.y < p_right->center.y; - } - }; - struct BVHCmpZ { - - bool operator()(const BVH* p_left, const BVH* p_right) const { - - return p_left->center.z < p_right->center.z; - } - }; - - - struct DirLight { - - - Vector3 pos; - Vector3 up; - Vector3 left; - Vector3 dir; - Color diffuse; - Color specular; - float energy; - float length; - int rays_thrown; - - }; - - AABB octree_aabb; - Octant *octree; - BVH*bvh; - Vector triangles; - Transform base_inv; - Octant *leaf_list; - int octree_depth; - int cell_count; - uint32_t *ray_stack; - BVH **bvh_stack; - float cell_size; - float plot_size; //multiplied by cell size - Vector directional_lights; - int max_bounces; - - - - void _add_mesh(const Ref& p_mesh,const Ref& p_mat_override,const Transform& p_xform); - void _parse_geometry(Node* p_node); - BVH* _parse_bvh(BVH** p_children,int p_size,int p_depth,int& max_depth); - void _make_bvh(); - void _make_octree(); - void _octree_insert(const AABB& p_aabb,Octant *p_octant,Triangle* p_triangle, int p_depth); - - void _free_octree(Octant *p_octant) { - - if (!p_octant->leaf) { - - for(int i=0;i<8;i++) { - if (p_octant->children[i]) - _free_octree(p_octant->children[i]); - } - } - - memdelete(p_octant); - } - - void _free_bvh(BVH* p_bvh) { - - if (!p_bvh->leaf) { - if (p_bvh->children[0]) - _free_bvh(p_bvh->children[0]); - if (p_bvh->children[1]) - _free_bvh(p_bvh->children[1]); - } - - memdelete(p_bvh); - - } - - void _fix_lights(); - - - void _plot_light(const Vector3& p_plot_pos,const AABB& p_plot_aabb, Octant *p_octant, const AABB& p_aabb,const Color& p_light); - void _plot_light_point(const Vector3& p_plot_pos, Octant *p_octant, const AABB& p_aabb,const Color& p_light); - - void _throw_ray(const Vector3& p_from, const Vector3& p_to,const Color& p_light,float *p_att_curve,float p_att_curve_len,int p_bounces); - - - void throw_rays(int p_amount); - float get_normalization() const; - - - void bake(Node *p_base); - - - void clear() { - - if (octree) - _free_octree(octree); - if (bvh) - _free_bvh(bvh); - - if (ray_stack) - memdelete_arr(ray_stack); - if (bvh_stack) - memdelete_arr(bvh_stack); - - octree=NULL; - bvh=NULL; - leaf_list=NULL; - cell_count=0; - ray_stack=NULL; - bvh_stack=NULL; - } - - BakedLightBaker() { - octree_depth=6; - octree=NULL; - bvh=NULL; - leaf_list=NULL; - cell_count=0; - ray_stack=NULL; - bvh_stack=NULL; - plot_size=2; - max_bounces=3; - } - - ~BakedLightBaker() { - - clear(); - } - -}; - - -void BakedLightBaker::_add_mesh(const Ref& p_mesh,const Ref& p_mat_override,const Transform& p_xform) { - - - for(int i=0;iget_surface_count();i++) { - - if (p_mesh->surface_get_primitive_type(i)!=Mesh::PRIMITIVE_TRIANGLES) - continue; - Ref mat = p_mat_override.is_valid()?p_mat_override:p_mesh->surface_get_material(i); - - int facecount=0; - - - if (p_mesh->surface_get_format(i)&Mesh::ARRAY_FORMAT_INDEX) { - - facecount=p_mesh->surface_get_array_index_len(i); - } else { - - facecount=p_mesh->surface_get_array_len(i); - } - - ERR_CONTINUE((facecount==0 || (facecount%3)!=0)); - - facecount/=3; - - int tbase=triangles.size(); - triangles.resize(facecount+tbase); - - - Array a = p_mesh->surface_get_arrays(i); - - DVector vertices = a[Mesh::ARRAY_VERTEX]; - DVector::Read vr=vertices.read(); - - if (p_mesh->surface_get_format(i)&Mesh::ARRAY_FORMAT_INDEX) { - - DVector indices = a[Mesh::ARRAY_INDEX]; - DVector::Read ir = indices.read(); - - for(int i=0;icast_to()) { - - MeshInstance *meshi=p_node->cast_to(); - Ref mesh=meshi->get_mesh(); - if (mesh.is_valid()) { - _add_mesh(mesh,meshi->get_material_override(),base_inv * meshi->get_global_transform()); - } - } - - if (p_node->cast_to()) { - - DirectionalLight *dl=p_node->cast_to(); - - DirLight dirl; - dirl.diffuse=dl->get_color(DirectionalLight::COLOR_DIFFUSE); - dirl.specular=dl->get_color(DirectionalLight::COLOR_SPECULAR); - dirl.energy=dl->get_parameter(DirectionalLight::PARAM_ENERGY); - dirl.pos=dl->get_global_transform().origin; - dirl.up=dl->get_global_transform().basis.get_axis(1).normalized(); - dirl.left=dl->get_global_transform().basis.get_axis(0).normalized(); - dirl.dir=-dl->get_global_transform().basis.get_axis(2).normalized(); - dirl.rays_thrown=0; - directional_lights.push_back(dirl); - - } - - for(int i=0;iget_child_count();i++) { - - _parse_geometry(p_node->get_child(i)); - } -} - - -void BakedLightBaker::_fix_lights() { - - - for(int i=0;iup_max) - up_max=up_d; - if (up_dleft_max) - left_max=left_d; - if (left_ddir_max) - dir_max=dir_d; - if (dir_dmax_depth) { - max_depth=p_depth; - } - - if (p_size==1) { - - return p_children[0]; - } else if (p_size==0) { - - return NULL; - } - - - AABB aabb; - aabb=p_children[0]->aabb; - for(int i=1;iaabb); - } - - int li=aabb.get_longest_axis_index(); - - switch(li) { - - case Vector3::AXIS_X: { - SortArray sort_x; - sort_x.nth_element(0,p_size,p_size/2,p_children); - //sort_x.sort(&p_bb[p_from],p_size); - } break; - case Vector3::AXIS_Y: { - SortArray sort_y; - sort_y.nth_element(0,p_size,p_size/2,p_children); - //sort_y.sort(&p_bb[p_from],p_size); - } break; - case Vector3::AXIS_Z: { - SortArray sort_z; - sort_z.nth_element(0,p_size,p_size/2,p_children); - //sort_z.sort(&p_bb[p_from],p_size); - - } break; - } - - - BVH* left = _parse_bvh(p_children,p_size/2,p_depth+1,max_depth); - BVH* right = _parse_bvh(&p_children[p_size/2],p_size-p_size/2,p_depth+1,max_depth); - - BVH *_new = memnew(BVH); - _new->aabb=aabb; - _new->center=aabb.pos+aabb.size*0.5; - _new->children[0]=left; - _new->children[1]=right; - _new->leaf=NULL; - - return _new; -} - -void BakedLightBaker::_make_bvh() { - - Vector bases; - bases.resize(triangles.size()); - int max_depth=0; - for(int i=0;ileaf=&triangles[i]; - bases[i]->aabb.pos=triangles[i].vertices[0]; - bases[i]->aabb.expand_to(triangles[i].vertices[1]); - bases[i]->aabb.expand_to(triangles[i].vertices[2]); - bases[i]->center=bases[i]->aabb.pos+bases[i]->aabb.size*0.5; - } - - bvh=_parse_bvh(bases.ptr(),bases.size(),1,max_depth); - ray_stack = memnew_arr(uint32_t,max_depth); - bvh_stack = memnew_arr(BVH*,max_depth); -} - -void BakedLightBaker::_octree_insert(const AABB& p_aabb,Octant *p_octant,Triangle* p_triangle, int p_depth) { - - if (p_octant->leaf) { -#if 0 - if (p_aabb.has_point(p_triangle->vertices[0]) && p_aabb.has_point(p_triangle->vertices[1]) &&p_aabb.has_point(p_triangle->vertices[2])) { - //face is completely enclosed, add area - p_octant->surface_area+=Face3(p_triangle->vertices[0],p_triangle->vertices[1],p_triangle->vertices[2]).get_area(); - } else { - //not completely enclosed, will need to be clipped.. - Vector poly; - poly.push_back(p_triangle->vertices[0]); - poly.push_back(p_triangle->vertices[1]); - poly.push_back(p_triangle->vertices[2]); - - //clip - for(int i=0;i<3;i++) { - - //top plane - Plane p(0,0,0,0); - p.normal[i]=1.0; - p.d=p_aabb.pos[i]+p_aabb.size[i]; - poly=Geometry::clip_polygon(poly,p); - - //bottom plane - p.normal[i]=-1.0; - p.d=-p_aabb.pos[i]; - poly=Geometry::clip_polygon(poly,p); - } - - - //calculate area - float clipped_area=0; - for(int i=2;ivertices[0],p_triangle->vertices[1],p_triangle->vertices[2]).get_area())+" clipped: "+rtos(clipped_area)); - p_octant->surface_area+=clipped_area; - } -#endif - } else { - - - for(int i=0;i<8;i++) { - - AABB aabb=p_aabb; - aabb.size*=0.5; - if (i&1) - aabb.pos.x+=aabb.size.x; - if (i&2) - aabb.pos.y+=aabb.size.y; - if (i&4) - aabb.pos.z+=aabb.size.z; - - AABB fit_aabb=aabb; - //fit_aabb=fit_aabb.grow(bvh->aabb.size.x*0.0001); - - if (!Face3(p_triangle->vertices[0],p_triangle->vertices[1],p_triangle->vertices[2]).intersects_aabb(fit_aabb)) - continue; - - if (!p_octant->children[i]) { - p_octant->children[i]=memnew(Octant); - if (p_depth==0) { - p_octant->children[i]->leaf=true; - p_octant->children[i]->light_accum[0]=0; - p_octant->children[i]->light_accum[1]=0; - p_octant->children[i]->light_accum[2]=0; - p_octant->children[i]->offset[0]=aabb.pos.x+aabb.size.x*0.5; - p_octant->children[i]->offset[1]=aabb.pos.y+aabb.size.y*0.5; - p_octant->children[i]->offset[2]=aabb.pos.z+aabb.size.z*0.5; - p_octant->children[i]->surface_area=0; - p_octant->children[i]->next_leaf=leaf_list; - leaf_list=p_octant->children[i]; - cell_count++; - } else { - - p_octant->children[i]->leaf=false; - for(int j=0;j<8;j++) { - p_octant->children[i]->children[j]=0; - } - } - } - - _octree_insert(aabb,p_octant->children[i],p_triangle,p_depth-1); - } - } -} - - -void BakedLightBaker::_make_octree() { - - AABB base = bvh->aabb; - float lal=base.get_longest_axis_size(); - //must be square because we want square blocks - base.size.x=lal; - base.size.y=lal; - base.size.z=lal; - base.grow_by(lal*0.001); //for precision - octree_aabb=base; - - cell_size=base.size.x; - for(int i=0;ileaf=false; - for(int i=0;i<8;i++) - octree->children[i]=NULL; - - for(int i=0;ileaf) { - - float r=cell_size*plot_size; - Vector3 center=p_aabb.pos+p_aabb.size*0.5; - float d = p_plot_pos.distance_to(center); - if (d>r) - return; //oh crap! outside radius - float intensity = 1.0;// - (d/r)*(d/r); //not gauss but.. - p_octant->light_accum[0]+=p_light.r*intensity; - p_octant->light_accum[1]+=p_light.g*intensity; - p_octant->light_accum[2]+=p_light.b*intensity; - - } else { - - for(int i=0;i<8;i++) { - - if (!p_octant->children[i]) - continue; - - AABB aabb=p_aabb; - aabb.size*=0.5; - if (i&1) - aabb.pos.x+=aabb.size.x; - if (i&2) - aabb.pos.y+=aabb.size.y; - if (i&4) - aabb.pos.z+=aabb.size.z; - - - if (!aabb.intersects(p_plot_aabb)) - continue; - - _plot_light(p_plot_pos,p_plot_aabb,p_octant->children[i],aabb,p_light); - - } - - } -} - -void BakedLightBaker::_plot_light_point(const Vector3& p_plot_pos, Octant *p_octant, const AABB& p_aabb,const Color& p_light) { - - - if (p_octant->leaf) { - - p_octant->light_accum[0]+=p_light.r; - p_octant->light_accum[1]+=p_light.g; - p_octant->light_accum[2]+=p_light.b; - - } else { - - for(int i=0;i<8;i++) { - - if (!p_octant->children[i]) - continue; - - AABB aabb=p_aabb; - aabb.size*=0.5; - if (i&1) - aabb.pos.x+=aabb.size.x; - if (i&2) - aabb.pos.y+=aabb.size.y; - if (i&4) - aabb.pos.z+=aabb.size.z; - - - if (!aabb.has_point(p_plot_pos)) - continue; - - _plot_light_point(p_plot_pos,p_octant->children[i],aabb,p_light); - - } - - } -} - - -void BakedLightBaker::_throw_ray(const Vector3& p_begin, const Vector3& p_end,const Color& p_light,float *p_att_curve,float p_att_curve_len,int p_bounces) { - - - uint32_t* stack = ray_stack; - BVH **bstack = bvh_stack; - - enum { - TEST_AABB_BIT=0, - VISIT_LEFT_BIT=1, - VISIT_RIGHT_BIT=2, - VISIT_DONE_BIT=3, - - - }; - - Vector3 n = (p_end-p_begin).normalized(); - real_t d=1e10; - bool inters=false; - Vector3 r_normal; - Vector3 r_point; - - //for(int i=0;ivertices[0],b.leaf->vertices[1],b.leaf->vertices[2]); - - - Vector3 res; - - if (f3.intersects_segment(p_begin,p_end,&res)) { - - - float nd = n.dot(res); - if (nd0) - r_normal=-r_normal; - - //ok... - Color diffuse_at_point(0.8,0.8,0.8); - Color specular_at_point(0.8,0.8,0.8); - - AABB aabb; - aabb.pos=r_point; - aabb.pos-=Vector3(1,1,1)*cell_size*plot_size; - aabb.size=Vector3(2,2,2)*cell_size*plot_size; - - _plot_light(r_point,aabb,octree,octree_aabb,p_light); -// _plot_light_point(r_point,octree,octree_aabb,p_light); - - } - -} - - - - - - -float BakedLightBaker::get_normalization() const { - - float nrg=0; - for(int i=0;iclear(); + set_process(false); + button_bake->set_pressed(false); + bake_info->set_text(""); } void BakedLightEditor::_node_removed(Node *p_node) { @@ -833,71 +21,83 @@ void BakedLightEditor::_node_removed(Node *p_node) { if(p_node==node) { _end_baking(); node=NULL; - p_node->remove_child(preview); - preview->set_mesh(Ref()); + hide(); } } -void BakedLightEditor::_bake_thread_func(void *arg) { - - BakedLightEditor *ble = (BakedLightEditor*)arg; - - while(!ble->bake_thread_exit) { - - ble->baker->throw_rays(1000); - } - -} void BakedLightEditor::_notification(int p_option) { + if (p_option==NOTIFICATION_ENTER_SCENE) { + + button_bake->set_icon(get_icon("Bake","EditorIcons")); + button_reset->set_icon(get_icon("Reload","EditorIcons")); + } + if (p_option==NOTIFICATION_PROCESS) { - if (bake_thread) { + if (baker->is_baking() && !baker->is_paused()) { update_timeout-=get_process_delta_time(); if (update_timeout<0) { + if (baker->get_baked_light()!=node->get_baked_light()) { + _end_baking(); + return; + } + uint64_t t = OS::get_singleton()->get_ticks_msec(); - float norm = baker->get_normalization(); +#ifdef DEBUG_CUBES + double norm = baker->get_normalization(); float max_lum=0; + { DVector::Write cw=colors.write(); - BakedLightBaker::Octant *oct = baker->leaf_list; + BakedLightBaker::Octant *octants=baker->octant_pool.ptr(); + BakedLightBaker::Octant *oct = &octants[baker->leaf_list]; int vert_idx=0; while(oct) { - Color color; - color.r=oct->light_accum[0]/norm; - color.g=oct->light_accum[1]/norm; - color.b=oct->light_accum[2]/norm; - float lum = color.get_v(); - //if (lum<0.05) - // color.a=0; - if (lum>max_lum) - max_lum=lum; + Color colors[8]; + for(int i=0;i<8;i++) { + colors[i].r=oct->light_accum[i][0]/norm; + colors[i].g=oct->light_accum[i][1]/norm; + colors[i].b=oct->light_accum[i][2]/norm; + + float lum = colors[i].get_v(); + //if (lum<0.05) + // color.a=0; + if (lum>max_lum) + max_lum=lum; + + } + static const int vert2cub[36]={7,3,1,1,5,7,7,6,2,2,3,7,7,5,4,4,6,7,2,6,4,4,0,2,4,5,1,1,0,4,1,3,2,2,0,1}; for (int i=0;i<36;i++) { - cw[vert_idx++]=color; + cw[vert_idx++]=colors[vert2cub[i]]; } - oct=oct->next_leaf; + if (oct->next_leaf) + oct=&octants[oct->next_leaf]; + else + oct=NULL; } } - + print_line("MSCOL: "+itos(OS::get_singleton()->get_ticks_msec()-t)); + t = OS::get_singleton()->get_ticks_msec(); Array a; a.resize(Mesh::ARRAY_MAX); @@ -907,8 +107,28 @@ void BakedLightEditor::_notification(int p_option) { mesh->surface_remove(0); mesh->add_surface(Mesh::PRIMITIVE_TRIANGLES,a); mesh->surface_set_material(0,material); +#endif + ERR_FAIL_COND(node->get_baked_light().is_null()); + + baker->update_octree_image(octree_texture); +#if 0 +//debug + Image img(baker->baked_octree_texture_w,baker->baked_octree_texture_h,0,Image::FORMAT_RGBA,octree_texture); + Ref it = memnew( ImageTexture ); + it->create_from_image(img); + ResourceSaver::save("baked_octree.png",it); + + +#endif + bake_info->set_text("rays/s: "+itos(baker->get_rays_sec())); + update_timeout=1; + print_line("MSUPDATE: "+itos(OS::get_singleton()->get_ticks_msec()-t)); + t=OS::get_singleton()->get_ticks_msec(); + node->get_baked_light()->set_octree(octree_texture); + print_line("MSSET: "+itos(OS::get_singleton()->get_ticks_msec()-t)); + + - update_timeout=1; } } } @@ -924,89 +144,11 @@ void BakedLightEditor::_menu_option(int p_option) { case MENU_OPTION_BAKE: { ERR_FAIL_COND(!node); - preview->set_mesh(Ref()); - baker->base_inv=node->get_global_transform().affine_inverse(); - baker->bake(node); + ERR_FAIL_COND(node->get_baked_light().is_null()); + baker->bake(node->get_baked_light(),node); - print_line("CELLS: "+itos(baker->cell_count)); - print_line("cell size: "+rtos(baker->cell_size)); - colors.resize(baker->cell_count*36); - vertices.resize(baker->cell_count*36); - - - { - DVector::Write cw=colors.write(); - DVector::Write vw=vertices.write(); - BakedLightBaker::Octant *oct = baker->leaf_list; - int vert_idx=0; - - while(oct) { - - Color color; - - for (int i=0;i<6;i++) { - - - Vector3 face_points[4]; - for (int j=0;j<4;j++) { - - float v[3]; - v[0]=1.0; - v[1]=1-2*((j>>1)&1); - v[2]=v[1]*(1-2*(j&1)); - - for (int k=0;k<3;k++) { - - if (i<3) - face_points[j][(i+k)%3]=v[k]*(i>=3?-1:1); - else - face_points[3-j][(i+k)%3]=v[k]*(i>=3?-1:1); - } - } - - for(int j=0;j<4;j++) { - face_points[j]*=baker->cell_size*0.5; - face_points[j]+=Vector3(oct->offset[0],oct->offset[1],oct->offset[2]); - } - -#define ADD_VTX(m_idx) \ - vw[vert_idx]=face_points[m_idx]; \ - cw[vert_idx]=color; \ - vert_idx++; - - //tri 1 - ADD_VTX(0); - ADD_VTX(1); - ADD_VTX(2); - //tri 2 - ADD_VTX(2); - ADD_VTX(3); - ADD_VTX(0); - -#undef ADD_VTX - - } - - oct=oct->next_leaf; - } - - - } - - Array a; - a.resize(Mesh::ARRAY_MAX); - a[Mesh::ARRAY_VERTEX]=vertices; - a[Mesh::ARRAY_COLOR]=colors; - while(mesh->get_surface_count()) - mesh->surface_remove(0); - mesh->add_surface(Mesh::PRIMITIVE_TRIANGLES,a); - mesh->surface_set_material(0,material); - - bake_thread_exit=false; update_timeout=0; set_process(true); - bake_thread=Thread::create(_bake_thread_func,this); - preview->set_mesh(mesh); } break; @@ -1019,20 +161,56 @@ void BakedLightEditor::_menu_option(int p_option) { } } +void BakedLightEditor::_bake_pressed() { -void BakedLightEditor::edit(BakedLight *p_baked_light) { - - if (node==p_baked_light) + ERR_FAIL_COND(!node); + if (node->get_baked_light().is_null()) { + err_dialog->set_text("BakedLightInstance does not contain a BakedLight resource."); + err_dialog->popup_centered(Size2(350,70)); + button_bake->set_pressed(false); return; - if (node) { - node->remove_child(preview); } - node=p_baked_light; - _end_baking(); + if (baker->is_baking()) { - if (node) - node->add_child(preview); + baker->set_pause(!button_bake->is_pressed()); + if (baker->is_paused()) { + + set_process(false); + bake_info->set_text(""); + } else { + + update_timeout=0; + set_process(true); + } + + } else { + baker->bake(node->get_baked_light(),node); + update_timeout=0; + set_process(true); + } + +} + +void BakedLightEditor::_clear_pressed(){ + + baker->clear(); + button_bake->set_pressed(false); + bake_info->set_text(""); + +} + +void BakedLightEditor::edit(BakedLightInstance *p_baked_light) { + + if (p_baked_light==NULL || node==p_baked_light) { + return; + } + if (node && node!=p_baked_light) + _end_baking(); + + + node=p_baked_light; + //_end_baking(); } @@ -1041,35 +219,33 @@ void BakedLightEditor::edit(BakedLight *p_baked_light) { void BakedLightEditor::_bind_methods() { ObjectTypeDB::bind_method("_menu_option",&BakedLightEditor::_menu_option); + ObjectTypeDB::bind_method("_bake_pressed",&BakedLightEditor::_bake_pressed); + ObjectTypeDB::bind_method("_clear_pressed",&BakedLightEditor::_clear_pressed); } BakedLightEditor::BakedLightEditor() { - options = memnew( MenuButton ); - - options->set_text("BakedLight"); - options->get_popup()->add_item("Bake..",MENU_OPTION_BAKE); - options->get_popup()->add_item("Clear",MENU_OPTION_CLEAR); - options->get_popup()->connect("item_pressed", this,"_menu_option"); - + bake_hbox = memnew( HBoxContainer ); + button_bake = memnew( ToolButton ); + button_bake->set_text("Bake!"); + button_bake->set_toggle_mode(true); + button_reset = memnew( Button ); + bake_info = memnew( Label ); + bake_hbox->add_child( button_bake ); + bake_hbox->add_child( button_reset ); + bake_hbox->add_child( bake_info ); err_dialog = memnew( AcceptDialog ); add_child(err_dialog); node=NULL; baker = memnew( BakedLightBaker ); - preview = memnew( MeshInstance ); - bake_thread=NULL; + + button_bake->connect("pressed",this,"_bake_pressed"); + button_reset->connect("pressed",this,"_clear_pressed"); + update_timeout=0; - material = Ref ( memnew( FixedMaterial ) ); - material->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY,true); - material->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA,true); - material->set_flag(FixedMaterial::FLAG_UNSHADED,true); - material->set_flag(FixedMaterial::FLAG_DOUBLE_SIDED,true); - material->set_parameter(FixedMaterial::PARAM_DIFFUSE,Color(1,1,1)); - - mesh = Ref( memnew( Mesh )); } @@ -1081,28 +257,24 @@ BakedLightEditor::~BakedLightEditor() { void BakedLightEditorPlugin::edit(Object *p_object) { - baked_light_editor->edit(p_object->cast_to()); + baked_light_editor->edit(p_object->cast_to()); } bool BakedLightEditorPlugin::handles(Object *p_object) const { - return p_object->is_type("BakedLight"); + return p_object->is_type("BakedLightInstance"); } void BakedLightEditorPlugin::make_visible(bool p_visible) { if (p_visible) { baked_light_editor->show(); - baked_light_editor->options->show(); + baked_light_editor->bake_hbox->show(); } else { baked_light_editor->hide(); - baked_light_editor->options->show(); + baked_light_editor->bake_hbox->hide(); baked_light_editor->edit(NULL); - if (baked_light_editor->node) { - baked_light_editor->node->remove_child(baked_light_editor->preview); - baked_light_editor->node=NULL; - } } } @@ -1112,9 +284,9 @@ BakedLightEditorPlugin::BakedLightEditorPlugin(EditorNode *p_node) { editor=p_node; baked_light_editor = memnew( BakedLightEditor ); editor->get_viewport()->add_child(baked_light_editor); - add_custom_control(CONTAINER_SPATIAL_EDITOR_MENU,baked_light_editor->options); + add_custom_control(CONTAINER_SPATIAL_EDITOR_MENU,baked_light_editor->bake_hbox); baked_light_editor->hide(); - baked_light_editor->options->hide(); + baked_light_editor->bake_hbox->hide(); } diff --git a/tools/editor/plugins/baked_light_editor_plugin.h b/tools/editor/plugins/baked_light_editor_plugin.h index 9424503a16..4ecc0b458f 100644 --- a/tools/editor/plugins/baked_light_editor_plugin.h +++ b/tools/editor/plugins/baked_light_editor_plugin.h @@ -3,15 +3,17 @@ #include "tools/editor/editor_plugin.h" #include "tools/editor/editor_node.h" -#include "scene/3d/baked_light.h" +#include "tools/editor/plugins/baked_light_baker.h" #include "scene/gui/spin_box.h" + + /** @author Juan Linietsky */ -class BakedLightBaker; + class MeshInstance; class BakedLightEditor : public Control { @@ -20,20 +22,18 @@ class BakedLightEditor : public Control { float update_timeout; - DVector colors; - DVector vertices; - Ref mesh; - Ref material; + DVector octree_texture; - Thread *bake_thread; - bool bake_thread_exit; - - MeshInstance *preview; BakedLightBaker *baker; AcceptDialog *err_dialog; - MenuButton * options; - BakedLight *node; + HBoxContainer *bake_hbox; + Button *button_bake; + Button *button_reset; + Label *bake_info; + + + BakedLightInstance *node; enum Menu { @@ -41,7 +41,9 @@ class BakedLightEditor : public Control { MENU_OPTION_CLEAR }; - static void _bake_thread_func(void *arg); + void _bake_pressed(); + void _clear_pressed(); + void _end_baking(); void _menu_option(int); @@ -52,7 +54,7 @@ protected: void _notification(int p_what); public: - void edit(BakedLight *p_baked_light); + void edit(BakedLightInstance *p_baked_light); BakedLightEditor(); ~BakedLightEditor(); }; diff --git a/tools/editor/project_export.cpp b/tools/editor/project_export.cpp index aac3837da9..d757a4c07d 100644 --- a/tools/editor/project_export.cpp +++ b/tools/editor/project_export.cpp @@ -232,6 +232,26 @@ void ProjectExportDialog::_format_toggled() { } +void ProjectExportDialog::_script_edited(Variant v) { + + if (updating_script) + return; + updating_script=true; + EditorNode::get_undo_redo()->create_action("Edit Script Options"); + EditorNode::get_undo_redo()->add_do_method(EditorImportExport::get_singleton(),"script_set_action",script_mode->get_selected()); + EditorNode::get_undo_redo()->add_undo_method(EditorImportExport::get_singleton(),"script_set_action",EditorImportExport::get_singleton()->script_get_action()); + EditorNode::get_undo_redo()->add_do_method(EditorImportExport::get_singleton(),"script_set_encryption_key",script_key->get_text()); + EditorNode::get_undo_redo()->add_undo_method(EditorImportExport::get_singleton(),"script_set_encryption_key",EditorImportExport::get_singleton()->script_get_encryption_key()); + EditorNode::get_undo_redo()->add_do_method(this,"_update_script"); + EditorNode::get_undo_redo()->add_undo_method(this,"_update_script"); + EditorNode::get_undo_redo()->add_do_method(this,"_save_export_cfg"); + EditorNode::get_undo_redo()->add_undo_method(this,"_save_export_cfg"); + EditorNode::get_undo_redo()->commit_action(); + updating_script=false; + + +} + void ProjectExportDialog::_notification(int p_what) { switch(p_what) { @@ -277,10 +297,16 @@ void ProjectExportDialog::_notification(int p_what) { image_action->select(EditorImportExport::get_singleton()->get_export_image_action()); image_quality->set_val(EditorImportExport::get_singleton()->get_export_image_quality()); image_shrink->set_val(EditorImportExport::get_singleton()->get_export_image_shrink()); + _update_script(); + + image_quality->connect("value_changed",this,"_quality_edited"); image_shrink->connect("value_changed",this,"_shrink_edited"); image_action->connect("item_selected",this,"_image_export_edited"); + script_mode->connect("item_selected",this,"_script_edited"); + script_key->connect("text_changed",this,"_script_edited"); + for(int i=0;iget_image_formats().has(formats[i]->get_text(0))) formats[i]->set_checked(0,true); @@ -651,10 +677,15 @@ bool ProjectExportDialog::_update_group_treef(TreeItem *p_parent,EditorFileSyste } void ProjectExportDialog::_update_group_tree() { + if (updating) + return; + group_images->clear(); if (_get_selected_group()=="") return; + + updating=true; print_line("****UGT"); List img_extensions; ImageLoader::get_recognized_extensions(&img_extensions); @@ -677,7 +708,7 @@ void ProjectExportDialog::_update_group_tree() { groupenum+=","+String(E->get()); } - + updating=false; _update_group_treef(NULL,EditorFileSystem::get_singleton()->get_filesystem(),extensions,groupenum,group_index); @@ -690,7 +721,7 @@ void ProjectExportDialog::_group_changed(Variant v) { return; if (_get_selected_group()=="") return; - + updating=true; StringName name = _get_selected_group(); EditorNode::get_undo_redo()->create_action("Change Image Group"); EditorNode::get_undo_redo()->add_do_method(EditorImportExport::get_singleton(),"image_export_group_set_image_action",name,group_image_action->get_selected()); @@ -706,6 +737,7 @@ void ProjectExportDialog::_group_changed(Variant v) { EditorNode::get_undo_redo()->add_do_method(this,"_save_export_cfg"); EditorNode::get_undo_redo()->add_undo_method(this,"_save_export_cfg"); EditorNode::get_undo_redo()->commit_action(); + updating=false; } void ProjectExportDialog::_group_item_edited() { @@ -926,11 +958,11 @@ void ProjectExportDialog::_group_atlas_preview() { int flags=0; - if (Globals::get_singleton()->get("texture_import/filter")) + if (Globals::get_singleton()->get("image_loader/filter")) flags|=EditorTextureImportPlugin::IMAGE_FLAG_FILTER; - if (!Globals::get_singleton()->get("texture_import/gen_mipmaps")) + if (!Globals::get_singleton()->get("image_loader/gen_mipmaps")) flags|=EditorTextureImportPlugin::IMAGE_FLAG_NO_MIPMAPS; - if (!Globals::get_singleton()->get("texture_import/repeat")) + if (!Globals::get_singleton()->get("image_loader/repeat")) flags|=EditorTextureImportPlugin::IMAGE_FLAG_REPEAT; flags|=EditorTextureImportPlugin::IMAGE_FLAG_FIX_BORDER_ALPHA; @@ -956,6 +988,17 @@ void ProjectExportDialog::_group_atlas_preview() { } +void ProjectExportDialog::_update_script() { + + if (updating_script) + return; + updating_script=true; + script_mode->select(EditorImportExport::get_singleton()->script_get_action()); + script_key->set_text(EditorImportExport::get_singleton()->script_get_encryption_key()); + updating_script=false; + +} + void ProjectExportDialog::_image_filter_changed(String) { _update_group_tree(); @@ -991,6 +1034,8 @@ void ProjectExportDialog::_bind_methods() { ObjectTypeDB::bind_method(_MD("_group_atlas_preview"),&ProjectExportDialog::_group_atlas_preview); ObjectTypeDB::bind_method(_MD("_group_select_all"),&ProjectExportDialog::_group_select_all); ObjectTypeDB::bind_method(_MD("_group_select_none"),&ProjectExportDialog::_group_select_none); + ObjectTypeDB::bind_method(_MD("_script_edited"),&ProjectExportDialog::_script_edited); + ObjectTypeDB::bind_method(_MD("_update_script"),&ProjectExportDialog::_update_script); ObjectTypeDB::bind_method(_MD("export_platform"),&ProjectExportDialog::export_platform); @@ -1171,7 +1216,7 @@ ProjectExportDialog::ProjectExportDialog(EditorNode *p_editor) { group_lossy_quality->set_step(0.1); group_lossy_quality->set_val(0.7); group_options->add_margin_child("Lossy Quality:",group_lossy_quality); - group_lossy_quality->connect("value_changed",this,"_group_changed"); + group_lossy_quality->connect("value_changed",this,"_quality_edited"); group_atlas = memnew(CheckButton); group_atlas->set_pressed("Generate Atlas"); @@ -1261,6 +1306,18 @@ ProjectExportDialog::ProjectExportDialog(EditorNode *p_editor) { hbc->add_child(button_reload); */ + script_vbox = memnew( VBoxContainer ); + script_vbox->set_name("Script"); + sections->add_child(script_vbox); + script_mode = memnew( OptionButton ); + script_vbox->add_margin_child("Script Export Mode:",script_mode); + script_mode->add_item("Text"); + script_mode->add_item("Compiled"); + script_mode->add_item("Encrypted (Provide Key Below)"); + script_key = memnew( LineEdit ); + script_vbox->add_margin_child("Script Encryption Key (256-bits as hex):",script_key); + + updating=false; @@ -1302,6 +1359,7 @@ ProjectExportDialog::ProjectExportDialog(EditorNode *p_editor) { add_child(pck_export); button_export = add_button("Export..",!OS::get_singleton()->get_swap_ok_cancel(),"export_pck"); + updating_script=false; } diff --git a/tools/editor/project_export.h b/tools/editor/project_export.h index 6ceffadc62..dfe7a2d900 100644 --- a/tools/editor/project_export.h +++ b/tools/editor/project_export.h @@ -132,6 +132,12 @@ private: TextureFrame *atlas_preview_frame; + VBoxContainer *script_vbox; + OptionButton *script_mode; + LineEdit *script_key; + + + void _export_mode_changed(int p_idx); void _prop_edited(String what); @@ -166,6 +172,9 @@ private: void _group_select_none(); void _group_del(Object *item,int p_column, int p_button); + bool updating_script; + void _update_script(); + void _script_edited(Variant v); void _export_action(const String& p_file); void _export_action_pck(const String& p_file); void ok_pressed();