#include "editor_export_godot3.h" #include "editor_node.h" #include "io/resource_format_xml.h" #include "io/resource_format_binary.h" #include "scene/resources/scene_format_text.h" static const char* prop_renames[][2]={ {"script/script","script"}, {"pause/pause_mode","pause_mode"}, {"anchor/left","anchor_left"}, {"anchor/right","anchor_right"}, {"anchor/bottom","anchor_bottom"}, {"anchor/top","anchor_top"}, {"focus_neighbour/left","focus_neighbour_left"}, {"focus_neighbour/right","focus_neighbour_right"}, {"focus_neighbour/bottom","focus_neighbour_bottom"}, {"focus_neighbour/top","focus_neighbour_top"}, {"focus/ignore_mouse","focus_ignore_mouse"}, {"focus/stop_mouse","focus_stop_mouse"}, {"size_flags/horizontal","size_flags_horizontal"}, {"size_flags/vertical","size_flags_vertical"}, {"size_flags/stretch_ratio","size_flags_stretch_ratio"}, {"theme/theme","theme"}, {"visibility/visible","visible"}, {"visibility/behind_parent","show_behind_parent"}, {"visibility/on_top","show_on_top"}, {"visibility/light_mask","light_mask"}, {"material/material","material"}, {"material/use_parent","use_parent_material"}, {"resource/path","resource_path"}, {"resource/name","resource_name"}, {"collision/layers","collision_layers"}, {"collision/mask","collision_mask"}, {"limit/left","limit_left"}, {"limit/right","limit_right"}, {"limit/bottom","limit_bottom"}, {"limit/top","limit_top"}, {"limit/smoothed","limit_smoothed"}, {"draw_margin/h_enabled","draw_margin_h_enabled"}, {"draw_margin/v_enabled","draw_margin_v_enabled"}, {"smoothing/enable","smoothing_enabled"}, {"smoothing/speed","smoothing_speed"}, {"drag_margin/left","drag_margin_left"}, {"drag_margin/top","drag_margin_top"}, {"drag_margin/right","drag_margin_right"}, {"drag_margin/bottom","drag_margin_bottom"}, {"input/pickable","input_pickable"}, {"bias/bias","bias"}, {"collision/exclude_nodes","disable_collision"}, {"range/height","range_height"}, {"range/z_min","range_z_min"}, {"range/z_max","range_z_max"}, {"range/layer_max","range_layer_max"}, {"range/item_cull_mask","range_item_cull_max"}, {"shadow/enabled","shadow_enabled"}, {"shadow/color","shadow_color"}, {"shadow/buffer_size","shadow_buffer_size"}, {"shadow/gradient_length","shadow_gradient_length"}, {"shadow/filter","shadow_filter"}, {"shadow/item_cull_mask","shadow_item_cull_mask"}, {"transform/pos","position"}, {"transform/rot","rotation"}, {"transform/scale","scale"}, {"z/z","z"}, {"z/relative","z_as_relative"}, {"scroll/offset","scroll_offset"}, {"scroll/base_offset","scroll_base_offset"}, {"scroll/base_scale","scroll_base_scale"}, {"scroll/limit_begin","scroll_limit_begin"}, {"scroll/limit_end","scroll_limit_end"}, {"scroll/ignore_camera_zoom","scroll_ignore_camera_zoom"}, {"motion/scale","motion_scale"}, {"motion/offset","motion_offset"}, {"motion/mirroring","motion_mirroring"}, {"collision/layers","collision_layer"}, {"collision/mask","collision_mask"}, {"texture/texture","texture"}, {"texture/offset","texture_offset"}, {"texture/rotation","texture_rotation"}, {"texture/scale","texture_scale"}, {"invert/enable","invert_enable"}, {"invert/border","invert_border"}, {"config/polyphony","polyphony"}, {"config/samples","samples"}, {"config/pitch_random","random_pitch"}, {"params/volume_db","volume_db"}, {"params/pitch_scale","pitch_scale"}, {"params/attenuation/min_distance","attenuation_min_distance"}, {"params/attenuation/max_distance","attenuation_max_distance"}, {"params/attenuation/distance_exp","attenuation_distance_exp"}, {"cell/size","cell_size"}, {"cell/quadrant_size","cell_quadrant_size"}, {"cell/half_offset","cell_half_offset"}, {"cell/tile_origin","cell_tile_origin"}, {"cell/y_sort","cell_y_sort"}, {"collision/use_kinematic","collision_use_kinematic"}, {"collision/friction","collision_friction"}, {"collision/bounce","collision_bounce"}, {"collision/layers","collision_layers"}, {"collision/mask","collision_mask"}, {"occluder/light_mask","occluder_light_mask"}, {"enabler/pause_animations","pause_animations"}, {"enabler/freeze_bodies","freeze_bodies"}, {"enabler/pause_particles","pause_particles"}, {"enabler/pause_animated_sprites","pause_animated_sprites"}, {"enabler/process_parent","process_parent"}, {"enabler/fixed_process_parent","fixed_process_parent"}, {"sort/enabled","sort_enabled"}, {"collision/layers","collision_layers"}, {"collision/mask","collision_mask"}, {"input/ray_pickable","input_ray_pickable"}, {"input/capture_on_drag","input_capture_on_drag"}, {"light/color","light_color"}, {"light/energy","light_energy"}, {"light/negative","light_negative"}, {"light/specular","light_specular"}, {"light/cull_mask","light_cull_mask"}, {"shadow/enabled","shadow_enabled"}, {"shadow/color","shadow_color"}, {"shadow/bias","shadow_bias"}, {"shadow/max_distance","shadow_max_distance"}, {"editor/editor_only","editor_only"}, {"directional_shadow/mode","directional_shadow_mode"}, {"directional_shadow/split_1","directional_shadow_split_1"}, {"directional_shadow/split_2","directional_shadow_split_2"}, {"directional_shadow/split_3","directional_shadow_split_3"}, {"directional_shadow/blend_splits","directional_shadow_blend_splits"}, {"directional_shadow/normal_bias","directional_shadow_normal_bias"}, {"directional_shadow/bias_split_scale","directional_shadow_bias_split_scale"}, {"omni/range","omni_range"}, {"omni/attenuation","omni_attenuation"}, {"omni/shadow_mode","omni_shadow_mode"}, {"omni/shadow_detail","omni_shadow_detail"}, {"spot/range","spot_range"}, {"spot/attenuation","spot_attenuation"}, {"spot/angle","spot_angle"}, {"spot/spot_attenuation","spot_angle_attenuation"}, {"mesh/mesh","mesh"}, {"mesh/skeleton","skeleton"}, {"collision/layers","collision_layer"}, {"collision/mask","collision_mask"}, {"quad/axis","axis"}, {"quad/size","size"}, {"quad/offset","offset"}, {"quad/centered","centered"}, {"transform/local","transform"}, {"transform/transiation","translation"}, {"transform/rotation","rotation"}, {"transform/scale","scale"}, {"visibility/visible","visible"}, {"params/volume_db","volume_db"}, {"params/pitch_scale","pitch_scale"}, {"params/attenuation/min_distance","attenuation_min_distance"}, {"params/attenuation/max_distance","attenuation_max_distance"}, {"params/attenuation/distance_exp","attenuation_distance_exp"}, {"params/emission_cone/degrees","emission_cone_degrees"}, {"params/emission_cone/attenuation_db","emission_cone_attenuation_db"}, {"config/polyphony","polyphony"}, {"config/samples","samples"}, {"flags/transparent","transparent"}, {"flags/shaded","shaded"}, {"flags/alpha_cut","alpha_cut"}, {"type/traction","use_as_traction"}, {"type/steering","use_as_steering"}, {"wheel/radius","wheel_radius"}, {"wheel/rest_length","wheel_rest_length"}, {"wheel/friction_slip","wheel_friction_sleep"}, {"suspension/travel","suspension_travel"}, {"suspension/stiffness","suspension_stiffness"}, {"suspension/max_force","suspension_max_force"}, {"damping/compression","damping_compression"}, {"damping/relaxation","damping_relaxation"}, {"motion/engine_force","engine_force"}, {"motion/breake","breake"}, {"motion/steering","steering"}, {"body/mass","mass"}, {"body/friction","friction"}, {"enabler/pause_animations","pause_animations"}, {"enabler/freeze_bodies","freeze_bodies"}, {"geometry/material_override","material_override"}, {"geometry/cast_shadow","cast_shadow"}, {"geometry/extra_cull_margin","extra_cull_margin"}, {"geometry/billboard","use_as_billboard"}, {"geometry/billboard_y","use_as_y_billboard"}, {"geometry/depth_scale","use_depth_scale"}, {"geometry/visible_in_all_rooms","visible_in_all_rooms"}, {"geometry/use_baked_light","use_in_baked_light"}, {"playback/process_mode","playback_process_mode"}, {"playback/default_blend_time","playback_default_blend_time"}, {"root/root","root_node"}, {"playback/process_mode","playback_process_mode"}, {"stream/stream","stream"}, {"stream/play","play"}, {"stream/loop","loop"}, {"stream/volume_db","volume_db"}, {"stream/pitch_scale","pitch_scale"}, {"stream/tempo_scale","tempo_scale"}, {"stream/autoplay","autoplay"}, {"stream/paused","paused"}, {"stream/stream","stream"}, {"stream/play","play"}, {"stream/loop","loop"}, {"stream/volume_db","volume_db"}, {"stream/autoplay","autoplay"}, {"stream/paused","paused"}, {"stream/loop_restart_time","loop_restart_time"}, {"stream/buffering_ms","buffering_ms"}, {"stream/stream","stream"}, {"stream/play","play"}, {"stream/loop","loop"}, {"stream/volume_db","volume_db"}, {"stream/autoplay","autoplay"}, {"stream/paused","paused"}, {"stream/loop_restart_time","loop_restart_time"}, {"stream/buffering_ms","buffering_ms"}, {"window/title","window_title"}, {"dialog/text","dialog_text"}, {"dialog/hide_on_ok","dialog_hide_on_ok"}, {"placeholder/text","placeholder_text"}, {"placeholder/alpha","placeholder_alpha"}, {"caret/caret_blink","caret_blink"}, {"caret/caret_blink_speed","caret_blink_speed"}, {"patch_margin/left","patch_margin_left"}, {"patch_margin/right","patch_margin_right"}, {"patch_margin/top","patch_margin_top"}, {"patch_margin/bottom","patch_margin_bottom"}, {"popup/exclusive","popup_exclusive"}, {"percent/visible","percent_visible"}, {"range/min","min_value"}, {"range/max","max_value"}, {"range/step","step"}, {"range/page","page"}, {"range/value","value"}, {"range/exp_edit","exp_edit"}, {"range/rounded","rounded"}, {"velocity/linear","linear_velocity"}, {"velocity/angular","angular_velocity"}, {"damp_override_linear","linear_damp"}, {"damp_override_angular","angular_damp"}, {"velocity/linear","linear_velocity"}, {"velocity/angular","angular_velocity"}, {"damp_override_linear","linear_damp"}, {"damp_override_angular","angular_damp"}, {"playback/process_mode","playback_process_mode"}, {"bbcode/enabled","bbcode_enabled"}, {"bbcode/bbcode","bbcode_text"}, {"scroll/horizontal","scroll_horizontal"}, {"scroll/vertical","scroll_vertical"}, {"split/offset","split_offset"}, {"split/collapsed","collapsed"}, {"split/dragger_visibility","dragger_visibility"}, {"caret/block_caret","caret_block_mode"}, {"caret/caret_blink","caret_blink"}, {"caret/caret_blink_speed","caret_blink_speed"}, {"textures/normal","texture_normal"}, {"textures/pressed","texture_pressed"}, {"textures/hover","texture_hover"}, {"textures/disabled","texture_disabled"}, {"textures/focused","texture_focused"}, {"textures/click_mask","texture_click_mask"}, {"params/scale","texture_scale"}, {"params/modulate","self_modulate"}, {"texture/under","texture_under"}, {"texture/over","texture_over"}, {"texture/progress","texture_progress"}, {"mode","fill_mode"}, {"radial_fill/initial_angle","radial_initial_angle"}, {"radial_fill/fill_degrees","radial_fill_degrees"}, {"radial_fill/center_offset","radial_center_offset"}, {"stream/audio_track","audio_track"}, {"stream/stream","stream"}, {"stream/volume_db","volume_db"}, {"stream/autoplay","stream_autoplay"}, {"stream/paused","stream_paused"}, {"font/size","size"}, {"extra_spacing/top","extra_spacing_top"}, {"extra_spacing/bottom","extra_spacing_bottom"}, {"extra_spacing/char","extra_spacing_char"}, {"extra_spacing/space","extra_spacing_space"}, {"font/use_mipmaps","use_mipmaps"}, {"font/use_filter","use_filter"}, {"font/font","font_data"}, {"content_margin/left","content_margin_left"}, {"content_margin/right","content_margin_right"}, {"content_margin/bottom","content_margin_bottom"}, {"content_margin/top","content_margin_top"}, {"margin/left","margin_left"}, {"margin/top","margin_top"}, {"margin/bottom","margin_bottom"}, {"margin/right","margin_right"}, {"expand_margin/left","expand_margin_left"}, {"expand_margin/top","expand_margin_top"}, {"expand_margin/bottom","expand_margin_bottom"}, {"expand_margin/right","expand_margin_right"}, {"modulate/color","modulate_color"}, {"modulate","self_modulate"}, {"cell/size","cell_size"}, {"cell/octant_size","cell_octant_size"}, {"cell/center_x","cell_center_x"}, {"cell/center_y","cell_center_y"}, {"cell/center_z","cell_center_z"}, {"cell/scale","cell_scale"}, {NULL,NULL} }; static const char* type_renames[][2]={ {"SpatialPlayer","Spatial"}, {"SpatialSamplePlayer","Spatial"}, {"SpatialStreamPlayer","Spatial"}, {"Particles","Spatial"}, {"SamplePlayer","Node"}, {"SamplePlayer2D","Node2D"}, {"SoundPlayer2D","Node2D"}, {"StreamPlayer2D","Node2D"}, {"Particles2D","Node2D"}, {"SampleLibrary","Resource"}, {"TextureFrame","TextureRect"}, {"FixedMaterial","FixedSpatialMaterial"}, {NULL,NULL} }; static const char* signal_renames[][2]={ {"area_enter","area_entered"}, {"area_exit","area_exited"}, {"area_enter_shape","area_shape_entered"}, {"area_exit_shape","area_shape_exited"}, {"body_enter","body_entered"}, {"body_exit","body_exited"}, {"body_enter_shape","body_shape_entered"}, {"body_exit_shape","body_shape_exited"}, {"mouse_enter","mouse_entered"}, {"mouse_exit","mouse_exited"}, {"focus_enter","focus_entered"}, {"focus_exit","focus_exited"}, {"modal_close","modal_closed"}, {"enter_tree","tree_entered"}, {"exit_tree","tree_exited"}, {NULL,NULL} }; void EditorExportGodot3::_find_files(EditorFileSystemDirectory *p_dir,List * r_files) { for(int i=0;iget_subdir_count();i++) { _find_files(p_dir->get_subdir(i),r_files); } for(int i=0;iget_file_count();i++) { r_files->push_back(p_dir->get_file_path(i)); } } void EditorExportGodot3::_rename_properties(const String& p_type,List *p_props) { for (List::Element *E=p_props->front();E;E=E->next()) { if (prop_rename_map.has(E->get().name)) { E->get().name=prop_rename_map[E->get().name]; } } } void EditorExportGodot3::_convert_resources(ExportData &resource) { for(int i=0;i::Element *E=resource.resources[resource.resources.size()-1].properties.front();E;E=E->next()) { if (E->get().name=="_bundled") { d=E->get().value; } } ERR_FAIL_COND(d.empty()); ERR_FAIL_COND( !d.has("names")); ERR_FAIL_COND( !d.has("variants")); ERR_FAIL_COND( !d.has("node_count")); ERR_FAIL_COND( !d.has("nodes")); ERR_FAIL_COND( !d.has("conn_count")); ERR_FAIL_COND( !d.has("conns")); Vector names; DVector snames = d["names"]; if (snames.size()) { int namecount = snames.size(); names.resize(namecount); DVector::Read r =snames.read(); for(int i=0;i snodes = d["nodes"]; DVector::Read r = snodes.read(); int idx=0; for(int i=0;i=0) { node_data.instance_is_placeholder=instance&SceneState::FLAG_INSTANCE_IS_PLACEHOLDER; node_data.instance=variants[instance&SceneState::FLAG_MASK]; } int prop_count = r[idx++]; for(int j=0;j sconns = d["conns"]; DVector::Read r = sconns.read(); int idx=0; for(int i=0;i node_data; for(int i=0;i connections; for(int i=0;i names; names.resize(pack_names.size()); { DVector::Write w=names.write(); for(Map::Element *E=pack_names.front();E;E=E->next()) { w[E->get()]=E->key(); } } d["names"]=names; Array values; values.resize(pack_values.size()); const Variant*K=NULL; while((K=pack_values.next(K))) { int index=pack_values[*K]; values[index]=*K; } d["variants"]=values; ExportData::ResourceData packed_scene; packed_scene.type="PackedScene"; packed_scene.index=-1; ExportData::PropertyData pd; pd.name="_bundled"; pd.value=d; packed_scene.properties.push_back(pd); resource.resources.push_back(packed_scene); resource.nodes.clear(); resource.connections.clear(); resource.editables.clear(); resource.node_paths.clear();; resource.base_scene=Variant(); } static String rtosfix(double p_value) { if (p_value==0.0) return "0"; //avoid negative zero (-0) being written, which may annoy git, svn, etc. for changes when they don't exist. else return rtoss(p_value); } Error EditorExportGodot3::_get_property_as_text(const Variant& p_variant,String&p_string) { switch( p_variant.get_type() ) { case Variant::NIL: { p_string+=("null"); } break; case Variant::BOOL: { p_string+=(p_variant.operator bool() ? "true":"false" ); } break; case Variant::INT: { p_string+=( itos(p_variant.operator int()) ); } break; case Variant::REAL: { String s = rtosfix(p_variant.operator real_t()); if (s.find(".")==-1 && s.find("e")==-1) s+=".0"; p_string+=( s ); } break; case Variant::STRING: { String str=p_variant; if (str.begins_with("@RESLOCAL:")) { p_string+="SubResource("+str.get_slice(":",1)+")"; } else if (str.begins_with("@RESEXTERNAL:")) { p_string+="ExtResource("+str.get_slice(":",1)+")"; } else { str="\""+str.c_escape_multiline()+"\""; p_string+=( str ); } } break; case Variant::VECTOR2: { Vector2 v = p_variant; p_string+=("Vector2( "+rtosfix(v.x) +", "+rtosfix(v.y)+" )" ); } break; case Variant::RECT2: { Rect2 aabb = p_variant; p_string+=("Rect2( "+rtosfix(aabb.pos.x) +", "+rtosfix(aabb.pos.y) +", "+rtosfix(aabb.size.x) +", "+rtosfix(aabb.size.y)+" )" ); } break; case Variant::VECTOR3: { Vector3 v = p_variant; p_string+=("Vector3( "+rtosfix(v.x) +", "+rtosfix(v.y)+", "+rtosfix(v.z)+" )"); } break; case Variant::PLANE: { Plane p = p_variant; p_string+=("Plane( "+rtosfix(p.normal.x) +", "+rtosfix(p.normal.y)+", "+rtosfix(p.normal.z)+", "+rtosfix(p.d)+" )" ); } break; case Variant::_AABB: { Rect3 aabb = p_variant; p_string+=("Rect3( "+rtosfix(aabb.pos.x) +", "+rtosfix(aabb.pos.y) +", "+rtosfix(aabb.pos.z) +", "+rtosfix(aabb.size.x) +", "+rtosfix(aabb.size.y) +", "+rtosfix(aabb.size.z)+" )" ); } break; case Variant::QUAT: { Quat quat = p_variant; p_string+=("Quat( "+rtosfix(quat.x)+", "+rtosfix(quat.y)+", "+rtosfix(quat.z)+", "+rtosfix(quat.w)+" )"); } break; case Variant::MATRIX32: { String s="Transform2D( "; Matrix32 m3 = p_variant; for (int i=0;i<3;i++) { for (int j=0;j<2;j++) { if (i!=0 || j!=0) s+=", "; s+=rtosfix( m3.elements[i][j] ); } } p_string+=(s+" )"); } break; case Variant::MATRIX3: { String s="Basis( "; Matrix3 m3 = p_variant; for (int i=0;i<3;i++) { for (int j=0;j<3;j++) { if (i!=0 || j!=0) s+=", "; s+=rtosfix( m3.elements[i][j] ); } } p_string+=(s+" )"); } break; case Variant::TRANSFORM: { String s="Transform( "; Transform t = p_variant; Matrix3 &m3 = t.basis; for (int i=0;i<3;i++) { for (int j=0;j<3;j++) { if (i!=0 || j!=0) s+=", "; s+=rtosfix( m3.elements[i][j] ); } } s=s+", "+rtosfix(t.origin.x) +", "+rtosfix(t.origin.y)+", "+rtosfix(t.origin.z); p_string+=(s+" )"); } break; // misc types case Variant::COLOR: { Color c = p_variant; p_string+=("Color( "+rtosfix(c.r) +", "+rtosfix(c.g)+", "+rtosfix(c.b)+", "+rtosfix(c.a)+" )"); } break; case Variant::IMAGE: { Image img=p_variant; if (img.empty()) { p_string+=("Image()"); break; } String imgstr="Image()"; p_string+=imgstr; //do not convert this for now /*imgstr+=itos(img.get_width()); imgstr+=", "+itos(img.get_height()); imgstr+=", "+String(img.get_mipmaps()?"true":"false"); imgstr+=", "+Image::get_format_name(img.get_format()); String s; DVector data = img.get_data(); int len = data.size(); DVector::Read r = data.read(); const uint8_t *ptr=r.ptr(); for (int i=0;i0) s+=", "; s+=itos(ptr[i]); } imgstr+=", "; p_string+=(imgstr); p_string+=(s); p_string+=(" )");*/ } break; case Variant::NODE_PATH: { String str=p_variant; str="NodePath(\""+str.c_escape()+"\")"; p_string+=(str); } break; case Variant::OBJECT: { //should never arrive here! ERR_FAIL_V(ERR_BUG); } break; case Variant::INPUT_EVENT: { String str="InputEvent("; InputEvent ev=p_variant; switch(ev.type) { case InputEvent::KEY: { str+="KEY,"+itos(ev.key.scancode); String mod; if (ev.key.mod.alt) mod+="A"; if (ev.key.mod.shift) mod+="S"; if (ev.key.mod.control) mod+="C"; if (ev.key.mod.meta) mod+="M"; if (mod!=String()) str+=","+mod; } break; case InputEvent::MOUSE_BUTTON: { str+="MBUTTON,"+itos(ev.mouse_button.button_index); } break; case InputEvent::JOYSTICK_BUTTON: { str+="JBUTTON,"+itos(ev.joy_button.button_index); } break; case InputEvent::JOYSTICK_MOTION: { str+="JAXIS,"+itos(ev.joy_motion.axis)+","+itos(ev.joy_motion.axis_value); } break; case InputEvent::NONE: { str+="NONE"; } break; default: {} } str+=")"; p_string+=(str); //will be added later } break; case Variant::DICTIONARY: { Dictionary dict = p_variant; List keys; dict.get_key_list(&keys); keys.sort(); p_string+=("{\n"); for(List::Element *E=keys.front();E;E=E->next()) { /* if (!_check_type(dict[E->get()])) continue; */ _get_property_as_text(E->get(),p_string); p_string+=(": "); _get_property_as_text(dict[E->get()],p_string); if (E->next()) p_string+=(",\n"); } p_string+=("\n}"); } break; case Variant::ARRAY: { p_string+=("[ "); Array array = p_variant; int len=array.size(); for (int i=0;i0) p_string+=(", "); _get_property_as_text(array[i],p_string); } p_string+=(" ]"); } break; case Variant::RAW_ARRAY: { p_string+=("PoolByteArray( "); String s; DVector data = p_variant; int len = data.size(); DVector::Read r = data.read(); const uint8_t *ptr=r.ptr(); for (int i=0;i0) p_string+=(", "); p_string+=(itos(ptr[i])); } p_string+=(" )"); } break; case Variant::INT_ARRAY: { p_string+=("PoolIntArray( "); DVector data = p_variant; int len = data.size(); DVector::Read r = data.read(); const int *ptr=r.ptr(); for (int i=0;i0) p_string+=(", "); p_string+=(itos(ptr[i])); } p_string+=(" )"); } break; case Variant::REAL_ARRAY: { p_string+=("PoolFloatArray( "); DVector data = p_variant; int len = data.size(); DVector::Read r = data.read(); const real_t *ptr=r.ptr(); for (int i=0;i0) p_string+=(", "); p_string+=(rtosfix(ptr[i])); } p_string+=(" )"); } break; case Variant::STRING_ARRAY: { p_string+=("PoolStringArray( "); DVector data = p_variant; int len = data.size(); DVector::Read r = data.read(); const String *ptr=r.ptr(); String s; //write_string("\n"); for (int i=0;i0) p_string+=(", "); String str=ptr[i]; p_string+=("\""+str.c_escape()+"\""); } p_string+=(" )"); } break; case Variant::VECTOR2_ARRAY: { p_string+=("PoolVector2Array( "); DVector data = p_variant; int len = data.size(); DVector::Read r = data.read(); const Vector2 *ptr=r.ptr(); for (int i=0;i0) p_string+=(", "); p_string+=(rtosfix(ptr[i].x)+", "+rtosfix(ptr[i].y) ); } p_string+=(" )"); } break; case Variant::VECTOR3_ARRAY: { p_string+=("PoolVector3Array( "); DVector data = p_variant; int len = data.size(); DVector::Read r = data.read(); const Vector3 *ptr=r.ptr(); for (int i=0;i0) p_string+=(", "); p_string+=(rtosfix(ptr[i].x)+", "+rtosfix(ptr[i].y)+", "+rtosfix(ptr[i].z) ); } p_string+=(" )"); } break; case Variant::COLOR_ARRAY: { p_string+=("PoolColorArray( "); DVector data = p_variant; int len = data.size(); DVector::Read r = data.read(); const Color *ptr=r.ptr(); for (int i=0;i0) p_string+=(", "); p_string+=(rtosfix(ptr[i].r)+", "+rtosfix(ptr[i].g)+", "+rtosfix(ptr[i].b)+", "+rtosfix(ptr[i].a) ); } p_string+=(" )"); } break; default: {} } return OK; } void EditorExportGodot3::_save_text(const String& p_path,ExportData &resource) { FileAccessRef f = FileAccess::open(p_path,FileAccess::WRITE); if (resource.nodes.size()) { f->store_line("[gd_scene load_steps="+itos(resource.nodes.size()+resource.resources.size())+" format=2]\n"); } else { f->store_line("[gd_resource type=\""+resource.resources[resource.resources.size()-1].type+"\" load_steps="+itos(resource.resources.size())+" format=2]\n"); } for (Map::Element *E=resource.dependencies.front();E;E=E->next()) { f->store_line("[ext_resource type=\""+E->get().type+"\" path=\""+E->get().path+"\" id="+itos(E->key())+"]\n"); } for (int i=0;istore_line("\n[sub_resource type=\""+resource.resources[i].type+"\" id="+itos(resource.resources[i].index)+"]\n"); } else { f->store_line("\n[resource]\n"); } for( List::Element *E=resource.resources[i].properties.front();E;E=E->next() ) { String prop; _get_property_as_text(E->get().value,prop); f->store_line(E->get().name+"="+prop); } } for (int i=0;istore_line(node_txt); for( List::Element *E=resource.nodes[i].properties.front();E;E=E->next() ) { String prop; _get_property_as_text(E->get().value,prop); f->store_line(E->get().name+"="+prop); } } for(int i=0;istore_line("\n[connection signal=\""+resource.connections[i].signal+"\" from=\""+String(resource.connections[i].from).c_escape()+"\" to=\""+String(resource.connections[i].to).c_escape()+"\" method=\""+resource.connections[i].method+"\" binds="+prop+"]"); } for(int i=0;istore_line("[editable path=\""+String(resource.editables[i]).c_escape()+"\"]"); } } enum { //numbering must be different from variant, in case new variant types are added (variant must be always contiguous for jumptable optimization) VARIANT_NIL=1, VARIANT_BOOL=2, VARIANT_INT=3, VARIANT_REAL=4, VARIANT_STRING=5, VARIANT_VECTOR2=10, VARIANT_RECT2=11, VARIANT_VECTOR3=12, VARIANT_PLANE=13, VARIANT_QUAT=14, VARIANT_AABB=15, VARIANT_MATRIX3=16, VARIANT_TRANSFORM=17, VARIANT_MATRIX32=18, VARIANT_COLOR=20, VARIANT_IMAGE=21, VARIANT_NODE_PATH=22, VARIANT_RID=23, VARIANT_OBJECT=24, VARIANT_INPUT_EVENT=25, VARIANT_DICTIONARY=26, VARIANT_ARRAY=30, VARIANT_RAW_ARRAY=31, VARIANT_INT_ARRAY=32, VARIANT_REAL_ARRAY=33, VARIANT_STRING_ARRAY=34, VARIANT_VECTOR3_ARRAY=35, VARIANT_COLOR_ARRAY=36, VARIANT_VECTOR2_ARRAY=37, VARIANT_INT64=40, VARIANT_DOUBLE=41, IMAGE_ENCODING_EMPTY=0, IMAGE_ENCODING_RAW=1, IMAGE_ENCODING_LOSSLESS=2, IMAGE_ENCODING_LOSSY=3, OBJECT_EMPTY=0, OBJECT_EXTERNAL_RESOURCE=1, OBJECT_INTERNAL_RESOURCE=2, OBJECT_EXTERNAL_RESOURCE_INDEX=3, //version 2: added 64 bits support for float and int FORMAT_VERSION=2, FORMAT_VERSION_CAN_RENAME_DEPS=1 }; enum { IMAGE_FORMAT_L8, //luminance IMAGE_FORMAT_LA8, //luminance-alpha IMAGE_FORMAT_R8, IMAGE_FORMAT_RG8, IMAGE_FORMAT_RGB8, IMAGE_FORMAT_RGBA8, IMAGE_FORMAT_RGB565, //16 bit IMAGE_FORMAT_RGBA4444, IMAGE_FORMAT_RGBA5551, IMAGE_FORMAT_RF, //float IMAGE_FORMAT_RGF, IMAGE_FORMAT_RGBF, IMAGE_FORMAT_RGBAF, IMAGE_FORMAT_RH, //half float IMAGE_FORMAT_RGH, IMAGE_FORMAT_RGBH, IMAGE_FORMAT_RGBAH, IMAGE_FORMAT_DXT1, //s3tc bc1 IMAGE_FORMAT_DXT3, //bc2 IMAGE_FORMAT_DXT5, //bc3 IMAGE_FORMAT_ATI1, //bc4 IMAGE_FORMAT_ATI2, //bc5 IMAGE_FORMAT_BPTC_RGBA, //btpc bc6h IMAGE_FORMAT_BPTC_RGBF, //float / IMAGE_FORMAT_BPTC_RGBFU, //unsigned float IMAGE_FORMAT_PVRTC2, //pvrtc IMAGE_FORMAT_PVRTC2A, IMAGE_FORMAT_PVRTC4, IMAGE_FORMAT_PVRTC4A, IMAGE_FORMAT_ETC, //etc1 IMAGE_FORMAT_ETC2_R11, //etc2 IMAGE_FORMAT_ETC2_R11S, //signed, NOT srgb. IMAGE_FORMAT_ETC2_RG11, IMAGE_FORMAT_ETC2_RG11S, IMAGE_FORMAT_ETC2_RGB8, IMAGE_FORMAT_ETC2_RGBA8, IMAGE_FORMAT_ETC2_RGB8A1, }; static void _pad_buffer(int p_bytes,FileAccess *f) { int extra = 4-(p_bytes%4); if (extra<4) { for(int i=0;istore_8(0); //pad to 32 } } static void save_unicode_string(const String& p_string,FileAccess *f,bool p_hi_bit=false) { CharString utf8 = p_string.utf8(); f->store_32(uint32_t(utf8.length()+1) | (p_hi_bit?0x80000000:0)); f->store_buffer((const uint8_t*)utf8.get_data(),utf8.length()+1); } void EditorExportGodot3::_save_binary_property(const Variant& p_property,FileAccess *f) { switch(p_property.get_type()) { case Variant::NIL: { f->store_32(VARIANT_NIL); // don't store anything } break; case Variant::BOOL: { f->store_32(VARIANT_BOOL); bool val=p_property; f->store_32(val); } break; case Variant::INT: { f->store_32(VARIANT_INT); int val=p_property; f->store_32(int32_t(val)); } break; case Variant::REAL: { f->store_32(VARIANT_REAL); f->store_real(p_property); } break; case Variant::STRING: { String str=p_property; if (str.begins_with("@RESLOCAL:")) { f->store_32(VARIANT_OBJECT); f->store_32(OBJECT_INTERNAL_RESOURCE); f->store_32(str.get_slice(":",1).to_int()); print_line("SAVE RES LOCAL: "+itos(str.get_slice(":",1).to_int())); } else if (str.begins_with("@RESEXTERNAL:")) { f->store_32(VARIANT_OBJECT); f->store_32(OBJECT_EXTERNAL_RESOURCE_INDEX); f->store_32(str.get_slice(":",1).to_int()); print_line("SAVE RES EXTERNAL: "+itos(str.get_slice(":",1).to_int())); } else { f->store_32(VARIANT_STRING); save_unicode_string(str,f); } } break; case Variant::VECTOR2: { f->store_32(VARIANT_VECTOR2); Vector2 val=p_property; f->store_real(val.x); f->store_real(val.y); } break; case Variant::RECT2: { f->store_32(VARIANT_RECT2); Rect2 val=p_property; f->store_real(val.pos.x); f->store_real(val.pos.y); f->store_real(val.size.x); f->store_real(val.size.y); } break; case Variant::VECTOR3: { f->store_32(VARIANT_VECTOR3); Vector3 val=p_property; f->store_real(val.x); f->store_real(val.y); f->store_real(val.z); } break; case Variant::PLANE: { f->store_32(VARIANT_PLANE); Plane val=p_property; f->store_real(val.normal.x); f->store_real(val.normal.y); f->store_real(val.normal.z); f->store_real(val.d); } break; case Variant::QUAT: { f->store_32(VARIANT_QUAT); Quat val=p_property; f->store_real(val.x); f->store_real(val.y); f->store_real(val.z); f->store_real(val.w); } break; case Variant::_AABB: { f->store_32(VARIANT_AABB); Rect3 val=p_property; f->store_real(val.pos.x); f->store_real(val.pos.y); f->store_real(val.pos.z); f->store_real(val.size.x); f->store_real(val.size.y); f->store_real(val.size.z); } break; case Variant::MATRIX32: { f->store_32(VARIANT_MATRIX32); Matrix32 val=p_property; f->store_real(val.elements[0].x); f->store_real(val.elements[0].y); f->store_real(val.elements[1].x); f->store_real(val.elements[1].y); f->store_real(val.elements[2].x); f->store_real(val.elements[2].y); } break; case Variant::MATRIX3: { f->store_32(VARIANT_MATRIX3); Matrix3 val=p_property; f->store_real(val.elements[0].x); f->store_real(val.elements[0].y); f->store_real(val.elements[0].z); f->store_real(val.elements[1].x); f->store_real(val.elements[1].y); f->store_real(val.elements[1].z); f->store_real(val.elements[2].x); f->store_real(val.elements[2].y); f->store_real(val.elements[2].z); } break; case Variant::TRANSFORM: { f->store_32(VARIANT_TRANSFORM); Transform val=p_property; f->store_real(val.basis.elements[0].x); f->store_real(val.basis.elements[0].y); f->store_real(val.basis.elements[0].z); f->store_real(val.basis.elements[1].x); f->store_real(val.basis.elements[1].y); f->store_real(val.basis.elements[1].z); f->store_real(val.basis.elements[2].x); f->store_real(val.basis.elements[2].y); f->store_real(val.basis.elements[2].z); f->store_real(val.origin.x); f->store_real(val.origin.y); f->store_real(val.origin.z); } break; case Variant::COLOR: { f->store_32(VARIANT_COLOR); Color val=p_property; f->store_real(val.r); f->store_real(val.g); f->store_real(val.b); f->store_real(val.a); } break; case Variant::IMAGE: { f->store_32(VARIANT_IMAGE); Image val =p_property; if (val.empty()) { f->store_32(IMAGE_ENCODING_EMPTY); break; } f->store_32(IMAGE_ENCODING_RAW); f->store_32(val.get_width()); f->store_32(val.get_height()); f->store_32(val.get_mipmaps()?1:0); switch(val.get_format()) { case Image::FORMAT_GRAYSCALE: f->store_32(IMAGE_FORMAT_L8 ); break; ///< one byte per pixel: f->store_32(IMAGE_FORMAT_ ); break; 0-255 case Image::FORMAT_INTENSITY: f->store_32(IMAGE_FORMAT_L8 ); break; ///< one byte per pixel: f->store_32(IMAGE_FORMAT_ ); break; 0-255 case Image::FORMAT_GRAYSCALE_ALPHA: f->store_32(IMAGE_FORMAT_LA8 ); break; ///< two bytes per pixel: f->store_32(IMAGE_FORMAT_ ); break; 0-255. alpha 0-255 case Image::FORMAT_RGB: f->store_32(IMAGE_FORMAT_RGB8 ); break; ///< one byte R: f->store_32(IMAGE_FORMAT_ ); break; one byte G: f->store_32(IMAGE_FORMAT_ ); break; one byte B case Image::FORMAT_RGBA: f->store_32(IMAGE_FORMAT_RGBA8 ); break; ///< one byte R: f->store_32(IMAGE_FORMAT_ ); break; one byte G: f->store_32(IMAGE_FORMAT_ ); break; one byte B: f->store_32(IMAGE_FORMAT_ ); break; one byte A case Image::FORMAT_BC1: f->store_32(IMAGE_FORMAT_DXT1 ); break; // DXT1 case Image::FORMAT_BC2: f->store_32(IMAGE_FORMAT_DXT3 ); break; // DXT3 case Image::FORMAT_BC3: f->store_32(IMAGE_FORMAT_DXT5 ); break; // DXT5 case Image::FORMAT_BC4: f->store_32(IMAGE_FORMAT_ATI1 ); break; // ATI1 case Image::FORMAT_BC5: f->store_32(IMAGE_FORMAT_ATI2 ); break; // ATI2 case Image::FORMAT_PVRTC2: f->store_32(IMAGE_FORMAT_PVRTC2 ); break; case Image::FORMAT_PVRTC2_ALPHA: f->store_32(IMAGE_FORMAT_PVRTC2A ); break; case Image::FORMAT_PVRTC4: f->store_32(IMAGE_FORMAT_PVRTC4 ); break; case Image::FORMAT_PVRTC4_ALPHA: f->store_32(IMAGE_FORMAT_PVRTC4A ); break; case Image::FORMAT_ETC: f->store_32(IMAGE_FORMAT_ETC ); break; // regular ETC: f->store_32(IMAGE_FORMAT_ ); break; no transparency default: f->store_32(IMAGE_FORMAT_L8 ); break; } int dlen = val.get_data().size(); f->store_32(dlen); DVector::Read r = val.get_data().read(); f->store_buffer(r.ptr(),dlen); _pad_buffer(dlen,f); } break; case Variant::NODE_PATH: { f->store_32(VARIANT_NODE_PATH); NodePath np=p_property; f->store_16(np.get_name_count()); uint16_t snc = np.get_subname_count(); if (np.is_absolute()) snc|=0x8000; f->store_16(snc); for(int i=0;istore_32(VARIANT_RID); WARN_PRINT("Can't save RIDs"); RID val = p_property; f->store_32(val.get_id()); } break; case Variant::OBJECT: { ERR_FAIL(); } break; case Variant::INPUT_EVENT: { f->store_32(VARIANT_INPUT_EVENT); InputEvent event=p_property; f->store_32(0); //event type none, nothing else suported for now. } break; case Variant::DICTIONARY: { f->store_32(VARIANT_DICTIONARY); Dictionary d = p_property; f->store_32(uint32_t(d.size())); List keys; d.get_key_list(&keys); for(List::Element *E=keys.front();E;E=E->next()) { /* if (!_check_type(dict[E->get()])) continue; */ _save_binary_property(E->get(),f); _save_binary_property(d[E->get()],f); } } break; case Variant::ARRAY: { f->store_32(VARIANT_ARRAY); Array a=p_property; f->store_32(uint32_t(a.size())); for(int i=0;istore_32(VARIANT_RAW_ARRAY); DVector arr = p_property; int len=arr.size(); f->store_32(len); DVector::Read r = arr.read(); f->store_buffer(r.ptr(),len); _pad_buffer(len,f); } break; case Variant::INT_ARRAY: { f->store_32(VARIANT_INT_ARRAY); DVector arr = p_property; int len=arr.size(); f->store_32(len); DVector::Read r = arr.read(); for(int i=0;istore_32(r[i]); } break; case Variant::REAL_ARRAY: { f->store_32(VARIANT_REAL_ARRAY); DVector arr = p_property; int len=arr.size(); f->store_32(len); DVector::Read r = arr.read(); for(int i=0;istore_real(r[i]); } } break; case Variant::STRING_ARRAY: { f->store_32(VARIANT_STRING_ARRAY); DVector arr = p_property; int len=arr.size(); f->store_32(len); DVector::Read r = arr.read(); for(int i=0;istore_32(VARIANT_VECTOR3_ARRAY); DVector arr = p_property; int len=arr.size(); f->store_32(len); DVector::Read r = arr.read(); for(int i=0;istore_real(r[i].x); f->store_real(r[i].y); f->store_real(r[i].z); } } break; case Variant::VECTOR2_ARRAY: { f->store_32(VARIANT_VECTOR2_ARRAY); DVector arr = p_property; int len=arr.size(); f->store_32(len); DVector::Read r = arr.read(); for(int i=0;istore_real(r[i].x); f->store_real(r[i].y); } } break; case Variant::COLOR_ARRAY: { f->store_32(VARIANT_COLOR_ARRAY); DVector arr = p_property; int len=arr.size(); f->store_32(len); DVector::Read r = arr.read(); for(int i=0;istore_real(r[i].r); f->store_real(r[i].g); f->store_real(r[i].b); f->store_real(r[i].a); } } break; default: { ERR_EXPLAIN("Invalid variant"); ERR_FAIL(); } } } void EditorExportGodot3::_save_binary(const String& p_path,ExportData &resource) { FileAccessRef f = FileAccess::open(p_path,FileAccess::WRITE); ERR_FAIL_COND(!f.operator ->()); //save header compressed static const uint8_t header[4]={'R','S','R','C'}; f->store_buffer(header,4); f->store_32(0); f->store_32(0); //64 bits file, false for now f->store_32(3);//major f->store_32(0); //minor f->store_32(2); //format version (2 is for 3.0) //f->store_32(saved_resources.size()+external_resources.size()); // load steps -not needed save_unicode_string(resource.resources[resource.resources.size()-1].type,f.operator->()); for(int i=0;i<16;i++) f->store_32(0); // unused f->store_32(0); //no names saved f->store_32(resource.dependencies.size()); //amount of external resources for (Map::Element *E=resource.dependencies.front();E;E=E->next()) { save_unicode_string(E->get().type,f.operator->()); save_unicode_string(E->get().path,f.operator->()); } // save internal resource table Vector ofs_pos; f->store_32(resource.resources.size()); //amount of internal resources for(int i=0;i()); ofs_pos.push_back(f->get_pos()); f->store_64(0); } Vector ofs_table; // int saved_idx=0; //now actually save the resources for(int i=0;iget_pos()); save_unicode_string(resource.resources[i].type,f.operator->()); f->store_32(resource.resources[i].properties.size()); for( List::Element *E=resource.resources[i].properties.front();E;E=E->next() ) { save_unicode_string(E->get().name,f.operator->(),true); _save_binary_property(E->get().value,f.operator->()); } } for(int i=0;iseek(ofs_pos[i]); f->store_64(ofs_table[i]); } f->seek_end(); f->store_buffer((const uint8_t*)"RSRC",4); //magic at end ERR_FAIL_COND(f->get_error()!=OK); } void EditorExportGodot3::_save_config(const String &p_path) { FileAccessRef f = FileAccess::open(p_path.plus_file("godot.cfg"),FileAccess::WRITE); f->store_line("[application]\n"); String name = Globals::get_singleton()->get("application/name"); f->store_line("name=\""+name.c_escape()+"\""); String main_scene = Globals::get_singleton()->get("application/main_scene"); f->store_line("main_scene=\""+_replace_resource(main_scene).c_escape()+"\""); List props; Globals::get_singleton()->get_property_list(&props); f->store_line("[input]\n"); for (List::Element *E=props.front();E;E=E->next()) { if (!E->get().name.begins_with("input/")) continue; String prop; _get_property_as_text(Globals::get_singleton()->get(E->get().name),prop); String what = E->get().name.get_slice("/",1); f->store_line(what+"="+prop); } } Error EditorExportGodot3::export_godot3(const String& p_path) { List files; _find_files(EditorFileSystem::get_singleton()->get_filesystem(),&files); EditorProgress progress("exporting","Exporting Godot 3.0",files.size()); //find XML resources resource_replace_map.clear(); Set xml_extensions; Set binary_extensions; Set text_extensions; { List xml_exts; ResourceFormatLoaderXML::singleton->get_recognized_extensions(&xml_exts); for (List::Element *E=xml_exts.front();E;E=E->next()) { xml_extensions.insert(E->get()); } } { List binary_exts; ResourceFormatLoaderBinary::singleton->get_recognized_extensions(&binary_exts); for (List::Element *E=binary_exts.front();E;E=E->next()) { binary_extensions.insert(E->get()); } } { List text_exts; ResourceFormatLoaderText::singleton->get_recognized_extensions(&text_exts); for (List::Element *E=text_exts.front();E;E=E->next()) { text_extensions.insert(E->get()); } } for(List::Element *E=files.front();E;E=E->next()) { String file=E->get(); if (xml_extensions.has(file.extension().to_lower())) { if (ResourceLoader::get_resource_type(file)=="PackedScene") { resource_replace_map[file]=file.basename()+".tscn"; } else { resource_replace_map[file]=file.basename()+".tres"; } } } DirAccess *directory = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); if (directory->change_dir(p_path)!=OK) { memdelete(directory); ERR_FAIL_V(ERR_CANT_OPEN); } int idx=0; for(List::Element *E=files.front();E;E=E->next()) { String path = E->get(); String extension = path.extension().to_lower(); String target_path; bool repack=false; target_path = p_path.plus_file(path.replace("res://","")); progress.step(target_path.get_file(),idx++); print_line("exporting: "+target_path); if (directory->make_dir_recursive(target_path.get_base_dir())!=OK) { memdelete(directory); ERR_FAIL_V(ERR_CANT_CREATE); } ExportData resource_data; if (xml_extensions.has(extension)) { Error err = ResourceLoader::get_export_data(path,resource_data); if (err!=OK) { memdelete(directory); ERR_FAIL_V(err); } } else if (text_extensions.has(extension)) { Error err = ResourceLoader::get_export_data(path,resource_data); if (err!=OK) { memdelete(directory); ERR_FAIL_V(err); } } else if (binary_extensions.has(extension)) { Error err = ResourceLoader::get_export_data(path,resource_data); if (err!=OK) { memdelete(directory); ERR_FAIL_V(err); } } else { //single file, copy it Error err = directory->copy(path,target_path); if (err!=OK) { memdelete(directory); ERR_FAIL_V(err); } continue; //no longer needed to do anything, just copied the file! } if (resource_data.nodes.size()==0 && resource_data.resources[resource_data.resources.size()-1].type=="PackedScene") { //must unpack a PackedScene _unpack_packed_scene(resource_data); repack=true; } _convert_resources(resource_data); if (repack) { _pack_packed_scene(resource_data); } if (xml_extensions.has(extension)) { String save_path=resource_replace_map[target_path]; _save_text(save_path,resource_data); } else if (text_extensions.has(extension)) { _save_text(target_path,resource_data); } else if (binary_extensions.has(extension)) { _save_binary(target_path,resource_data); } } memdelete(directory); _save_config(p_path); return OK; } EditorExportGodot3::EditorExportGodot3() { int idx=0; while(prop_renames[idx][0]!=NULL) { prop_rename_map[prop_renames[idx][0]]=prop_renames[idx][1]; idx++; } idx=0; while(type_renames[idx][0]!=NULL) { type_rename_map[type_renames[idx][0]]=type_renames[idx][1]; idx++; } idx=0; while(signal_renames[idx][0]!=NULL) { signal_rename_map[signal_renames[idx][0]]=signal_renames[idx][1]; idx++; } }