This commit is contained in:
Juan Linietsky 2015-10-17 10:30:08 -03:00
commit 63033aa646
75 changed files with 3541 additions and 504 deletions

3
.gitignore vendored
View file

@ -23,6 +23,9 @@ tools/editor/editor_icons.cpp
make.bat
log.txt
# Doxygen generated documentation
doc/doxygen/*
# Javascript specific
*.bc

View file

@ -51,14 +51,14 @@ PROJECT_BRIEF = "Game Engine MIT"
# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
# the logo to the output directory.
PROJECT_LOGO = E:/development/godot/logo_small.png
PROJECT_LOGO = ./logo_small.png
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
# into which the generated documentation will be written. If a relative path is
# entered, it will be relative to the location where doxygen was started. If
# left blank the current directory will be used.
OUTPUT_DIRECTORY = E:/development/godot/doxygen
OUTPUT_DIRECTORY = ./doc/doxygen/
# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
# directories (in 2 levels) under the output directory of each output format and
@ -768,7 +768,7 @@ WARN_LOGFILE =
# spaces.
# Note: If this tag is empty the current directory is searched.
INPUT = E:/development/godot
INPUT = ./core/ ./main/ ./scene/
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses

View file

@ -61,6 +61,7 @@ const char ** tests_get_names() {
"gui",
"io",
"shaderlang",
"physics",
NULL
};

View file

@ -31,8 +31,7 @@ void FuncRef::_bind_methods() {
{
MethodInfo mi;
mi.name="call";
mi.arguments.push_back( PropertyInfo( Variant::STRING, "method"));
mi.name="call_func";
Vector<Variant> defargs;
for(int i=0;i<10;i++) {
mi.arguments.push_back( PropertyInfo( Variant::NIL, "arg"+itos(i)));

View file

@ -299,10 +299,8 @@ Error decode_variant(Variant& r_variant,const uint8_t *p_buffer, int p_len,int *
ERR_FAIL_COND_V(len<12,ERR_INVALID_DATA);
Vector<StringName> names;
Vector<StringName> subnames;
bool absolute;
StringName prop;
int i=0;
uint32_t namecount=strlen&=0x7FFFFFFF;
uint32_t subnamecount = decode_uint32(buf+4);
uint32_t flags = decode_uint32(buf+8);
@ -391,7 +389,6 @@ Error decode_variant(Variant& r_variant,const uint8_t *p_buffer, int p_len,int *
ie.type=decode_uint32(&buf[0]);
ie.device=decode_uint32(&buf[4]);
uint32_t len = decode_uint32(&buf[8])-12;
if (r_len)
(*r_len)+=12;

View file

@ -231,14 +231,12 @@ Ref<ResourceImportMetadata> ResourceLoader::load_import_metadata(const String &p
local_path = Globals::get_singleton()->localize_path(p_path);
String extension=p_path.extension();
bool found=false;
Ref<ResourceImportMetadata> ret;
for (int i=0;i<loader_count;i++) {
if (!loader[i]->recognize(extension))
continue;
found=true;
Error err = loader[i]->load_import_metadata(local_path,ret);
if (err==OK)

View file

@ -1788,7 +1788,7 @@ extern int ZEXPORT unzReadCurrentFile (unzFile file, voidp buf, unsigned len)
return UNZ_PARAMERROR;
if ((pfile_in_zip_read_info->read_buffer == NULL))
if (pfile_in_zip_read_info->read_buffer==NULL)
return UNZ_END_OF_LIST_OF_FILE;
if (len==0)
return 0;

View file

@ -1114,9 +1114,9 @@ extern int ZEXPORT zipOpenNewFileInZip4_64 (zipFile file, const char* filename,
zi->ci.flag = flagBase;
if ((level==8) || (level==9))
zi->ci.flag |= 2;
if ((level==2))
if (level==2)
zi->ci.flag |= 4;
if ((level==1))
if (level==1)
zi->ci.flag |= 6;
if (password != NULL)
zi->ci.flag |= 1;

View file

@ -516,6 +516,7 @@ OS::OS() {
_target_fps=0;
_render_thread_mode=RENDER_THREAD_SAFE;
_time_scale=1.0;
_pixel_snap=false;
Math::seed(1234567);
}

View file

@ -58,6 +58,7 @@ class OS {
float _fps;
int _target_fps;
float _time_scale;
bool _pixel_snap;
char *last_error;
@ -393,7 +394,7 @@ public:
void set_time_scale(float p_scale);
float get_time_scale() const;
_FORCE_INLINE_ bool get_use_pixel_snap() const { return _pixel_snap; }
OS();
virtual ~OS();

View file

@ -286,6 +286,37 @@ NodePath::NodePath(const Vector<StringName>& p_path,const Vector<StringName>& p_
data->property=p_property;
}
void NodePath::simplify() {
if (!data)
return;
for(int i=0;i<data->path.size();i++) {
if (data->path.size()==1)
break;
if (data->path[i].operator String()==".") {
data->path.remove(i);
i--;
} else if (data->path[i].operator String()==".." && i>0 && data->path[i-1].operator String()!="." && data->path[i-1].operator String()!="..") {
//remove both
data->path.remove(i-1);
data->path.remove(i-1);
i-=2;
if (data->path.size()==0) {
data->path.push_back(".");
break;
}
}
}
}
NodePath NodePath::simplified() const {
NodePath np=*this;
np.simplify();
return np;
}
NodePath::NodePath(const String& p_path) {
data=NULL;

View file

@ -84,7 +84,10 @@ public:
bool operator==(const NodePath& p_path) const;
bool operator!=(const NodePath& p_path) const;
void operator=(const NodePath& p_path);
void simplify();
NodePath simplified() const;
NodePath(const Vector<StringName>& p_path,bool p_absolute,const String& p_property="");
NodePath(const Vector<StringName>& p_path,const Vector<StringName>& p_subpath,bool p_absolute,const String& p_property="");
NodePath(const NodePath& p_path);

View file

@ -130,7 +130,7 @@ public:
void set_name(const String& p_name);
String get_name() const;
void set_path(const String& p_path,bool p_take_over=false);
virtual void set_path(const String& p_path,bool p_take_over=false);
String get_path() const;
void set_subindex(int p_sub_index);

View file

@ -3066,7 +3066,7 @@ String String::world_wrap(int p_chars_per_line) const {
} else if (operator[](i)==' ' || operator[](i)=='\t') {
last_space=i;
} else if (operator[](i)=='\n') {
ret+=substr(from,i-from);
ret+=substr(from,i-from)+"\n";
from=i+1;
last_space=-1;
}

View file

@ -18,3 +18,11 @@ func _ready():
# Initalization here
pass
func _on_coin_area_enter( area ):
pass # replace with function body
func _on_coin_area_enter_shape( area_id, area, area_shape, area_shape ):
pass # replace with function body

View file

@ -0,0 +1 @@
filter=false

View file

@ -5905,7 +5905,7 @@
<description>
Base class of anything 2D. Canvas items are laid out in a tree and children inherit and extend the transform of their parent. CanvasItem is extended by [Control], for anything GUI related, and by [Node2D] for anything 2D engine related.
Any CanvasItem can draw. For this, the "update" function must be called, then NOTIFICATION_DRAW will be received on idle time to request redraw. Because of this, canvas items don't need to be redraw on every frame, improving the performance significan'tly. Several functions for drawing on the CanvasItem are provided (see draw_* functions). They can only be used inside the notification, signal or _draw() overrided function, though.
Canvas items are draw in tree order. By default, children are on top of their parents so a root CanvasItem will be drawn behind everything (this can be changed per item though).
Canvas items are draw in tree order. By default, children are on top of their parents so a root CanvasItem will be drawn behind everything (this can be changed per item though).
Canvas items can also be hidden (hiding also their subtree). They provide many means for changing standard parameters such as opacity (for it and the subtree) and self opacity, blend mode.
Ultimately, a transform notification can be requested, which will notify the node that its global position changed in case the parent tree changed.
</description>
@ -11556,8 +11556,11 @@
</class>
<class name="GraphEdit" inherits="Control" category="Core">
<brief_description>
GraphEdit is an area capable of showing various GraphNodes. It manages connection events between them.
</brief_description>
<description>
GraphEdit manages the showing of GraphNodes it contains, as well as connections an disconnections between them. Signals are sent for each of these two events. Disconnection between GraphNodes slots is disabled by default.
It is greatly advised to enable low processor usage mode [OS.set_low_processor_usage_mode()] when using GraphEdits.
</description>
<methods>
<method name="connect_node">
@ -11572,6 +11575,7 @@
<argument index="3" name="to_port" type="int">
</argument>
<description>
Create a connection between 'from_port' slot of 'from' GraphNode and 'to_port' slot of 'to' GraphNode. If the connection already exists, no connection is created.
</description>
</method>
<method name="is_node_connected">
@ -11586,6 +11590,7 @@
<argument index="3" name="to_port" type="int">
</argument>
<description>
Return true if the 'from_port' slot of 'from' GraphNode is connected to the 'to_port' slot of 'to' GraphNode.
</description>
</method>
<method name="disconnect_node">
@ -11598,24 +11603,28 @@
<argument index="3" name="to_port" type="int">
</argument>
<description>
Remove the connection between 'from_port' slot of 'from' GraphNode and 'to_port' slot of 'to' GraphNode, if connection exists.
</description>
</method>
<method name="get_connection_list" qualifiers="const">
<return type="Array">
</return>
<description>
Return an Array containing the list of connections. A connection consists in a structure of the form {from_slot: 0, from: "GraphNode name 0", to_slot: 1, to: "GraphNode name 1" }
</description>
</method>
<method name="set_right_disconnects">
<argument index="0" name="enable" type="bool">
</argument>
<description>
Enable the disconnection of existing connections in the visual GraphEdit by left-clicking a connection and releasing into the void.
</description>
</method>
<method name="is_right_disconnects_enabled" qualifiers="const">
<return type="bool">
</return>
<description>
Return true is the disconnection of connections is enable in the visual GraphEdit. False otherwise.
</description>
</method>
</methods>
@ -11630,6 +11639,7 @@
<argument index="3" name="to_slot" type="int">
</argument>
<description>
Signal sent to the GraphEdit when the connection between 'from_slot' slot of 'from' GraphNode and 'to_slot' slot of 'to' GraphNode is attempted to be removed.
</description>
</signal>
<signal name="connection_request">
@ -11642,6 +11652,7 @@
<argument index="3" name="to_slot" type="int">
</argument>
<description>
Signal sent to the GraphEdit when the connection between 'from_slot' slot of 'from' GraphNode and 'to_slot' slot of 'to' GraphNode is attempted to be created.
</description>
</signal>
</signals>
@ -11650,20 +11661,24 @@
</class>
<class name="GraphNode" inherits="Container" category="Core">
<brief_description>
A GraphNode is a container with several input and output slots allowing connections between GraphNodes. Slots can have different, incompatible types.
</brief_description>
<description>
A GraphNode is a container defined by a title. It can have 1 or more input and output slots, which can be enabled (shown) or disabled (not shown) and have different (incompatible) types. Colors can also be assigned to slots. A tuple of input and output slots is defined for each GUI element included in the GraphNode. Input and output connections are left and right slots, but only enabled slots are counted as connections.
</description>
<methods>
<method name="set_title">
<argument index="0" name="title" type="String">
</argument>
<description>
Set the title of the GraphNode.
</description>
</method>
<method name="get_title" qualifiers="const">
<return type="String">
</return>
<description>
Return the title of the GraphNode.
</description>
</method>
<method name="set_slot">
@ -11682,16 +11697,19 @@
<argument index="6" name="color_right" type="Color">
</argument>
<description>
Set the tuple of input/output slots defined by 'idx' ID. 'left' slots are input, 'right' are output. 'type' is an integer defining the type of the slot. Refer to description for the compatibility between slot types.
</description>
</method>
<method name="clear_slot">
<argument index="0" name="idx" type="int">
</argument>
<description>
Disable input and ouput slot whose index is 'idx'.
</description>
</method>
<method name="clear_all_slots">
<description>
Disable all input and output slots of the GraphNode.
</description>
</method>
<method name="is_slot_enabled_left" qualifiers="const">
@ -11700,6 +11718,7 @@
<argument index="0" name="idx" type="int">
</argument>
<description>
Return true if left (input) slot 'idx' is enabled. False otherwise.
</description>
</method>
<method name="get_slot_type_left" qualifiers="const">
@ -11708,6 +11727,7 @@
<argument index="0" name="idx" type="int">
</argument>
<description>
Return the (integer) type of left (input) 'idx' slot.
</description>
</method>
<method name="get_slot_color_left" qualifiers="const">
@ -11716,6 +11736,7 @@
<argument index="0" name="idx" type="int">
</argument>
<description>
Return the color set to 'idx' left (input) slot.
</description>
</method>
<method name="is_slot_enabled_right" qualifiers="const">
@ -11724,6 +11745,7 @@
<argument index="0" name="idx" type="int">
</argument>
<description>
Return true if right (output) slot 'idx' is enabled. False otherwise.
</description>
</method>
<method name="get_slot_type_right" qualifiers="const">
@ -11732,6 +11754,7 @@
<argument index="0" name="idx" type="int">
</argument>
<description>
Return the (integer) type of right (output) 'idx' slot.
</description>
</method>
<method name="get_slot_color_right" qualifiers="const">
@ -11740,30 +11763,35 @@
<argument index="0" name="idx" type="int">
</argument>
<description>
Return the color set to 'idx' right (output) slot.
</description>
</method>
<method name="set_offset">
<argument index="0" name="offset" type="Vector2">
</argument>
<description>
Set the offset of the GraphNode.
</description>
</method>
<method name="get_offset" qualifiers="const">
<return type="Vector2">
</return>
<description>
Return the offset of the GraphNode.
</description>
</method>
<method name="get_connection_output_count">
<return type="int">
</return>
<description>
Return the number of enabled output slots (connections) of the GraphNode.
</description>
</method>
<method name="get_connection_input_count">
<return type="int">
</return>
<description>
Return the number of enabled input slots (connections) to the GraphNode.
</description>
</method>
<method name="get_connection_output_pos">
@ -11772,6 +11800,7 @@
<argument index="0" name="idx" type="int">
</argument>
<description>
Return the position of the output connection 'idx'.
</description>
</method>
<method name="get_connection_output_type">
@ -11780,6 +11809,7 @@
<argument index="0" name="idx" type="int">
</argument>
<description>
Return the type of the output connection 'idx'.
</description>
</method>
<method name="get_connection_output_color">
@ -11788,6 +11818,7 @@
<argument index="0" name="idx" type="int">
</argument>
<description>
Return the color of the output connection 'idx'.
</description>
</method>
<method name="get_connection_input_pos">
@ -11796,6 +11827,7 @@
<argument index="0" name="idx" type="int">
</argument>
<description>
Return the position of the input connection 'idx'.
</description>
</method>
<method name="get_connection_input_type">
@ -11804,6 +11836,7 @@
<argument index="0" name="idx" type="int">
</argument>
<description>
Return the type of the input connection 'idx'.
</description>
</method>
<method name="get_connection_input_color">
@ -11812,28 +11845,33 @@
<argument index="0" name="idx" type="int">
</argument>
<description>
Return the color of the input connection 'idx'.
</description>
</method>
<method name="set_show_close_button">
<argument index="0" name="show" type="bool">
</argument>
<description>
Show the close button on the GraphNode if 'show' is true (disabled by default). If enabled, a connection on the signal close_request is needed for the close button to work.
</description>
</method>
<method name="is_close_button_visible" qualifiers="const">
<return type="bool">
</return>
<description>
Returns true if the close button is shown. False otherwise.
</description>
</method>
</methods>
<signals>
<signal name="raise_request">
<description>
Signal sent when the GraphNode is requested to be displayed over other ones. Happens on focusing (clicking into) the GraphNode.
</description>
</signal>
<signal name="close_request">
<description>
Signal sent on closing the GraphNode.
</description>
</signal>
<signal name="dragged">
@ -11842,10 +11880,12 @@
<argument index="1" name="to" type="Vector2">
</argument>
<description>
Signal sent when the GraphNode is dragged.
</description>
</signal>
<signal name="offset_changed">
<description>
Signal sent when the GraphNode is moved.
</description>
</signal>
</signals>
@ -17934,7 +17974,7 @@
</brief_description>
<description>
Nodes can be set as children of other nodes, resulting in a tree arrangement. Any tree of nodes is called a "Scene".
Scenes can be saved to disk, and then instanced into other scenes. This allows for very high flexibility in the architecture and data model of the projects.
Scenes can be saved to disk, and then instanced into other scenes. This allows for very high flexibility in the architecture and data model of the projects.
[SceneMainLoop] contains the "active" tree of nodes, and a node becomes active (receinving NOTIFICATION_ENTER_SCENE) when added to that tree.
A node can contain any number of nodes as a children (but there is only one tree root) with the requirement that no two childrens with the same name can exist.
Nodes can, optionally, be added to groups. This makes it easy to reach a number of nodes from the code (for example an "enemies" group).
@ -18684,11 +18724,11 @@
<description>
Operating System functions. OS Wraps the most common functionality to communicate with the host Operating System, such as:
-Mouse Grabbing
-Mouse Cursors
-Mouse Cursors
-Clipboard
-Video Mode
-Date " Time
-Timers
-Timers
-Environment Variables
-Execution of Binaries
-Command Line
@ -27567,7 +27607,7 @@
Rigid body 2D node.
</brief_description>
<description>
Rigid body 2D node. This node is used for placing rigid bodies in the scene. It can contain a number of shapes, and also shift state between regular Rigid Body to Character or even Static.
Rigid body 2D node. This node is used for placing rigid bodies in the scene. It can contain a number of shapes, and also shift state between regular Rigid Body to Character or even Static.
Character mode forbids the node from being rotated. This node can have a custom force integrator function, for writing complex physics motion behavior per node.
As a warning, don't change this node position every frame or very often. Sporadic changes work fine, but physics runs at a different granularity (fixed hz) than usual rendering (process callback) and maybe even in a separate thread, so changing this from a process loop will yield strange behavior.
</description>
@ -37719,6 +37759,18 @@
<description>
</description>
</method>
<method name="set_audio_track">
<argument index="0" name="track" type="int">
</argument>
<description>
</description>
</method>
<method name="get_audio_track" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
<method name="get_stream_name" qualifiers="const">
<return type="String">
</return>
@ -37755,6 +37807,18 @@
<description>
</description>
</method>
<method name="set_buffering_msec">
<argument index="0" name="msec" type="int">
</argument>
<description>
</description>
</method>
<method name="get_buffering_msec" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
</methods>
<constants>
</constants>
@ -37765,30 +37829,16 @@
<description>
</description>
<methods>
<method name="get_pending_frame_count" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
<method name="pop_frame">
<argument index="0" name="arg0" type="Object">
</argument>
<description>
</description>
</method>
<method name="peek_frame" qualifiers="const">
<return type="Image">
</return>
<description>
</description>
</method>
<method name="set_audio_track">
<argument index="0" name="idx" type="int">
</argument>
<description>
</description>
</method>
</methods>
<constants>
</constants>
</class>
<class name="VideoStreamTheora" inherits="VideoStream" category="Core">
<brief_description>
</brief_description>
<description>
</description>
<methods>
</methods>
<constants>
</constants>

View file

@ -4145,7 +4145,7 @@ void RasterizerGLES2::begin_frame() {
//fragment_lighting=Globals::get_singleton()->get("rasterizer/use_fragment_lighting");
#ifdef TOOLS_ENABLED
canvas_shader.set_conditional(CanvasShaderGLES2::USE_PIXEL_SNAP,GLOBAL_DEF("rasterizer/use_pixel_snap",false));
canvas_shader.set_conditional(CanvasShaderGLES2::USE_PIXEL_SNAP,GLOBAL_DEF("display/use_2d_pixel_snap",false));
shadow_filter=ShadowFilterTechnique(int(Globals::get_singleton()->get("rasterizer/shadow_filter")));
#endif
@ -10807,7 +10807,7 @@ void RasterizerGLES2::init() {
copy_shader.set_conditional(CopyShaderGLES2::USE_8BIT_HDR,!use_fp16_fb);
canvas_shader.set_conditional(CanvasShaderGLES2::USE_DEPTH_SHADOWS,read_depth_supported);
canvas_shader.set_conditional(CanvasShaderGLES2::USE_PIXEL_SNAP,GLOBAL_DEF("rasterizer/use_pixel_snap",false));
canvas_shader.set_conditional(CanvasShaderGLES2::USE_PIXEL_SNAP,GLOBAL_DEF("display/use_2d_pixel_snap",false));
npo2_textures_available=true;
//fragment_lighting=false;

View file

@ -29,7 +29,7 @@ extern "C" {
#define WEBP_USE_SSE2
#endif
#if defined(__ANDROID__) && defined(__ARM_ARCH_7A__)
#if defined(__ANDROID__) && defined(__ARM_ARCH_7A__) && defined(__ARM_NEON__)
#define WEBP_ANDROID_NEON // Android targets that might support NEON
#endif

View file

@ -701,6 +701,7 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas
GLOBAL_DEF("display/resizable",video_mode.resizable);
GLOBAL_DEF("display/test_width",0);
GLOBAL_DEF("display/test_height",0);
OS::get_singleton()->_pixel_snap=GLOBAL_DEF("display/use_2d_pixel_snap",false);
if (rtm==-1) {
rtm=GLOBAL_DEF("render/thread_model",OS::RENDER_THREAD_SAFE);
if (rtm>=1) //hack for now
@ -1006,61 +1007,49 @@ bool Main::start() {
bool export_debug=false;
List<String> args = OS::get_singleton()->get_cmdline_args();
for (int i=0;i<args.size();i++) {
if (args[i]=="-doctool" && i <(args.size()-1)) {
doc_tool=args[i+1];
//parameters that have an argument to the right
if (i < (args.size()-1)) {
if (args[i]=="-doctool") {
doc_tool=args[i+1];
} else if (args[i]=="-script" || args[i]=="-s") {
script=args[i+1];
} else if (args[i]=="-level" || args[i]=="-l") {
OS::get_singleton()->_custom_level=args[i+1];
} else if (args[i]=="-test") {
test=args[i+1];
} else if (args[i]=="-optimize") {
optimize=args[i+1];
} else if (args[i]=="-optimize_preset") {
optimize_preset=args[i+1];
} else if (args[i]=="-export") {
editor=true; //needs editor
_export_platform=args[i+1];
} else if (args[i]=="-export_debug") {
editor=true; //needs editor
_export_platform=args[i+1];
export_debug=true;
} else if (args[i]=="-import") {
editor=true; //needs editor
_import=args[i+1];
} else if (args[i]=="-import_script") {
editor=true; //needs editor
_import_script=args[i+1];
} else if (args[i]=="-dumpstrings") {
editor=true; //needs editor
dumpstrings=args[i+1];
}
i++;
}else if (args[i]=="-nodocbase") {
}
//parameters that do not have an argument to the right
if (args[i]=="-nodocbase") {
doc_base=false;
} else if ((args[i]=="-script" || args[i]=="-s") && i <(args.size()-1)) {
script=args[i+1];
i++;
} else if ((args[i]=="-level" || args[i]=="-l") && i <(args.size()-1)) {
OS::get_singleton()->_custom_level=args[i+1];
i++;
} else if (args[i]=="-test" && i <(args.size()-1)) {
test=args[i+1];
i++;
} else if (args[i]=="-optimize" && i <(args.size()-1)) {
optimize=args[i+1];
i++;
} else if (args[i]=="-optimize_preset" && i <(args.size()-1)) {
optimize_preset=args[i+1];
i++;
} else if (args[i]=="-export" && i <(args.size()-1)) {
editor=true; //needs editor
_export_platform=args[i+1];
i++;
} else if (args[i]=="-export_debug" && i <(args.size()-1)) {
editor=true; //needs editor
_export_platform=args[i+1];
export_debug=true;
i++;
} else if (args[i]=="-import" && i <(args.size()-1)) {
editor=true; //needs editor
_import=args[i+1];
i++;
} else if (args[i]=="-import_script" && i <(args.size()-1)) {
editor=true; //needs editor
_import_script=args[i+1];
i++;
} else if (args[i]=="-noquit" ) {
} else if (args[i]=="-noquit") {
noquit=true;
} else if (args[i]=="-dumpstrings" && i <(args.size()-1)) {
editor=true; //needs editor
dumpstrings=args[i+1];
i++;
} else if (args[i]=="-editor" || args[i]=="-e") {
editor=true;
} else if (args[i]=="-convert_old") {
convert_old=true;
} else if (args[i]=="-editor" || args[i]=="-e") {
editor=true;
} else if (args[i].length() && args[i][0] != '-' && game_path == "") {
game_path=args[i];
}
}

View file

@ -904,6 +904,15 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
r_ret = gdscr->_new(NULL,0,r_error);
GDInstance *ins = static_cast<GDInstance*>(static_cast<Object*>(r_ret)->get_script_instance());
Ref<GDScript> gd_ref = ins->get_script();
for(Map<StringName,GDScript::MemberInfo>::Element *E = gd_ref->member_indices.front(); E; E = E->next()) {
if(d.has(E->key())) {
ins->members[E->get().index] = d[E->key()];
}
}
} break;
case HASH: {

View file

@ -2421,6 +2421,16 @@ void GDParser::_parse_class(ClassNode *p_class) {
}; //fallthrough to use the same
case Variant::REAL: {
if (tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier()=="EASE") {
current_export.hint=PROPERTY_HINT_EXP_EASING;
tokenizer->advance();
if (tokenizer->get_token()!=GDTokenizer::TK_PARENTHESIS_CLOSE) {
_set_error("Expected ')' in hint.");
return;
}
break;
}
float sign=1.0;
if (tokenizer->get_token()==GDTokenizer::TK_OP_SUB) {
@ -2571,6 +2581,17 @@ void GDParser::_parse_class(ClassNode *p_class) {
}
break;
}
if (tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier()=="MULTILINE") {
current_export.hint=PROPERTY_HINT_MULTILINE_TEXT;
tokenizer->advance();
if (tokenizer->get_token()!=GDTokenizer::TK_PARENTHESIS_CLOSE) {
_set_error("Expected ')' in hint.");
return;
}
break;
}
} break;
case Variant::COLOR: {
@ -2607,23 +2628,16 @@ void GDParser::_parse_class(ClassNode *p_class) {
} else if (tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER) {
String identifier = tokenizer->get_token_identifier();
if (identifier == "flag") {
current_export.type=Variant::INT;
current_export.hint=PROPERTY_HINT_ALL_FLAGS;
}else if (identifier == "multiline"){
current_export.type=Variant::STRING;
current_export.hint=PROPERTY_HINT_MULTILINE_TEXT;
} else {
if (!ObjectTypeDB::is_type(identifier,"Resource")) {
current_export=PropertyInfo();
_set_error("Export hint not a type or resource.");
}
current_export.type=Variant::OBJECT;
current_export.hint=PROPERTY_HINT_RESOURCE_TYPE;
current_export.hint_string=identifier;
if (!ObjectTypeDB::is_type(identifier,"Resource")) {
current_export=PropertyInfo();
_set_error("Export hint not a type or resource.");
}
current_export.type=Variant::OBJECT;
current_export.hint=PROPERTY_HINT_RESOURCE_TYPE;
current_export.hint_string=identifier;
tokenizer->advance();
}

View file

@ -236,13 +236,12 @@ void AudioDriverOpenSL::start(){
ERR_FAIL_COND( res !=SL_RESULT_SUCCESS );
/* Initialize arrays required[] and iidArray[] */
int i;
SLboolean required[MAX_NUMBER_INTERFACES];
SLInterfaceID iidArray[MAX_NUMBER_INTERFACES];
#if 0
for (i=0; i<MAX_NUMBER_INTERFACES; i++)
for (int i=0; i<MAX_NUMBER_INTERFACES; i++)
{
required[i] = SL_BOOLEAN_FALSE;
iidArray[i] = SL_IID_NULL;

View file

@ -127,7 +127,7 @@ static __inline__ void x86_cpuid(int func, int values[4])
static int
get_file_size(const char* pathname)
{
int fd, ret, result = 0;
int fd, result = 0;
char buffer[256];
fd = open(pathname, O_RDONLY);

View file

@ -20,15 +20,14 @@ def can_build():
def get_opts():
return [
('ANDROID_NDK_ROOT', 'the path to Android NDK', os.environ.get("ANDROID_NDK_ROOT", 0)),
('NDK_TOOLCHAIN', 'toolchain to use for the NDK',"arm-eabi-4.4.0"),
#android 2.3
('ndk_platform', 'compile for platform: (2.2,2.3)',"2.2"),
('NDK_TARGET', 'toolchain to use for the NDK',"arm-linux-androideabi-4.8"),
('android_stl','enable STL support in android port (for modules)','no'),
('armv6','compile for older phones running arm v6 (instead of v7+neon+smp)','no'),
('x86','Xompile for Android-x86','no')
('ANDROID_NDK_ROOT', 'the path to Android NDK', os.environ.get("ANDROID_NDK_ROOT", 0)),
('NDK_TOOLCHAIN', 'toolchain to use for the NDK',"arm-eabi-4.4.0"),
('NDK_TARGET', 'toolchain to use for the NDK',"arm-linux-androideabi-4.8"),
('NDK_TARGET_X86', 'toolchain to use for the NDK x86',"x86-4.8"),
('ndk_platform', 'compile for platform: (android-<api> , example: android-15)',"android-15"),
('android_arch', 'select compiler architecture: (armv7/armv6/x86)',"armv7"),
('android_neon','enable neon (armv7 only)',"yes"),
('android_stl','enable STL support in android port (for modules)',"no")
]
def get_flags():
@ -92,8 +91,13 @@ def configure(env):
env['SPAWN'] = mySpawn
if env['x86']=='yes':
env['NDK_TARGET']='x86-4.8'
ndk_platform=env['ndk_platform']
if env['android_arch'] not in ['armv7','armv6','x86']:
env['android_arch']='armv7'
if env['android_arch']=='x86':
env['NDK_TARGET']=env['NDK_TARGET_X86']
if env['PLATFORM'] == 'win32':
import methods
@ -101,22 +105,28 @@ def configure(env):
#env['SPAWN'] = methods.win32_spawn
env['SHLIBSUFFIX'] = '.so'
# env.android_source_modules.append("../libs/apk_expansion")
#env.android_source_modules.append("../libs/apk_expansion")
env.android_source_modules.append("../libs/google_play_services")
env.android_source_modules.append("../libs/downloader_library")
env.android_source_modules.append("../libs/play_licensing")
ndk_platform=""
ndk_platform="android-15"
print("Godot Android!!!!!")
neon_text=""
if env["android_arch"]=="armv7" and env['android_neon']=='yes':
neon_text=" (with neon)"
print("Godot Android!!!!! ("+env['android_arch']+")"+neon_text)
env.Append(CPPPATH=['#platform/android'])
if env['x86']=='yes':
env.extra_suffix=".x86"
if env['android_arch']=='x86':
env.extra_suffix=".x86"+env.extra_suffix
elif env['android_arch']=='armv6':
env.extra_suffix=".armv6"+env.extra_suffix
elif env["android_arch"]=="armv7":
if env['android_neon']=='yes':
env.extra_suffix=".armv7.neon"+env.extra_suffix
else:
env.extra_suffix=".armv7"+env.extra_suffix
gcc_path=env["ANDROID_NDK_ROOT"]+"/toolchains/"+env["NDK_TARGET"]+"/prebuilt/";
import os
@ -134,7 +144,7 @@ def configure(env):
env['ENV']['PATH'] = gcc_path+":"+env['ENV']['PATH']
if env['x86']=='yes':
if env['android_arch']=='x86':
env['CC'] = gcc_path+'/i686-linux-android-gcc'
env['CXX'] = gcc_path+'/i686-linux-android-g++'
env['AR'] = gcc_path+"/i686-linux-android-ar"
@ -147,7 +157,7 @@ def configure(env):
env['RANLIB'] = gcc_path+"/arm-linux-androideabi-ranlib"
env['AS'] = gcc_path+"/arm-linux-androideabi-as"
if env['x86']=='yes':
if env['android_arch']=='x86':
env['ARCH'] = 'arch-x86'
else:
env['ARCH'] = 'arch-arm'
@ -161,12 +171,18 @@ def configure(env):
env.Append(CPPPATH=[gcc_include])
# env['CCFLAGS'] = string.split('-DNO_THREADS -MMD -MP -MF -fpic -ffunction-sections -funwind-tables -fstack-protector -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -Wno-psabi -march=armv5te -mtune=xscale -msoft-float -fno-exceptions -mthumb -fno-strict-aliasing -DANDROID -Wa,--noexecstack -DGLES2_ENABLED ')
if env['x86']=='yes':
env['neon_enabled']=False
if env['android_arch']=='x86':
env['CCFLAGS'] = string.split('-DNO_STATVFS -MMD -MP -MF -fpic -ffunction-sections -funwind-tables -fstack-protector -fvisibility=hidden -D__GLIBC__ -Wno-psabi -ftree-vectorize -funsafe-math-optimizations -fno-strict-aliasing -DANDROID -Wa,--noexecstack -DGLES2_ENABLED')
elif env["armv6"]!="no":
elif env["android_arch"]=="armv6":
env['CCFLAGS'] = string.split('-DNO_STATVFS -MMD -MP -MF -fpic -ffunction-sections -funwind-tables -fstack-protector -fvisibility=hidden -D__ARM_ARCH_6__ -D__GLIBC__ -Wno-psabi -march=armv6 -mfpu=vfp -mfloat-abi=softfp -funsafe-math-optimizations -fno-strict-aliasing -DANDROID -Wa,--noexecstack -DGLES2_ENABLED')
else:
env['CCFLAGS'] = string.split('-DNO_STATVFS -MMD -MP -MF -fpic -ffunction-sections -funwind-tables -fstack-protector -fvisibility=hidden -D__ARM_ARCH_7__ -D__GLIBC__ -Wno-psabi -march=armv6 -mfpu=neon -mfloat-abi=softfp -ftree-vectorize -funsafe-math-optimizations -fno-strict-aliasing -DANDROID -Wa,--noexecstack -DGLES2_ENABLED')
elif env["android_arch"]=="armv7":
env['CCFLAGS'] = string.split('-DNO_STATVFS -MMD -MP -MF -fpic -ffunction-sections -funwind-tables -fstack-protector -fvisibility=hidden -D__ARM_ARCH_7__ -D__ARM_ARCH_7A__ -D__GLIBC__ -Wno-psabi -march=armv7-a -mfloat-abi=softfp -ftree-vectorize -funsafe-math-optimizations -fno-strict-aliasing -DANDROID -Wa,--noexecstack -DGLES2_ENABLED')
if env['android_neon']=='yes':
env['neon_enabled']=True
env.Append(CCFLAGS=['-mfpu=neon','-D__ARM_NEON__'])
else:
env.Append(CCFLAGS=['-mfpu=vfpv3-d16'])
env.Append(LDPATH=[ld_path])
env.Append(LIBS=['OpenSLES'])
@ -190,9 +206,6 @@ def configure(env):
env.Append(CCFLAGS=['-D_DEBUG', '-g1', '-Wall', '-O0', '-DDEBUG_ENABLED'])
env.Append(CPPFLAGS=['-DDEBUG_MEMORY_ALLOC'])
if env["armv6"] == "no" and env['x86'] != 'yes':
env['neon_enabled']=True
env.Append(CPPFLAGS=['-DANDROID_ENABLED', '-DUNIX_ENABLED', '-DNO_FCNTL','-DMPC_FIXED_POINT'])
# env.Append(CPPFLAGS=['-DANDROID_ENABLED', '-DUNIX_ENABLED','-DMPC_FIXED_POINT'])
@ -202,9 +215,17 @@ def configure(env):
if (env['android_stl']=='yes'):
#env.Append(CCFLAGS=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/system/include"])
env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gnu-libstdc++/4.4.3/include"])
env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gnu-libstdc++/4.4.3/libs/armeabi/include"])
env.Append(LIBPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gnu-libstdc++/4.4.3/libs/armeabi"])
env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gnu-libstdc++/4.8/include"])
if env['android_arch']=='x86':
env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gnu-libstdc++/4.8/libs/x86/include"])
env.Append(LIBPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gnu-libstdc++/4.8/libs/x86"])
elif env['android_arch']=='armv6':
env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gnu-libstdc++/4.8/libs/armeabi/include"])
env.Append(LIBPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gnu-libstdc++/4.8/libs/armeabi"])
elif env["android_arch"]=="armv7":
env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gnu-libstdc++/4.8/libs/armeabi-v7a/include"])
env.Append(LIBPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gnu-libstdc++/4.8/libs/armeabi-v7a"])
env.Append(LIBS=["gnustl_static","supc++"])
env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cpufeatures"])
@ -215,10 +236,12 @@ def configure(env):
env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gabi++/include"])
env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cpufeatures"])
if env['x86']=='yes':
if env['android_arch']=='x86':
env.Append(LIBPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gabi++/libs/x86"])
else:
elif env["android_arch"]=="armv6":
env.Append(LIBPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gabi++/libs/armeabi"])
elif env["android_arch"]=="armv7":
env.Append(LIBPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gabi++/libs/armeabi-v7a"])
env.Append(LIBS=['gabi++_static'])
env.Append(CCFLAGS=["-fno-exceptions",'-DNO_SAFE_CAST'])

View file

@ -1,6 +0,0 @@
/** Automatically generated file. DO NOT MODIFY */
package com.android.vending.expansion.downloader;
public final class BuildConfig {
public final static boolean DEBUG = false;
}

View file

@ -1,73 +0,0 @@
/* AUTO-GENERATED FILE. DO NOT MODIFY.
*
* This class was automatically generated by the
* aapt tool from the resource data it found. It
* should not be modified by hand.
*/
package com.android.vending.expansion.downloader;
public final class R {
public static final class attr {
}
public static final class drawable {
public static int notify_panel_notification_icon_bg=0x7f020000;
}
public static final class id {
public static int appIcon=0x7f060001;
public static int description=0x7f060007;
public static int notificationLayout=0x7f060000;
public static int progress_bar=0x7f060006;
public static int progress_bar_frame=0x7f060005;
public static int progress_text=0x7f060002;
public static int time_remaining=0x7f060004;
public static int title=0x7f060003;
}
public static final class layout {
public static int status_bar_ongoing_event_progress_bar=0x7f030000;
}
public static final class string {
public static int kilobytes_per_second=0x7f040014;
/** When a download completes, a notification is displayed, and this
string is used to indicate that the download successfully completed.
Note that such a download could have been initiated by a variety of
applications, including (but not limited to) the browser, an email
application, a content marketplace.
*/
public static int notification_download_complete=0x7f040000;
/** When a download completes, a notification is displayed, and this
string is used to indicate that the download failed.
Note that such a download could have been initiated by a variety of
applications, including (but not limited to) the browser, an email
application, a content marketplace.
*/
public static int notification_download_failed=0x7f040001;
public static int state_completed=0x7f040007;
public static int state_connecting=0x7f040005;
public static int state_downloading=0x7f040006;
public static int state_failed=0x7f040013;
public static int state_failed_cancelled=0x7f040012;
public static int state_failed_fetching_url=0x7f040010;
public static int state_failed_sdcard_full=0x7f040011;
public static int state_failed_unlicensed=0x7f04000f;
public static int state_fetching_url=0x7f040004;
public static int state_idle=0x7f040003;
public static int state_paused_by_request=0x7f04000a;
public static int state_paused_network_setup_failure=0x7f040009;
public static int state_paused_network_unavailable=0x7f040008;
public static int state_paused_roaming=0x7f04000d;
public static int state_paused_sdcard_unavailable=0x7f04000e;
public static int state_paused_wifi_disabled=0x7f04000c;
public static int state_paused_wifi_unavailable=0x7f04000b;
public static int state_unknown=0x7f040002;
public static int time_remaining=0x7f040015;
public static int time_remaining_notification=0x7f040016;
}
public static final class style {
public static int ButtonBackground=0x7f050003;
public static int NotificationText=0x7f050000;
public static int NotificationTextSecondary=0x7f050004;
public static int NotificationTextShadow=0x7f050001;
public static int NotificationTitle=0x7f050002;
}
}

View file

@ -53,7 +53,6 @@ Error AudioDriverBB10::init(const char* p_name) {
dev_name = (char *) p_name;
}
printf("******** reconnecting to device %s\n", dev_name);
int card, dev;
int ret = snd_pcm_open_name(&pcm_handle, dev_name, SND_PCM_OPEN_PLAYBACK);
ERR_FAIL_COND_V(ret < 0, FAILED);
pcm_open = true;

View file

@ -157,6 +157,8 @@ public:
Error shell_open(String p_uri);
void push_input(const InputEvent& p_event);
String get_locale() const;
virtual void set_video_mode(const VideoMode& p_video_mode,int p_screen=0);
virtual VideoMode get_video_mode(int p_screen=0) const;
virtual void get_fullscreen_mode_list(List<VideoMode> *p_list,int p_screen=0) const;

View file

@ -1254,6 +1254,11 @@ Error OS_OSX::shell_open(String p_uri) {
return OK;
}
String OS_OSX::get_locale() const {
NSString* preferredLang = [[NSLocale preferredLanguages] objectAtIndex:0];
return [preferredLang UTF8String];
}
void OS_OSX::swap_buffers() {
[context flushBuffer];

View file

@ -79,6 +79,13 @@ Error TCPServerWinsock::listen(uint16_t p_port,const List<String> *p_accepted_ho
my_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP TODO: use p_accepted_hosts
memset(my_addr.sin_zero, '\0', sizeof my_addr.sin_zero);
int reuse=1;
if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) < 0) {
printf("REUSEADDR failed!");
}
if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof my_addr) != SOCKET_ERROR) {
if (::listen(sockfd, SOMAXCONN) == SOCKET_ERROR) {

View file

@ -892,7 +892,13 @@ void OS_X11::set_window_maximized(bool p_enabled) {
XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
XWindowAttributes xwa;
XGetWindowAttributes(x11_display,DefaultRootWindow(x11_display),&xwa);
current_videomode.width = xwa.width;
current_videomode.height = xwa.height;
maximized = p_enabled;
visual_server->init();
}
bool OS_X11::is_window_maximized() const {

View file

@ -28,6 +28,8 @@
/*************************************************************************/
#include "animated_sprite.h"
#include "scene/scene_string_names.h"
#include "os/os.h"
void AnimatedSprite::edit_set_pivot(const Point2& p_pivot) {
set_offset(p_pivot);
@ -153,6 +155,9 @@ void AnimatedSprite::_notification(int p_what) {
if (centered)
ofs-=s/2;
if (OS::get_singleton()->get_use_pixel_snap()) {
ofs=ofs.floor();
}
Rect2 dst_rect(ofs,s);
if (hflip)

View file

@ -126,7 +126,7 @@ void Joint2D::_bind_methods() {
ADD_PROPERTY( PropertyInfo( Variant::NODE_PATH, "node_a"), _SCS("set_node_a"),_SCS("get_node_a") );
ADD_PROPERTY( PropertyInfo( Variant::NODE_PATH, "node_b"), _SCS("set_node_b"),_SCS("get_node_b") );
ADD_PROPERTY( PropertyInfo( Variant::REAL, "bias/bias",PROPERTY_HINT_RANGE,"0,0.9,0.01"), _SCS("set_bias"),_SCS("get_bias") );
ADD_PROPERTY( PropertyInfo( Variant::REAL, "bias/bias",PROPERTY_HINT_RANGE,"0,0.9,0.001"), _SCS("set_bias"),_SCS("get_bias") );
}
@ -175,15 +175,37 @@ RID PinJoint2D::_configure_joint() {
//add a collision exception between both
Physics2DServer::get_singleton()->body_add_collision_exception(body_a->get_rid(),body_b->get_rid());
}
return Physics2DServer::get_singleton()->pin_joint_create(get_global_transform().get_origin(),body_a->get_rid(),body_b?body_b->get_rid():RID());
RID pj = Physics2DServer::get_singleton()->pin_joint_create(get_global_transform().get_origin(),body_a->get_rid(),body_b?body_b->get_rid():RID());
Physics2DServer::get_singleton()->pin_joint_set_param(pj, Physics2DServer::PIN_JOINT_SOFTNESS, softness);
return pj;
}
void PinJoint2D::set_softness(real_t p_softness) {
softness=p_softness;
update();
if (get_joint().is_valid())
Physics2DServer::get_singleton()->pin_joint_set_param(get_joint(), Physics2DServer::PIN_JOINT_SOFTNESS, p_softness);
}
real_t PinJoint2D::get_softness() const {
return softness;
}
void PinJoint2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_softness","softness"), &PinJoint2D::set_softness);
ObjectTypeDB::bind_method(_MD("get_softness"), &PinJoint2D::get_softness);
ADD_PROPERTY( PropertyInfo( Variant::REAL, "softness", PROPERTY_HINT_EXP_RANGE,"0.00,16,0.01"), _SCS("set_softness"), _SCS("get_softness"));
}
PinJoint2D::PinJoint2D() {
softness = 0;
}

View file

@ -72,13 +72,17 @@ class PinJoint2D : public Joint2D {
OBJ_TYPE(PinJoint2D,Joint2D);
real_t softness;
protected:
void _notification(int p_what);
virtual RID _configure_joint();
static void _bind_methods();
public:
void set_softness(real_t p_stiffness);
real_t get_softness() const;
PinJoint2D();
};

View file

@ -53,6 +53,16 @@ uint32_t RayCast2D::get_layer_mask() const {
return layer_mask;
}
void RayCast2D::set_type_mask(uint32_t p_mask) {
type_mask=p_mask;
}
uint32_t RayCast2D::get_type_mask() const {
return type_mask;
}
bool RayCast2D::is_colliding() const{
return collided;
@ -162,7 +172,7 @@ void RayCast2D::_notification(int p_what) {
Physics2DDirectSpaceState::RayResult rr;
if (dss->intersect_ray(gt.get_origin(),gt.xform(to),rr,exclude,layer_mask)) {
if (dss->intersect_ray(gt.get_origin(),gt.xform(to),rr,exclude,layer_mask,type_mask)) {
collided=true;
against=rr.collider_id;
@ -241,9 +251,13 @@ void RayCast2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_layer_mask","mask"),&RayCast2D::set_layer_mask);
ObjectTypeDB::bind_method(_MD("get_layer_mask"),&RayCast2D::get_layer_mask);
ObjectTypeDB::bind_method(_MD("set_type_mask","mask"),&RayCast2D::set_type_mask);
ObjectTypeDB::bind_method(_MD("get_type_mask"),&RayCast2D::get_type_mask);
ADD_PROPERTY(PropertyInfo(Variant::BOOL,"enabled"),_SCS("set_enabled"),_SCS("is_enabled"));
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2,"cast_to"),_SCS("set_cast_to"),_SCS("get_cast_to"));
ADD_PROPERTY(PropertyInfo(Variant::INT,"layer_mask",PROPERTY_HINT_ALL_FLAGS),_SCS("set_layer_mask"),_SCS("get_layer_mask"));
ADD_PROPERTY(PropertyInfo(Variant::INT,"type_mask",PROPERTY_HINT_FLAGS,"Static,Kinematic,Rigid,Character,Area"),_SCS("set_type_mask"),_SCS("get_type_mask"));
}
RayCast2D::RayCast2D() {
@ -253,5 +267,6 @@ RayCast2D::RayCast2D() {
collided=false;
against_shape=0;
layer_mask=1;
type_mask=Physics2DDirectSpaceState::TYPE_MASK_COLLISION;
cast_to=Vector2(0,50);
}

View file

@ -44,6 +44,7 @@ class RayCast2D : public Node2D {
Vector2 collision_normal;
Set<RID> exclude;
uint32_t layer_mask;
uint32_t type_mask;
Vector2 cast_to;
@ -62,6 +63,9 @@ public:
void set_layer_mask(uint32_t p_mask);
uint32_t get_layer_mask() const;
void set_type_mask(uint32_t p_mask);
uint32_t get_type_mask() const;
bool is_colliding() const;
Object *get_collider() const;
int get_collider_shape() const;

View file

@ -30,6 +30,7 @@
#include "core/core_string_names.h"
#include "scene/scene_string_names.h"
#include "scene/main/viewport.h"
#include "os/os.h"
void Sprite::edit_set_pivot(const Point2& p_pivot) {
@ -85,6 +86,9 @@ void Sprite::_notification(int p_what) {
Point2 ofs=offset;
if (centered)
ofs-=s/2;
if (OS::get_singleton()->get_use_pixel_snap()) {
ofs=ofs.floor();
}
Rect2 dst_rect(ofs,s);
@ -422,6 +426,9 @@ void ViewportSprite::_notification(int p_what) {
if (centered)
ofs-=s/2;
if (OS::get_singleton()->get_use_pixel_snap()) {
ofs=ofs.floor();
}
Rect2 dst_rect(ofs,s);
texture->draw_rect_region(ci,dst_rect,src_rect,modulate);

View file

@ -323,8 +323,10 @@ void PopupMenu::_input_event(const InputEvent &p_event) {
invalidated_click=false;
break;
}
if (over<0 || items[over].separator || items[over].disabled)
if (over<0 || items[over].separator || items[over].disabled) {
hide();
break; //non-activable
}
if (items[over].submenu!="") {

View file

@ -709,7 +709,7 @@ void TextEdit::_notification(int p_what) {
if (in_region==-1 && !in_keyword && is_char && !prev_is_char) {
int to=j;
while(_is_text_char(str[to]) && to<str.length())
while(to<str.length() && _is_text_char(str[to]))
to++;
uint32_t hash = String::hash(&str[j],to-j);

View file

@ -0,0 +1,74 @@
#include "instance_placeholder.h"
#include "scene/resources/packed_scene.h"
#include "io/resource_loader.h"
bool InstancePlaceholder::_set(const StringName& p_name, const Variant& p_value) {
PropSet ps;
ps.name=p_name;
ps.value=p_value;
stored_values.push_back(ps);
return true;
}
bool InstancePlaceholder::_get(const StringName& p_name,Variant &r_ret) const{
return false;
}
void InstancePlaceholder::_get_property_list( List<PropertyInfo> *p_list) const{
}
void InstancePlaceholder::set_path(const String& p_name) {
path=p_name;
}
String InstancePlaceholder::get_path() const {
return path;
}
void InstancePlaceholder::replace_by_instance(const Ref<PackedScene> &p_custom_scene){
ERR_FAIL_COND(!is_inside_tree());
Node *base = get_parent();
if (!base)
return;
Ref<PackedScene> ps;
if (p_custom_scene.is_valid())
ps = p_custom_scene;
else
ps = ResourceLoader::load(path,"PackedScene");
if (!ps.is_valid())
return;
Node *scene = ps->instance();
scene->set_name(get_name());
int pos = get_position_in_parent();
for(List<PropSet>::Element *E=stored_values.front();E;E=E->next()) {
scene->set(E->get().name,E->get().value);
}
queue_delete();
base->remove_child(this);
base->add_child(scene);
base->move_child(scene,pos);
}
void InstancePlaceholder::_bind_methods() {
ObjectTypeDB::bind_method(_MD("replace_by_instance","custom_scene:PackedScene"),&InstancePlaceholder::replace_by_instance,DEFVAL(Variant()));
}
InstancePlaceholder::InstancePlaceholder() {
}

View file

@ -0,0 +1,37 @@
#ifndef INSTANCE_PLACEHOLDER_H
#define INSTANCE_PLACEHOLDER_H
#include "scene/main/node.h"
class PackedScene;
class InstancePlaceholder : public Node {
OBJ_TYPE(InstancePlaceholder,Node);
String path;
struct PropSet {
StringName name;
Variant value;
};
List<PropSet> stored_values;
protected:
bool _set(const StringName& p_name, const Variant& p_value);
bool _get(const StringName& p_name,Variant &r_ret) const;
void _get_property_list( List<PropertyInfo> *p_list) const;
static void _bind_methods();
public:
void set_path(const String& p_name);
String get_path() const;
void replace_by_instance(const Ref<PackedScene>& p_custom_scene=Ref<PackedScene>());
InstancePlaceholder();
};
#endif // INSTANCE_PLACEHOLDER_H

View file

@ -841,6 +841,20 @@ Node *Node::get_child(int p_index) const {
return data.children[p_index];
}
Node *Node::_get_child_by_name(const StringName& p_name) const {
int cc=data.children.size();
Node* const* cd=data.children.ptr();
for(int i=0;i<cc;i++){
if (cd[i]->data.name==p_name)
return cd[i];
}
return NULL;
}
Node *Node::_get_node(const NodePath& p_path) const {
ERR_FAIL_COND_V( !data.inside_tree && p_path.is_absolute(), NULL );
@ -906,8 +920,10 @@ Node *Node::_get_node(const NodePath& p_path) const {
Node *Node::get_node(const NodePath& p_path) const {
Node *node = _get_node(p_path);
ERR_EXPLAIN("Node not found: "+p_path);
ERR_FAIL_COND_V(!node,NULL);
if (!node) {
ERR_EXPLAIN("Node not found: "+p_path);
ERR_FAIL_COND_V(!node,NULL);
}
return node;
}
@ -1036,6 +1052,7 @@ void Node::get_owned_by(Node *p_by,List<Node*> *p_owned) {
void Node::_set_owner_nocheck(Node* p_owner) {
ERR_FAIL_COND(data.owner);
data.owner=p_owner;
data.owner->data.owned.push_back( this );
data.OW = data.owner->data.owned.back();
@ -1332,7 +1349,29 @@ String Node::get_filename() const {
return data.filename;
}
void Node::set_editable_instance(Node* p_node,bool p_editable) {
ERR_FAIL_NULL(p_node);
ERR_FAIL_COND(!is_a_parent_of(p_node));
NodePath p = get_path_to(p_node);
if (!p_editable)
data.editable_instances.erase(p);
else
data.editable_instances[p]=true;
}
bool Node::is_editable_instance(Node *p_node) const {
if (!p_node)
return false; //easier, null is never editable :)
ERR_FAIL_COND_V(!is_a_parent_of(p_node),false);
NodePath p = get_path_to(p_node);
return data.editable_instances.has(p);
}
#if 0
void Node::generate_instance_state() {
@ -1383,13 +1422,36 @@ Dictionary Node::get_instance_state() const {
return data.instance_state;
}
Vector<StringName> Node::get_instance_groups() const {
#endif
return data.instance_groups;
void Node::set_scene_instance_state(const Ref<SceneState>& p_state) {
data.instance_state=p_state;
}
Vector<Node::Connection> Node::get_instance_connections() const{
return data.instance_connections;
Ref<SceneState> Node::get_scene_instance_state() const{
return data.instance_state;
}
void Node::set_scene_inherited_state(const Ref<SceneState>& p_state) {
data.inherited_state=p_state;
}
Ref<SceneState> Node::get_scene_inherited_state() const{
return data.inherited_state;
}
void Node::set_scene_instance_load_placeholder(bool p_enable) {
data.use_placeholder=p_enable;
}
bool Node::get_scene_instance_load_placeholder() const{
return data.use_placeholder;
}
int Node::get_position_in_parent() const {
@ -1931,7 +1993,7 @@ void Node::_bind_methods() {
ObjectTypeDB::bind_method(_MD("has_node","path"),&Node::has_node);
ObjectTypeDB::bind_method(_MD("get_node:Node","path"),&Node::get_node);
ObjectTypeDB::bind_method(_MD("get_parent:Parent"),&Node::get_parent);
ObjectTypeDB::bind_method(_MD("find_node:Node","mask","recursive","owned"),&Node::get_node,DEFVAL(true),DEFVAL(true));
ObjectTypeDB::bind_method(_MD("find_node:Node","mask","recursive","owned"),&Node::find_node,DEFVAL(true),DEFVAL(true));
ObjectTypeDB::bind_method(_MD("has_node_and_resource","path"),&Node::has_node_and_resource);
ObjectTypeDB::bind_method(_MD("get_node_and_resource","path"),&Node::_get_node_and_resource);
@ -2049,6 +2111,7 @@ Node::Node() {
data.parent_owned=false;
data.in_constructor=true;
data.viewport=NULL;
data.use_placeholder=false;
}
Node::~Node() {
@ -2065,3 +2128,4 @@ Node::~Node() {
}
////////////////////////////////

View file

@ -38,6 +38,7 @@
class Viewport;
class SceneState;
class Node : public Object {
OBJ_TYPE( Node, Object );
@ -69,9 +70,10 @@ private:
struct Data {
String filename;
Dictionary instance_state;
Vector<StringName> instance_groups;
Vector<Connection> instance_connections;
Ref<SceneState> instance_state;
Ref<SceneState> inherited_state;
HashMap<NodePath,int> editable_instances;
Node *parent;
Node *owner;
@ -96,6 +98,7 @@ private:
PauseMode pause_mode;
Node *pause_owner;
// variables used to properly sort the node when processing, ignored otherwise
//should move all the stuff below to bits
bool fixed_process;
bool idle_process;
@ -105,6 +108,9 @@ private:
bool parent_owned;
bool in_constructor;
bool use_placeholder;
} data;
@ -112,6 +118,7 @@ private:
virtual bool _use_builtin_script() const { return true; }
Node *_get_node(const NodePath& p_path) const;
Node *_get_child_by_name(const StringName& p_name) const;
@ -151,7 +158,7 @@ protected:
static void _bind_methods();
friend class PackedScene;
friend class SceneState;
void _add_child_nocheck(Node* p_child,const StringName& p_name);
void _set_owner_nocheck(Node* p_owner);
@ -208,7 +215,7 @@ public:
struct GroupInfo {
String name;
StringName name;
bool persistent;
};
@ -229,7 +236,11 @@ public:
void set_filename(const String& p_filename);
String get_filename() const;
void set_editable_instance(Node* p_node,bool p_editable);
bool is_editable_instance(Node* p_node) const;
/* NOTIFICATIONS */
void propagate_notification(int p_notification);
@ -261,10 +272,14 @@ public:
//Node *clone_tree() const;
// used by editors, to save what has changed only
void generate_instance_state();
Dictionary get_instance_state() const;
Vector<StringName> get_instance_groups() const;
Vector<Connection> get_instance_connections() const;
void set_scene_instance_state(const Ref<SceneState>& p_state);
Ref<SceneState> get_scene_instance_state() const;
void set_scene_inherited_state(const Ref<SceneState>& p_state);
Ref<SceneState> get_scene_inherited_state() const;
void set_scene_instance_load_placeholder(bool p_enable);
bool get_scene_instance_load_placeholder() const;
static Vector<Variant> make_binds(VARIANT_ARG_LIST);
@ -307,6 +322,4 @@ public:
typedef Set<Node*,Node::Comparator> NodeSet;
#endif

View file

@ -36,6 +36,7 @@
#include "resources/default_theme/default_theme.h"
#include "object_type_db.h"
#include "scene/main/canvas_layer.h"
#include "scene/main/instance_placeholder.h"
#include "scene/main/viewport.h"
#include "scene/gui/control.h"
#include "scene/gui/texture_progress.h"
@ -216,7 +217,7 @@
#include "scene/3d/collision_polygon.h"
#endif
#include "scene/resources/scene_format_text.h"
static ResourceFormatLoaderImage *resource_loader_image=NULL;
static ResourceFormatLoaderWAV *resource_loader_wav=NULL;
@ -229,6 +230,8 @@ static ResourceFormatLoaderBitMap *resource_loader_bitmap=NULL;
static ResourceFormatLoaderTheme *resource_loader_theme=NULL;
static ResourceFormatLoaderShader *resource_loader_shader=NULL;
static ResourceFormatSaverText *resource_saver_text=NULL;
//static SceneStringNames *string_names;
void register_scene_types() {
@ -267,6 +270,7 @@ void register_scene_types() {
ObjectTypeDB::register_type<Object>();
ObjectTypeDB::register_type<Node>();
ObjectTypeDB::register_virtual_type<InstancePlaceholder>();
ObjectTypeDB::register_type<Viewport>();
ObjectTypeDB::register_virtual_type<RenderTargetTexture>();
@ -612,6 +616,9 @@ void register_scene_types() {
OS::get_singleton()->yield(); //may take time to init
resource_saver_text = memnew( ResourceFormatSaverText );
ResourceSaver::add_resource_format_saver(resource_saver_text);
}
void unregister_scene_types() {
@ -629,5 +636,9 @@ void unregister_scene_types() {
memdelete( resource_loader_theme );
memdelete( resource_loader_shader );
if (resource_saver_text) {
memdelete(resource_saver_text);
}
SceneStringNames::free();
}

File diff suppressed because it is too large Load diff

View file

@ -32,26 +32,27 @@
#include "resource.h"
#include "scene/main/node.h"
//changes:
//1-make the InstanceState a reference inside the resource that can be shared
//2-make the instance "editable" with a flag, save here and load here, no need for property
//3-properly save modifications in sub-scene
//4-add scene inheritance
//5-chain of instance states in editor? (to check what was modified)
//6-saving will be hell
class SceneState : public Reference {
class PackedScene : public Resource {
OBJ_TYPE( PackedScene, Resource );
RES_BASE_EXTENSION("scn");
OBJ_TYPE( SceneState, Reference );
Vector<StringName> names;
Vector<Variant> variants;
Vector<NodePath> node_paths;
Vector<NodePath> editable_instances;
mutable HashMap<NodePath,int> node_path_cache;
mutable Map<int,int> base_scene_node_remap;
//missing - instances
//missing groups
//missing - owner
//missing - override names and values
int base_scene_idx;
enum {
FLAG_ID_IS_PATH=(1<<30),
FLAG_INSTANCE_IS_PLACEHOLDER=(1<<30),
FLAG_MASK=(1<<24)-1,
NO_PARENT_SAVED=0x7FFFFFFF,
TYPE_INSTANCED=0x7FFFFFFF,
};
struct NodeData {
@ -68,9 +69,15 @@ class PackedScene : public Resource {
};
Vector<Property> properties;
Vector<int> groups;
Vector<int> groups;
};
struct PackState {
Ref<SceneState> state;
int node;
PackState() { node=-1; }
};
Vector<NodeData> nodes;
@ -86,16 +93,78 @@ class PackedScene : public Resource {
Vector<ConnectionData> connections;
Error _parse_node(Node *p_owner,Node *p_node,int p_parent_idx, Map<StringName,int> &name_map,HashMap<Variant,int,VariantHasher> &variant_map,Map<Node*,int> &node_map);
Error _parse_connections(Node *p_owner,Node *p_node, Map<StringName,int> &name_map,HashMap<Variant,int,VariantHasher> &variant_map,Map<Node*,int> &node_map);
Error _parse_node(Node *p_owner,Node *p_node,int p_parent_idx, Map<StringName,int> &name_map,HashMap<Variant,int,VariantHasher> &variant_map,Map<Node*,int> &node_map,Map<Node*,int> &nodepath_map);
Error _parse_connections(Node *p_owner,Node *p_node, Map<StringName,int> &name_map,HashMap<Variant,int,VariantHasher> &variant_map,Map<Node*,int> &node_map,Map<Node*,int> &nodepath_map);
String path;
_FORCE_INLINE_ Ref<SceneState> _get_base_scene_state() const;
static bool disable_placeholders;
public:
static void set_disable_placeholders(bool p_disable);
int find_node_by_path(const NodePath& p_node) const;
Variant get_property_value(int p_node,const StringName& p_property,bool &found) const;
bool is_node_in_group(int p_node,const StringName& p_group) const;
bool is_connection(int p_node,const StringName& p_signal,int p_to_node,const StringName& p_to_method) const;
void set_bundled_scene(const Dictionary& p_dictionary);
Dictionary get_bundled_scene() const;
Error pack(Node *p_scene);
void set_path(const String &p_path);
String get_path() const;
void clear();
bool can_instance() const;
Node *instance(bool p_gen_edit_state=false) const;
//build-unbuild API
int get_node_count() const;
StringName get_node_type(int p_idx) const;
StringName get_node_name(int p_idx) const;
NodePath get_node_path(int p_idx,bool p_for_parent=false) const;
NodePath get_node_owner_path(int p_idx) const;
Ref<PackedScene> get_node_instance(int p_idx) const;
Vector<StringName> get_node_groups(int p_idx) const;
int get_node_property_count(int p_idx) const;
StringName get_node_property_name(int p_idx,int p_prop) const;
Variant get_node_property_value(int p_idx,int p_prop) const;
int get_connection_count() const;
NodePath get_connection_source(int p_idx) const;
StringName get_connection_signal(int p_idx) const;
NodePath get_connection_target(int p_idx) const;
StringName get_connection_method(int p_idx) const;
int get_connection_flags(int p_idx) const;
Array get_connection_binds(int p_idx) const;
Vector<NodePath> get_editable_instances() const;
SceneState();
};
class PackedScene : public Resource {
OBJ_TYPE(PackedScene, Resource );
RES_BASE_EXTENSION("scn");
Ref<SceneState> state;
void _set_bundled_scene(const Dictionary& p_scene);
Dictionary _get_bundled_scene() const;
protected:
static void _bind_methods();
public:
@ -107,7 +176,12 @@ public:
bool can_instance() const;
Node *instance(bool p_gen_edit_state=false) const;
virtual void set_path(const String& p_path,bool p_take_over=false);
Ref<SceneState> get_state();
PackedScene();
};
#endif // SCENE_PRELOADER_H

View file

@ -0,0 +1,792 @@
#include "scene_format_text.h"
#include "globals.h"
#include "version.h"
#include "os/dir_access.h"
#define FORMAT_VERSION 1
void ResourceFormatSaverTextInstance::write_property(const String& p_name,const Variant& p_property,bool *r_ok) {
if (r_ok)
*r_ok=false;
if (p_name!=String()) {
f->store_string(p_name+" = ");
}
switch( p_property.get_type() ) {
case Variant::NIL: {
f->store_string("null");
} break;
case Variant::BOOL: {
f->store_string(p_property.operator bool() ? "true":"false" );
} break;
case Variant::INT: {
f->store_string( itos(p_property.operator int()) );
} break;
case Variant::REAL: {
f->store_string( rtoss(p_property.operator real_t()) );
} break;
case Variant::STRING: {
String str=p_property;
str="\""+str.c_escape()+"\"";
f->store_string( str );
} break;
case Variant::VECTOR2: {
Vector2 v = p_property;
f->store_string("Vector2( "+rtoss(v.x) +", "+rtoss(v.y)+" )" );
} break;
case Variant::RECT2: {
Rect2 aabb = p_property;
f->store_string("Rect2( "+rtoss(aabb.pos.x) +", "+rtoss(aabb.pos.y) +", "+rtoss(aabb.size.x) +", "+rtoss(aabb.size.y)+" )" );
} break;
case Variant::VECTOR3: {
Vector3 v = p_property;
f->store_string("Vector3( "+rtoss(v.x) +", "+rtoss(v.y)+", "+rtoss(v.z)+" )");
} break;
case Variant::PLANE: {
Plane p = p_property;
f->store_string("Plane( "+rtoss(p.normal.x) +", "+rtoss(p.normal.y)+", "+rtoss(p.normal.z)+", "+rtoss(p.d)+" )" );
} break;
case Variant::_AABB: {
AABB aabb = p_property;
f->store_string("AABB( "+rtoss(aabb.pos.x) +", "+rtoss(aabb.pos.y) +", "+rtoss(aabb.pos.z) +", "+rtoss(aabb.size.x) +", "+rtoss(aabb.size.y) +", "+rtoss(aabb.size.z)+" )" );
} break;
case Variant::QUAT: {
Quat quat = p_property;
f->store_string("Quat( "+rtoss(quat.x)+", "+rtoss(quat.y)+", "+rtoss(quat.z)+", "+rtoss(quat.w)+" )");
} break;
case Variant::MATRIX32: {
String s="Matrix32( ";
Matrix32 m3 = p_property;
for (int i=0;i<3;i++) {
for (int j=0;j<2;j++) {
if (i!=0 || j!=0)
s+=", ";
s+=rtoss( m3.elements[i][j] );
}
}
f->store_string(s+" )");
} break;
case Variant::MATRIX3: {
String s="Matrix3( ";
Matrix3 m3 = p_property;
for (int i=0;i<3;i++) {
for (int j=0;j<3;j++) {
if (i!=0 || j!=0)
s+=", ";
s+=rtoss( m3.elements[i][j] );
}
}
f->store_string(s+" )");
} break;
case Variant::TRANSFORM: {
String s="Transform( ";
Transform t = p_property;
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+=rtoss( m3.elements[i][j] );
}
}
s=s+", "+rtoss(t.origin.x) +", "+rtoss(t.origin.y)+", "+rtoss(t.origin.z);
f->store_string(s+" )");
} break;
// misc types
case Variant::COLOR: {
Color c = p_property;
f->store_string("Color( "+rtoss(c.r) +", "+rtoss(c.g)+", "+rtoss(c.b)+", "+rtoss(c.a)+" )");
} break;
case Variant::IMAGE: {
Image img=p_property;
if (img.empty()) {
f->store_string("RawImage()");
break;
}
String imgstr="RawImage( ";
imgstr+=itos(img.get_width());
imgstr+=", "+itos(img.get_height());
imgstr+=", "+itos(img.get_mipmaps());
imgstr+=", ";
switch(img.get_format()) {
case Image::FORMAT_GRAYSCALE: imgstr+="GRAYSCALE"; break;
case Image::FORMAT_INTENSITY: imgstr+="INTENSITY"; break;
case Image::FORMAT_GRAYSCALE_ALPHA: imgstr+="GRAYSCALE_ALPHA"; break;
case Image::FORMAT_RGB: imgstr+="RGB"; break;
case Image::FORMAT_RGBA: imgstr+="RGBA"; break;
case Image::FORMAT_INDEXED : imgstr+="INDEXED"; break;
case Image::FORMAT_INDEXED_ALPHA: imgstr+="INDEXED_ALPHA"; break;
case Image::FORMAT_BC1: imgstr+="BC1"; break;
case Image::FORMAT_BC2: imgstr+="BC2"; break;
case Image::FORMAT_BC3: imgstr+="BC3"; break;
case Image::FORMAT_BC4: imgstr+="BC4"; break;
case Image::FORMAT_BC5: imgstr+="BC5"; break;
case Image::FORMAT_PVRTC2: imgstr+="PVRTC2"; break;
case Image::FORMAT_PVRTC2_ALPHA: imgstr+="PVRTC2_ALPHA"; break;
case Image::FORMAT_PVRTC4: imgstr+="PVRTC4"; break;
case Image::FORMAT_PVRTC4_ALPHA: imgstr+="PVRTC4_ALPHA"; break;
case Image::FORMAT_ETC: imgstr+="ETC"; break;
case Image::FORMAT_ATC: imgstr+="ATC"; break;
case Image::FORMAT_ATC_ALPHA_EXPLICIT: imgstr+="ATC_ALPHA_EXPLICIT"; break;
case Image::FORMAT_ATC_ALPHA_INTERPOLATED: imgstr+="ATC_ALPHA_INTERPOLATED"; break;
case Image::FORMAT_CUSTOM: imgstr+="CUSTOM"; break;
default: {}
}
String s;
DVector<uint8_t> data = img.get_data();
int len = data.size();
DVector<uint8_t>::Read r = data.read();
const uint8_t *ptr=r.ptr();;
for (int i=0;i<len;i++) {
uint8_t byte = ptr[i];
const char hex[16]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
char str[3]={ hex[byte>>4], hex[byte&0xF], 0};
s+=str;
}
imgstr+=", ";
f->store_string(imgstr);
f->store_string(s);
f->store_string(" )");
} break;
case Variant::NODE_PATH: {
String str=p_property;
str="NodePath(\""+str.c_escape()+"\")";
f->store_string(str);
} break;
case Variant::OBJECT: {
RES res = p_property;
if (res.is_null()) {
f->store_string("null");
if (r_ok)
*r_ok=true;
break; // don't save it
}
if (external_resources.has(res)) {
f->store_string("ExtResource( "+itos(external_resources[res]+1)+" )");
} else {
if (internal_resources.has(res)) {
f->store_string("SubResource( "+itos(internal_resources[res])+" )");
} else if (res->get_path().length() && res->get_path().find("::")==-1) {
//external resource
String path=relative_paths?local_path.path_to_file(res->get_path()):res->get_path();
f->store_string("Resource( \""+path+"\" )");
} else {
f->store_string("null");
ERR_EXPLAIN("Resource was not pre cached for the resource section, bug?");
ERR_BREAK(true);
//internal resource
}
}
} break;
case Variant::INPUT_EVENT: {
f->store_string("InputEvent()"); //will be added later
} break;
case Variant::DICTIONARY: {
Dictionary dict = p_property;
List<Variant> keys;
dict.get_key_list(&keys);
keys.sort();
f->store_string("{ ");
for(List<Variant>::Element *E=keys.front();E;E=E->next()) {
//if (!_check_type(dict[E->get()]))
// continue;
bool ok;
write_property("",E->get(),&ok);
ERR_CONTINUE(!ok);
f->store_string(":");
write_property("",dict[E->get()],&ok);
if (!ok)
write_property("",Variant()); //at least make the file consistent..
if (E->next())
f->store_string(", ");
}
f->store_string(" }");
} break;
case Variant::ARRAY: {
f->store_string("[ ");
Array array = p_property;
int len=array.size();
for (int i=0;i<len;i++) {
if (i>0)
f->store_string(", ");
write_property("",array[i]);
}
f->store_string(" ]");
} break;
case Variant::RAW_ARRAY: {
f->store_string("RawArray( ");
String s;
DVector<uint8_t> data = p_property;
int len = data.size();
DVector<uint8_t>::Read r = data.read();
const uint8_t *ptr=r.ptr();;
for (int i=0;i<len;i++) {
if (i>0)
f->store_string(", ");
uint8_t byte = ptr[i];
const char hex[16]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
char str[3]={ hex[byte>>4], hex[byte&0xF], 0};
f->store_string(str);
}
f->store_string(" )");
} break;
case Variant::INT_ARRAY: {
f->store_string("IntArray( ");
DVector<int> data = p_property;
int len = data.size();
DVector<int>::Read r = data.read();
const int *ptr=r.ptr();;
for (int i=0;i<len;i++) {
if (i>0)
f->store_string(", ");
f->store_string(itos(ptr[i]));
}
f->store_string(" )");
} break;
case Variant::REAL_ARRAY: {
f->store_string("FloatArray( ");
DVector<real_t> data = p_property;
int len = data.size();
DVector<real_t>::Read r = data.read();
const real_t *ptr=r.ptr();;
for (int i=0;i<len;i++) {
if (i>0)
f->store_string(", ");
f->store_string(rtoss(ptr[i]));
}
f->store_string(" )");
} break;
case Variant::STRING_ARRAY: {
f->store_string("StringArray( ");
DVector<String> data = p_property;
int len = data.size();
DVector<String>::Read r = data.read();
const String *ptr=r.ptr();;
String s;
//write_string("\n");
for (int i=0;i<len;i++) {
if (i>0)
f->store_string(", ");
String str=ptr[i];
f->store_string(""+str.c_escape()+"\"");
}
f->store_string(" )");
} break;
case Variant::VECTOR2_ARRAY: {
f->store_string("Vector2Array( ");
DVector<Vector2> data = p_property;
int len = data.size();
DVector<Vector2>::Read r = data.read();
const Vector2 *ptr=r.ptr();;
for (int i=0;i<len;i++) {
if (i>0)
f->store_string(", ");
f->store_string(rtoss(ptr[i].x)+", "+rtoss(ptr[i].y) );
}
f->store_string(" )");
} break;
case Variant::VECTOR3_ARRAY: {
f->store_string("Vector3Array( ");
DVector<Vector3> data = p_property;
int len = data.size();
DVector<Vector3>::Read r = data.read();
const Vector3 *ptr=r.ptr();;
for (int i=0;i<len;i++) {
if (i>0)
f->store_string(", ");
f->store_string(rtoss(ptr[i].x)+", "+rtoss(ptr[i].y)+", "+rtoss(ptr[i].z) );
}
f->store_string(" )");
} break;
case Variant::COLOR_ARRAY: {
f->store_string("ColorArray( ");
DVector<Color> data = p_property;
int len = data.size();
DVector<Color>::Read r = data.read();
const Color *ptr=r.ptr();;
for (int i=0;i<len;i++) {
if (i>0)
f->store_string(", ");
f->store_string(rtoss(ptr[i].r)+", "+rtoss(ptr[i].g)+", "+rtoss(ptr[i].b)+", "+rtoss(ptr[i].a) );
}
f->store_string(" )");
} break;
default: {}
}
if (r_ok)
*r_ok=true;
}
void ResourceFormatSaverTextInstance::_find_resources(const Variant& p_variant,bool p_main) {
switch(p_variant.get_type()) {
case Variant::OBJECT: {
RES res = p_variant.operator RefPtr();
if (res.is_null() || external_resources.has(res))
return;
if (!p_main && (!bundle_resources ) && res->get_path().length() && res->get_path().find("::") == -1 ) {
int index = external_resources.size();
external_resources[res]=index;
return;
}
if (resource_set.has(res))
return;
List<PropertyInfo> property_list;
res->get_property_list( &property_list );
property_list.sort();
List<PropertyInfo>::Element *I=property_list.front();
while(I) {
PropertyInfo pi=I->get();
if (pi.usage&PROPERTY_USAGE_STORAGE || (bundle_resources && pi.usage&PROPERTY_USAGE_BUNDLE)) {
Variant v=res->get(I->get().name);
_find_resources(v);
}
I=I->next();
}
resource_set.insert( res ); //saved after, so the childs it needs are available when loaded
saved_resources.push_back(res);
} break;
case Variant::ARRAY: {
Array varray=p_variant;
int len=varray.size();
for(int i=0;i<len;i++) {
Variant v=varray.get(i);
_find_resources(v);
}
} break;
case Variant::DICTIONARY: {
Dictionary d=p_variant;
List<Variant> keys;
d.get_key_list(&keys);
for(List<Variant>::Element *E=keys.front();E;E=E->next()) {
Variant v = d[E->get()];
_find_resources(v);
}
} break;
default: {}
}
}
Error ResourceFormatSaverTextInstance::save(const String &p_path,const RES& p_resource,uint32_t p_flags) {
if (p_path.ends_with(".tscn")) {
packed_scene=p_resource;
}
Error err;
f = FileAccess::open(p_path, FileAccess::WRITE,&err);
ERR_FAIL_COND_V( err, ERR_CANT_OPEN );
FileAccessRef _fref(f);
local_path = Globals::get_singleton()->localize_path(p_path);
relative_paths=p_flags&ResourceSaver::FLAG_RELATIVE_PATHS;
skip_editor=p_flags&ResourceSaver::FLAG_OMIT_EDITOR_PROPERTIES;
bundle_resources=p_flags&ResourceSaver::FLAG_BUNDLE_RESOURCES;
takeover_paths=p_flags&ResourceSaver::FLAG_REPLACE_SUBRESOURCE_PATHS;
if (!p_path.begins_with("res://")) {
takeover_paths=false;
}
// save resources
_find_resources(p_resource,true);
if (packed_scene.is_valid()) {
//add instances to external resources if saving a packed scene
for(int i=0;i<packed_scene->get_state()->get_node_count();i++) {
Ref<PackedScene> instance=packed_scene->get_state()->get_node_instance(i);
if (instance.is_valid() && !external_resources.has(instance)) {
int index = external_resources.size();
external_resources[instance]=index;
}
}
}
ERR_FAIL_COND_V(err!=OK,err);
{
String title=packed_scene.is_valid()?"[gd_scene ":"[gd_resource ";
if (packed_scene.is_null())
title+="type=\""+p_resource->get_type()+"\" ";
int load_steps=saved_resources.size()+external_resources.size();
//if (packed_scene.is_valid()) {
// load_steps+=packed_scene->get_node_count();
//}
//no, better to not use load steps from nodes, no point to that
if (load_steps>1) {
title+="load_steps="+itos(load_steps)+" ";
}
title+="format="+itos(FORMAT_VERSION)+"";
//title+="engine_version=\""+itos(VERSION_MAJOR)+"."+itos(VERSION_MINOR)+"\"";
f->store_string(title);
f->store_line("]\n"); //one empty line
}
for(Map<RES,int>::Element *E=external_resources.front();E;E=E->next()) {
String p = E->key()->get_path();
f->store_string("[ext_resource path=\""+p+"\" type=\""+E->key()->get_save_type()+"\" id="+itos(E->get()+1)+"]\n"); //bundled
}
if (external_resources.size())
f->store_line(String()); //separate
Set<int> used_indices;
for(List<RES>::Element *E=saved_resources.front();E;E=E->next()) {
RES res = E->get();
if (E->next() && (res->get_path()=="" || res->get_path().find("::") != -1 )) {
if (res->get_subindex()!=0) {
if (used_indices.has(res->get_subindex())) {
res->set_subindex(0); //repeated
} else {
used_indices.insert(res->get_subindex());
}
}
}
}
for(List<RES>::Element *E=saved_resources.front();E;E=E->next()) {
RES res = E->get();
ERR_CONTINUE(!resource_set.has(res));
bool main = (E->next()==NULL);
if (main && packed_scene.is_valid())
break; //save as a scene
if (main) {
f->store_line("[resource]\n");
} else {
String line="[sub_resource ";
if (res->get_subindex()==0) {
int new_subindex=1;
if (used_indices.size()) {
new_subindex=used_indices.back()->get()+1;
}
res->set_subindex(new_subindex);
used_indices.insert(new_subindex);
}
int idx = res->get_subindex();
line+="type=\""+res->get_type()+"\" id="+itos(idx);
f->store_line(line+"]\n");
if (takeover_paths) {
res->set_path(p_path+"::"+itos(idx),true);
}
internal_resources[res]=idx;
}
List<PropertyInfo> property_list;
res->get_property_list(&property_list);
// property_list.sort();
for(List<PropertyInfo>::Element *PE = property_list.front();PE;PE=PE->next()) {
if (skip_editor && PE->get().name.begins_with("__editor"))
continue;
if (PE->get().usage&PROPERTY_USAGE_STORAGE || (bundle_resources && PE->get().usage&PROPERTY_USAGE_BUNDLE)) {
String name = PE->get().name;
Variant value = res->get(name);
if ((PE->get().usage&PROPERTY_USAGE_STORE_IF_NONZERO && value.is_zero())||(PE->get().usage&PROPERTY_USAGE_STORE_IF_NONONE && value.is_one()) )
continue;
if (PE->get().type==Variant::OBJECT && value.is_zero())
continue;
write_property(name,value);
f->store_string("\n");
}
}
f->store_string("\n");
}
if (packed_scene.is_valid()) {
//if this is a scene, save nodes and connections!
Ref<SceneState> state = packed_scene->get_state();
for(int i=0;i<state->get_node_count();i++) {
StringName type = state->get_node_type(i);
StringName name = state->get_node_name(i);
NodePath path = state->get_node_path(i,true);
NodePath owner = state->get_node_owner_path(i);
Ref<PackedScene> instance = state->get_node_instance(i);
Vector<StringName> groups = state->get_node_groups(i);
String header="[node";
header+=" name=\""+String(name)+"\"";
if (type!=StringName()) {
header+=" type=\""+String(type)+"\"";
}
if (path!=NodePath()) {
header+=" parent=\""+String(path.simplified())+"\"";
}
if (owner!=NodePath() && owner!=NodePath(".")) {
header+=" owner=\""+String(owner.simplified())+"\"";
}
if (groups.size()) {
String sgroups=" groups=[ ";
for(int j=0;j<groups.size();j++) {
if (j>0)
sgroups+=", ";
sgroups+="\""+groups[i].operator String().c_escape()+"\"";
}
sgroups+=" ]";
header+=sgroups;
}
f->store_string(header);
if (instance.is_valid()) {
f->store_string(" instance=");
write_property("",instance);
}
f->store_line("]\n");
for(int j=0;j<state->get_node_property_count(i);j++) {
write_property(state->get_node_property_name(i,j),state->get_node_property_value(i,j));
f->store_line(String());
}
if (state->get_node_property_count(i)) {
//add space
f->store_line(String());
}
}
for(int i=0;i<state->get_connection_count();i++) {
String connstr="[connection";
connstr+=" signal=\""+String(state->get_connection_signal(i))+"\"";
connstr+=" from=\""+String(state->get_connection_source(i).simplified())+"\"";
connstr+=" to=\""+String(state->get_connection_target(i).simplified())+"\"";
connstr+=" method=\""+String(state->get_connection_method(i))+"\"";
int flags = state->get_connection_flags(i);
if (flags!=Object::CONNECT_PERSIST) {
connstr+=" flags="+itos(flags);
}
Array binds=state->get_connection_binds(i);
f->store_string(connstr);
if (binds.size()) {
f->store_string(" binds=");
write_property("",binds);
}
f->store_line("]\n");
}
f->store_line(String());
Vector<NodePath> editable_instances = state->get_editable_instances();
for(int i=0;i<editable_instances.size();i++) {
f->store_line("[editable path=\""+editable_instances[i].operator String()+"\"]");
}
}
if (f->get_error()!=OK && f->get_error()!=ERR_FILE_EOF) {
f->close();
return ERR_CANT_CREATE;
}
f->close();
//memdelete(f);
return OK;
}
Error ResourceFormatSaverText::save(const String &p_path,const RES& p_resource,uint32_t p_flags) {
if (p_path.ends_with(".sct") && p_resource->get_type()!="PackedScene") {
return ERR_FILE_UNRECOGNIZED;
}
ResourceFormatSaverTextInstance saver;
return saver.save(p_path,p_resource,p_flags);
}
bool ResourceFormatSaverText::recognize(const RES& p_resource) const {
return true; // all recognized!
}
void ResourceFormatSaverText::get_recognized_extensions(const RES& p_resource,List<String> *p_extensions) const {
p_extensions->push_back("tres"); //text resource
if (p_resource->get_type()=="PackedScene")
p_extensions->push_back("tscn"); //text scene
}
ResourceFormatSaverText* ResourceFormatSaverText::singleton=NULL;
ResourceFormatSaverText::ResourceFormatSaverText() {
singleton=this;
}

View file

@ -0,0 +1,46 @@
#ifndef SCENE_FORMAT_TEXT_H
#define SCENE_FORMAT_TEXT_H
#include "io/resource_loader.h"
#include "io/resource_saver.h"
#include "os/file_access.h"
#include "scene/resources/packed_scene.h"
class ResourceFormatSaverTextInstance {
String local_path;
Ref<PackedScene> packed_scene;
bool takeover_paths;
bool relative_paths;
bool bundle_resources;
bool skip_editor;
FileAccess *f;
Set<RES> resource_set;
List<RES> saved_resources;
Map<RES,int> external_resources;
Map<RES,int> internal_resources;
void _find_resources(const Variant& p_variant,bool p_main=false);
void write_property(const String& p_name,const Variant& p_property,bool *r_ok=NULL);
public:
Error save(const String &p_path,const RES& p_resource,uint32_t p_flags=0);
};
class ResourceFormatSaverText : public ResourceFormatSaver {
public:
static ResourceFormatSaverText* singleton;
virtual Error save(const String &p_path,const RES& p_resource,uint32_t p_flags=0);
virtual bool recognize(const RES& p_resource) const;
virtual void get_recognized_extensions(const RES& p_resource,List<String> *p_extensions) const;
ResourceFormatSaverText();
};
#endif // SCENE_FORMAT_TEXT_H

View file

@ -194,7 +194,6 @@ bool BodyPairSW::_test_ccd(float p_step,BodySW *p_A, int p_shape_A,const Transfo
//cast a segment from support in motion normal, in the same direction of motion by motion length
//support is the worst case collision point, so real collision happened before
int a;
Vector3 s=p_A->get_shape(p_shape_A)->get_support(p_xform_A.basis.xform(mnormal).normalized());
Vector3 from = p_xform_A.xform(s);
Vector3 to = from + motion;

View file

@ -34,10 +34,10 @@
_FORCE_INLINE_ static bool _match_object_type_query(CollisionObjectSW *p_object, uint32_t p_layer_mask, uint32_t p_type_mask) {
if ((p_object->get_layer_mask()&p_layer_mask)==0)
return false;
if (p_object->get_type()==CollisionObjectSW::TYPE_AREA)
return p_type_mask&PhysicsDirectSpaceState::TYPE_MASK_AREA;
if (p_object->get_type()==CollisionObjectSW::TYPE_AREA && !(p_type_mask&PhysicsDirectSpaceState::TYPE_MASK_AREA))
if ((p_object->get_layer_mask()&p_layer_mask)==0)
return false;
BodySW *body = static_cast<BodySW*>(p_object);

View file

@ -279,6 +279,18 @@ void PinJoint2DSW::solve(float p_step){
P += impulse;
}
void PinJoint2DSW::set_param(Physics2DServer::PinJointParam p_param, real_t p_value) {
if(p_param == Physics2DServer::PIN_JOINT_SOFTNESS)
softness = p_value;
}
real_t PinJoint2DSW::get_param(Physics2DServer::PinJointParam p_param) const {
if(p_param == Physics2DServer::PIN_JOINT_SOFTNESS)
return softness;
ERR_FAIL_V(0);
}
PinJoint2DSW::PinJoint2DSW(const Vector2& p_pos,Body2DSW* p_body_a,Body2DSW* p_body_b) : Joint2DSW(_arr,p_body_b?2:1) {

View file

@ -121,6 +121,8 @@ public:
virtual bool setup(float p_step);
virtual void solve(float p_step);
void set_param(Physics2DServer::PinJointParam p_param, real_t p_value);
real_t get_param(Physics2DServer::PinJointParam p_param) const;
PinJoint2DSW(const Vector2& p_pos,Body2DSW* p_body_a,Body2DSW* p_body_b=NULL);
~PinJoint2DSW();

View file

@ -1096,6 +1096,25 @@ RID Physics2DServerSW::damped_spring_joint_create(const Vector2& p_anchor_a,cons
}
void Physics2DServerSW::pin_joint_set_param(RID p_joint, PinJointParam p_param, real_t p_value) {
Joint2DSW *j = joint_owner.get(p_joint);
ERR_FAIL_COND(!j);
ERR_FAIL_COND(j->get_type()!=JOINT_PIN);
PinJoint2DSW *pin_joint = static_cast<PinJoint2DSW*>(j);
pin_joint->set_param(p_param, p_value);
}
real_t Physics2DServerSW::pin_joint_get_param(RID p_joint, PinJointParam p_param) const {
Joint2DSW *j = joint_owner.get(p_joint);
ERR_FAIL_COND_V(!j,0);
ERR_FAIL_COND_V(j->get_type()!=JOINT_PIN,0);
PinJoint2DSW *pin_joint = static_cast<PinJoint2DSW*>(j);
return pin_joint->get_param(p_param);
}
void Physics2DServerSW::damped_string_joint_set_param(RID p_joint, DampedStringParam p_param, real_t p_value) {

View file

@ -243,6 +243,8 @@ public:
virtual RID pin_joint_create(const Vector2& p_pos,RID p_body_a,RID p_body_b=RID());
virtual RID groove_joint_create(const Vector2& p_a_groove1,const Vector2& p_a_groove2, const Vector2& p_b_anchor, RID p_body_a,RID p_body_b);
virtual RID damped_spring_joint_create(const Vector2& p_anchor_a,const Vector2& p_anchor_b,RID p_body_a,RID p_body_b=RID());
virtual void pin_joint_set_param(RID p_joint, PinJointParam p_param, real_t p_value);
virtual real_t pin_joint_get_param(RID p_joint, PinJointParam p_param) const;
virtual void damped_string_joint_set_param(RID p_joint, DampedStringParam p_param, real_t p_value);
virtual real_t damped_string_joint_get_param(RID p_joint, DampedStringParam p_param) const;

View file

@ -258,6 +258,9 @@ public:
FUNC5R(RID,groove_joint_create,const Vector2&,const Vector2&,const Vector2&,RID,RID);
FUNC4R(RID,damped_spring_joint_create,const Vector2&,const Vector2&,RID,RID);
FUNC3(pin_joint_set_param,RID,PinJointParam,real_t);
FUNC2RC(real_t,pin_joint_get_param,RID,PinJointParam);
FUNC3(damped_string_joint_set_param,RID,DampedStringParam,real_t);
FUNC2RC(real_t,damped_string_joint_get_param,RID,DampedStringParam);

View file

@ -36,8 +36,8 @@ _FORCE_INLINE_ static bool _match_object_type_query(CollisionObject2DSW *p_objec
if ((p_object->get_layer_mask()&p_layer_mask)==0)
return false;
if (p_object->get_type()==CollisionObject2DSW::TYPE_AREA && !(p_type_mask&Physics2DDirectSpaceState::TYPE_MASK_AREA))
return false;
if (p_object->get_type()==CollisionObject2DSW::TYPE_AREA)
return p_type_mask&Physics2DDirectSpaceState::TYPE_MASK_AREA;
Body2DSW *body = static_cast<Body2DSW*>(p_object);

View file

@ -516,6 +516,13 @@ public:
virtual RID groove_joint_create(const Vector2& p_a_groove1,const Vector2& p_a_groove2, const Vector2& p_b_anchor, RID p_body_a,RID p_body_b)=0;
virtual RID damped_spring_joint_create(const Vector2& p_anchor_a,const Vector2& p_anchor_b,RID p_body_a,RID p_body_b=RID())=0;
enum PinJointParam {
PIN_JOINT_SOFTNESS
};
virtual void pin_joint_set_param(RID p_joint, PinJointParam p_param, real_t p_value)=0;
virtual real_t pin_joint_get_param(RID p_joint, PinJointParam p_param) const=0;
enum DampedStringParam {
DAMPED_STRING_REST_LENGTH,
DAMPED_STRING_STIFFNESS,

View file

@ -5219,7 +5219,6 @@ void VisualServerRaster::_light_instance_update_lispsm_shadow(Instance *p_light,
AABB proj_space_aabb;
float max_d,min_d;
{
@ -6824,7 +6823,11 @@ void VisualServerRaster::_render_canvas_item(CanvasItem *p_canvas_item,const Mat
copymem(child_items,ci->child_items.ptr(),child_item_count*sizeof(CanvasItem*));
if (ci->clip) {
ci->final_clip_rect=global_rect;
if (p_canvas_clip != NULL) {
ci->final_clip_rect=p_canvas_clip->final_clip_rect.clip(global_rect);
} else {
ci->final_clip_rect=global_rect;
}
ci->final_clip_owner=ci;
} else {

Binary file not shown.

View file

@ -0,0 +1,142 @@
# Translations template for PROJECT.
# Copyright (C) 2015 ORGANIZATION
# This file is distributed under the same license as the PROJECT project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2015.
#
msgid ""
msgstr ""
"Project-Id-Version: makedocs\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2015-10-07 11:47-0600\n"
"PO-Revision-Date: 2015-10-07 13:10-0600\n"
"Last-Translator: Jorge Araya Navarro <elcorreo@deshackra.com>\n"
"Language-Team: \n"
"Language: es\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.0\n"
"X-Generator: Poedit 1.8.4\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: makedocs.py:74
msgid ""
"\"<code>{gclass}</code>(Go to page of class {gclass})\":/class_{lkclass}"
msgstr ""
"\"<code>{gclass}</code>(Ir a la pagina de la clase {gclass})\":/"
"class_{lkclass}"
#: makedocs.py:76
msgid ""
"\"<code>{gclass}.{method}</code>(Go to page {gclass}, section {method})\":/"
"class_{lkclass}#{lkmethod}"
msgstr ""
"\"<code>{gclass}.{method}</code>(Ir a la pagina {gclass}, sección "
"{method})\":/class_{lkclass}#{lkmethod}"
#: makedocs.py:79
msgid "\"<code>{method}</code>(Jump to method {method})\":#{lkmethod}"
msgstr "\"<code>{method}</code>(Saltar al método {method})\":#{lkmethod}"
#: makedocs.py:81
msgid " \"{rtype}(Go to page of class {rtype})\":/class_{link} "
msgstr " \"{rtype}(Ir a la pagina de la clase {rtype})\":/class_{link} "
#: makedocs.py:82
msgid ""
"\"*{funcname}*(Jump to description for node {funcname})\":#{link} <b>(</b> "
msgstr ""
"\"*{funcname}*(Saltar a la descripción para el nodo {funcname})\":#{link} "
"<b>(</b> "
#: makedocs.py:87
msgid "h4. Inherits: "
msgstr "h4. Hereda de: "
#: makedocs.py:232
msgid "<doc>'s version attribute missing"
msgstr "El atributo version de <doc> no existe"
#: makedocs.py:246
msgid "|_. Index symbol |_. Class name |_. Index symbol |_. Class name |\n"
msgstr ""
"|_. Índice de símbolo |_. Nombre de la clase |_. Índice de símbolo |_. "
"Nombre de la clase |\n"
#: makedocs.py:305
msgid ""
"h4. Category: {}\n"
"\n"
msgstr ""
"h4. Categoría: {}\n"
"\n"
#: makedocs.py:310
msgid ""
"h2. Brief Description\n"
"\n"
msgstr ""
"h2. Descripción breve\n"
"\n"
#: makedocs.py:312
msgid ""
"\"read more\":#more\n"
"\n"
msgstr ""
"\"Leer más\":#more\n"
"\n"
#: makedocs.py:317
msgid ""
"\n"
"h3. Member Functions\n"
"\n"
msgstr ""
"\n"
"h3. Funciones miembro\n"
"\n"
#: makedocs.py:323
msgid ""
"\n"
"h3. Signals\n"
"\n"
msgstr ""
"\n"
"h3. Señales\n"
"\n"
#: makedocs.py:331
msgid ""
"\n"
"h3. Numeric Constants\n"
"\n"
msgstr ""
"\n"
"h3. Constantes numéricas\n"
"\n"
#: makedocs.py:347
msgid ""
"\n"
"h3(#more). Description\n"
"\n"
msgstr ""
"\n"
"h3(#more). Descripción\n"
"\n"
#: makedocs.py:351
msgid "_Nothing here, yet..._\n"
msgstr "_Aún nada por aquí..._\n"
#: makedocs.py:355
msgid ""
"\n"
"h3. Member Function Description\n"
"\n"
msgstr ""
"\n"
"h3. Descripción de las funciones miembro\n"
"\n"

108
tools/docdump/makedocs.pot Normal file
View file

@ -0,0 +1,108 @@
# Translations template for PROJECT.
# Copyright (C) 2015 ORGANIZATION
# This file is distributed under the same license as the PROJECT project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2015.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: makedocs 0.1\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2015-10-07 11:47-0600\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.0\n"
"X-Generator: Poedit 1.8.4\n"
#: makedocs.py:74
msgid "\"<code>{gclass}</code>(Go to page of class {gclass})\":/class_{lkclass}"
msgstr ""
#: makedocs.py:76
msgid "\"<code>{gclass}.{method}</code>(Go to page {gclass}, section {method})\":/class_{lkclass}#{lkmethod}"
msgstr ""
#: makedocs.py:79
msgid "\"<code>{method}</code>(Jump to method {method})\":#{lkmethod}"
msgstr ""
#: makedocs.py:81
msgid " \"{rtype}(Go to page of class {rtype})\":/class_{link} "
msgstr ""
#: makedocs.py:82
msgid "\"*{funcname}*(Jump to description for node {funcname})\":#{link} <b>(</b> "
msgstr ""
#: makedocs.py:87
msgid "h4. Inherits: "
msgstr ""
#: makedocs.py:232
msgid "<doc>'s version attribute missing"
msgstr ""
#: makedocs.py:246
msgid "|_. Index symbol |_. Class name |_. Index symbol |_. Class name |\n"
msgstr ""
#: makedocs.py:305
msgid ""
"h4. Category: {}\n"
"\n"
msgstr ""
#: makedocs.py:310
msgid ""
"h2. Brief Description\n"
"\n"
msgstr ""
#: makedocs.py:312
msgid ""
"\"read more\":#more\n"
"\n"
msgstr ""
#: makedocs.py:317
msgid ""
"\n"
"h3. Member Functions\n"
"\n"
msgstr ""
#: makedocs.py:323
msgid ""
"\n"
"h3. Signals\n"
"\n"
msgstr ""
#: makedocs.py:331
msgid ""
"\n"
"h3. Numeric Constants\n"
"\n"
msgstr ""
#: makedocs.py:347
msgid ""
"\n"
"h3(#more). Description\n"
"\n"
msgstr ""
#: makedocs.py:351
msgid "_Nothing here, yet..._\n"
msgstr ""
#: makedocs.py:355
msgid ""
"\n"
"h3. Member Function Description\n"
"\n"
msgstr ""

382
tools/docdump/makedocs.py Normal file
View file

@ -0,0 +1,382 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# makedocs.py: Generate documentation for Open Project Wiki
# Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur.
# Contributor: Jorge Araya Navarro <elcorreo@deshackra.com>
#
# IMPORTANT NOTICE:
# If you are going to modify anything from this file, please be sure to follow
# the Style Guide for Python Code or often called "PEP8". To do this
# automagically just install autopep8:
#
# $ sudo pip3 install autopep8
#
# and run:
#
# $ autopep8 makedocs.py
#
# Before committing your changes. Also be sure to delete any trailing
# whitespace you may left.
#
# TODO:
# * Refactor code.
# * Adapt this script for generating content in other markup formats like
# DokuWiki, Markdown, etc.
#
# Also check other TODO entries in this script for more information on what is
# left to do.
import argparse
import gettext
import logging
import re
from itertools import zip_longest
from os import path, listdir
from xml.etree import ElementTree
# add an option to change the verbosity
logging.basicConfig(level=logging.INFO)
def getxmlfloc():
""" Returns the supposed location of the XML file
"""
filepath = path.dirname(path.abspath(__file__))
return path.join(filepath, "class_list.xml")
def langavailable():
""" Return a list of languages available for translation
"""
filepath = path.join(
path.dirname(path.abspath(__file__)), "locales")
files = listdir(filepath)
choices = [x for x in files]
choices.insert(0, "none")
return choices
desc = "Generates documentation from a XML file to different markup languages"
parser = argparse.ArgumentParser(description=desc)
parser.add_argument("--input", dest="xmlfp", default=getxmlfloc(),
help="Input XML file, default: {}".format(getxmlfloc()))
parser.add_argument("--output-dir", dest="outputdir", required=True,
help="Output directory for generated files")
parser.add_argument("--language", choices=langavailable(), default="none",
help=("Choose the language of translation"
" for the output files. Default is English (none). "
"Note: This is NOT for the documentation itself!"))
# TODO: add an option for outputting different markup formats
args = parser.parse_args()
# Let's check if the file and output directory exists
if not path.isfile(args.xmlfp):
logging.critical("File not found: {}".format(args.xmlfp))
exit(1)
elif not path.isdir(args.outputdir):
logging.critical("Path does not exist: {}".format(args.outputdir))
exit(1)
_ = gettext.gettext
if args.language != "none":
lang = gettext.translation(domain="makedocs",
localedir="locales",
languages=[args.language])
lang.install()
_ = lang.gettext
# Strings
C_LINK = _("\"<code>{gclass}</code>(Go to page of class"
" {gclass})\":/class_{lkclass}")
MC_LINK = _("\"<code>{gclass}.{method}</code>(Go "
"to page {gclass}, section {method})\""
":/class_{lkclass}#{lkmethod}")
TM_JUMP = _("\"<code>{method}</code>(Jump to method"
" {method})\":#{lkmethod}")
GTC_LINK = _(" \"{rtype}(Go to page of class {rtype})\":/class_{link} ")
DFN_JUMP = _("\"*{funcname}*(Jump to description for"
" node {funcname})\":#{link} <b>(</b> ")
M_ARG_DEFAULT = C_LINK + " {name}={default}"
M_ARG = C_LINK + " {name}"
OPENPROJ_INH = _("h4. Inherits: ") + C_LINK + "\n\n"
def tb(string):
""" Return a byte representation of a string
"""
return bytes(string, "UTF-8")
def sortkey(c):
""" Symbols are first, letters second
"""
if "_" == c.attrib["name"][0]:
return "A"
else:
return c.attrib["name"]
def toOP(text):
""" Convert commands in text to Open Project commands
"""
# TODO: Make this capture content between [command] ... [/command]
groups = re.finditer((r'\[html (?P<command>/?\w+/?)(\]| |=)?(\]| |=)?(?P<a'
'rg>\w+)?(\]| |=)?(?P<value>"[^"]+")?/?\]'), text)
alignstr = ""
for group in groups:
gd = group.groupdict()
if gd["command"] == "br/":
text = text.replace(group.group(0), "\n\n", 1)
elif gd["command"] == "div":
if gd["value"] == '"center"':
alignstr = ("{display:block; margin-left:auto;"
" margin-right:auto;}")
elif gd["value"] == '"left"':
alignstr = "<"
elif gd["value"] == '"right"':
alignstr = ">"
text = text.replace(group.group(0), "\n\n", 1)
elif gd["command"] == "/div":
alignstr = ""
text = text.replace(group.group(0), "\n\n", 1)
elif gd["command"] == "img":
text = text.replace(group.group(0), "!{align}{src}!".format(
align=alignstr, src=gd["value"].strip('"')), 1)
elif gd["command"] == "b" or gd["command"] == "/b":
text = text.replace(group.group(0), "*", 1)
elif gd["command"] == "i" or gd["command"] == "/i":
text = text.replace(group.group(0), "_", 1)
elif gd["command"] == "u" or gd["command"] == "/u":
text = text.replace(group.group(0), "+", 1)
# Process other non-html commands
groups = re.finditer((r'\[method ((?P<class>[aA0-zZ9_]+)(?:\.))'
r'?(?P<method>[aA0-zZ9_]+)\]'), text)
for group in groups:
gd = group.groupdict()
if gd["class"]:
replacewith = (MC_LINK.format(gclass=gd["class"],
method=gd["method"],
lkclass=gd["class"].lower(),
lkmethod=gd["method"].lower()))
else:
# The method is located in the same wiki page
replacewith = (TM_JUMP.format(method=gd["method"],
lkmethod=gd["method"].lower()))
text = text.replace(group.group(0), replacewith, 1)
# Finally, [Classes] are around brackets, make them direct links
groups = re.finditer(r'\[(?P<class>[az0-AZ0_]+)\]', text)
for group in groups:
gd = group.groupdict()
replacewith = (C_LINK.
format(gclass=gd["class"],
lkclass=gd["class"].lower()))
text = text.replace(group.group(0), replacewith, 1)
return text + "\n\n"
def mkfn(node, is_signal=False):
""" Return a string containing a unsorted item for a function
"""
finalstr = ""
name = node.attrib["name"]
rtype = node.find("return")
if rtype:
rtype = rtype.attrib["type"]
else:
rtype = "void"
# write the return type and the function name first
finalstr += "* "
# return type
if not is_signal:
if rtype != "void":
finalstr += GTC_LINK.format(
rtype=rtype,
link=rtype.lower())
else:
finalstr += " void "
# function name
if not is_signal:
finalstr += DFN_JUMP.format(
funcname=name,
link=name.lower())
else:
# Signals have no description
finalstr += "*{funcname}* <b>(</b>".format(funcname=name)
# loop for the arguments of the function, if any
args = []
for arg in sorted(
node.iter(tag="argument"),
key=lambda a: int(a.attrib["index"])):
ntype = arg.attrib["type"]
nname = arg.attrib["name"]
if "default" in arg.attrib:
args.insert(-1, M_ARG_DEFAULT.format(
gclass=ntype,
lkclass=ntype.lower(),
name=nname,
default=arg.attrib["default"]))
else:
# No default value present
args.insert(-1, M_ARG.format(gclass=ntype,
lkclass=ntype.lower(), name=nname))
# join the arguments together
finalstr += ", ".join(args)
# and, close the function with a )
finalstr += " <b>)</b>"
# write the qualifier, if any
if "qualifiers" in node.attrib:
qualifier = node.attrib["qualifiers"]
finalstr += " " + qualifier
finalstr += "\n"
return finalstr
# Let's begin
tree = ElementTree.parse(args.xmlfp)
root = tree.getroot()
# Check version attribute exists in <doc>
if "version" not in root.attrib:
logging.critical(_("<doc>'s version attribute missing"))
exit(1)
version = root.attrib["version"]
classes = sorted(root, key=sortkey)
# first column is always longer, second column of classes should be shorter
zclasses = zip_longest(classes[:int(len(classes) / 2 + 1)],
classes[int(len(classes) / 2 + 1):],
fillvalue="")
# We write the class_list file and also each class file at once
with open(path.join(args.outputdir, "class_list.txt"), "wb") as fcl:
# Write header of table
fcl.write(tb("|^.\n"))
fcl.write(tb(_("|_. Index symbol |_. Class name "
"|_. Index symbol |_. Class name |\n")))
fcl.write(tb("|-.\n"))
indexletterl = ""
indexletterr = ""
for gdclassl, gdclassr in zclasses:
# write a row #
# write the index symbol column, left
if indexletterl != gdclassl.attrib["name"][0]:
indexletterl = gdclassl.attrib["name"][0]
fcl.write(tb("| *{}* |".format(indexletterl.upper())))
else:
# empty cell
fcl.write(tb("| |"))
# write the class name column, left
fcl.write(tb(C_LINK.format(
gclass=gdclassl.attrib["name"],
lkclass=gdclassl.attrib["name"].lower())))
# write the index symbol column, right
if isinstance(gdclassr, ElementTree.Element):
if indexletterr != gdclassr.attrib["name"][0]:
indexletterr = gdclassr.attrib["name"][0]
fcl.write(tb("| *{}* |".format(indexletterr.upper())))
else:
# empty cell
fcl.write(tb("| |"))
# We are dealing with an empty string
else:
# two empty cell
fcl.write(tb("| | |\n"))
# We won't get the name of the class since there is no ElementTree
# object for the right side of the tuple, so we iterate the next
# tuple instead
continue
# write the class name column (if any), right
fcl.write(tb(C_LINK.format(
gclass=gdclassl.attrib["name"],
lkclass=gdclassl.attrib["name"].lower()) + "|\n"))
# row written #
# now, let's write each class page for each class
for gdclass in [gdclassl, gdclassr]:
if not isinstance(gdclass, ElementTree.Element):
continue
classname = gdclass.attrib["name"]
with open(path.join(args.outputdir, "{}.txt".format(
classname.lower())), "wb") as clsf:
# First level header with the name of the class
clsf.write(tb("h1. {}\n\n".format(classname)))
# lay the attributes
if "inherits" in gdclass.attrib:
inh = gdclass.attrib["inherits"].strip()
clsf.write(tb(OPENPROJ_INH.format(gclass=inh,
lkclass=inh.lower())))
if "category" in gdclass.attrib:
clsf.write(tb(_("h4. Category: {}\n\n").
format(gdclass.attrib["category"].strip())))
# lay child nodes
briefd = gdclass.find("brief_description")
if briefd.text.strip():
clsf.write(tb(_("h2. Brief Description\n\n")))
clsf.write(tb(toOP(briefd.text.strip()) +
_("\"read more\":#more\n\n")))
# Write the list of member functions of this class
methods = gdclass.find("methods")
if methods and len(methods) > 0:
clsf.write(tb(_("\nh3. Member Functions\n\n")))
for method in methods.iter(tag='method'):
clsf.write(tb(mkfn(method)))
signals = gdclass.find("signals")
if signals and len(signals) > 0:
clsf.write(tb(_("\nh3. Signals\n\n")))
for signal in signals.iter(tag='signal'):
clsf.write(tb(mkfn(signal, True)))
# TODO: <members> tag is necessary to process? it does not
# exists in class_list.xml file.
consts = gdclass.find("constants")
if consts and len(consts) > 0:
clsf.write(tb(_("\nh3. Numeric Constants\n\n")))
for const in sorted(consts, key=lambda k:
k.attrib["name"]):
if const.text.strip():
clsf.write(tb("* *{name}* = *{value}* - {desc}\n".
format(
name=const.attrib["name"],
value=const.attrib["value"],
desc=const.text.strip())))
else:
# Constant have no description
clsf.write(tb("* *{name}* = *{value}*\n".
format(
name=const.attrib["name"],
value=const.attrib["value"])))
descrip = gdclass.find("description")
clsf.write(tb(_("\nh3(#more). Description\n\n")))
if descrip.text:
clsf.write(tb(descrip.text.strip() + "\n"))
else:
clsf.write(tb(_("_Nothing here, yet..._\n")))
# and finally, the description for each method
if methods and len(methods) > 0:
clsf.write(tb(_("\nh3. Member Function Description\n\n")))
for method in methods.iter(tag='method'):
clsf.write(tb("h4(#{n}). {name}\n\n".format(
n=method.attrib["name"].lower(),
name=method.attrib["name"])))
clsf.write(tb(mkfn(method) + "\n"))
clsf.write(tb(toOP(method.find(
"description").text.strip())))

View file

@ -547,6 +547,7 @@ Error EditorHelp::_goto_desc(const String& p_class,bool p_update_history,int p_v
class_desc->pop();
class_desc->add_newline();
class_desc->add_newline();
class_desc->add_newline();
}
@ -563,6 +564,7 @@ Error EditorHelp::_goto_desc(const String& p_class,bool p_update_history,int p_v
_add_text(cd.brief_description);
class_desc->add_newline();
class_desc->add_newline();
class_desc->add_newline();
}
bool method_descr=false;
@ -637,7 +639,6 @@ Error EditorHelp::_goto_desc(const String& p_class,bool p_update_history,int p_v
if (cd.properties.size()) {
class_desc->push_color(EditorSettings::get_singleton()->get("text_editor/keyword_color"));
class_desc->push_font(doc_title_font);
class_desc->add_text("Members:");
@ -715,9 +716,10 @@ Error EditorHelp::_goto_desc(const String& p_class,bool p_update_history,int p_v
class_desc->add_newline();
}
class_desc->add_newline();
class_desc->pop();
class_desc->add_newline();
class_desc->add_newline();
}
if (cd.signals.size()) {
@ -779,6 +781,7 @@ Error EditorHelp::_goto_desc(const String& p_class,bool p_update_history,int p_v
class_desc->pop();
class_desc->add_newline();
class_desc->add_newline();
}
@ -823,6 +826,7 @@ Error EditorHelp::_goto_desc(const String& p_class,bool p_update_history,int p_v
class_desc->pop();
class_desc->add_newline();
class_desc->add_newline();
}
@ -830,17 +834,18 @@ Error EditorHelp::_goto_desc(const String& p_class,bool p_update_history,int p_v
if (cd.description!="") {
description_line=class_desc->get_line_count()-2;
class_desc->push_color(EditorSettings::get_singleton()->get("text_editor/keyword_color"));
class_desc->push_font(doc_title_font);
class_desc->add_text("Description:");
class_desc->pop();
class_desc->pop();
class_desc->add_newline();
class_desc->add_newline();
_add_text(cd.description);
class_desc->add_newline();
class_desc->add_newline();
class_desc->add_newline();
}
if (method_descr) {
@ -853,12 +858,16 @@ Error EditorHelp::_goto_desc(const String& p_class,bool p_update_history,int p_v
class_desc->add_newline();
class_desc->add_newline();
class_desc->push_indent(1);
for(int i=0;i<cd.methods.size();i++) {
method_line[cd.methods[i].name]=class_desc->get_line_count()-2;
if( cd.methods[i].description != "") {
class_desc->add_newline();
}
class_desc->push_font(doc_code_font);
_add_type(cd.methods[i].return_type);
@ -899,9 +908,12 @@ Error EditorHelp::_goto_desc(const String& p_class,bool p_update_history,int p_v
class_desc->pop();
class_desc->add_newline();
class_desc->add_newline();
_add_text(cd.methods[i].description);
if( cd.methods[i].description != "") {
class_desc->add_text(" ");
_add_text(cd.methods[i].description);
class_desc->add_newline();
class_desc->add_newline();
}
class_desc->add_newline();
class_desc->add_newline();
@ -1392,6 +1404,8 @@ EditorHelp::EditorHelp(EditorNode *p_editor) {
PanelContainer *pc = memnew( PanelContainer );
Ref<StyleBoxFlat> style( memnew( StyleBoxFlat ) );
style->set_bg_color( EditorSettings::get_singleton()->get("text_editor/background_color") );
style->set_default_margin(MARGIN_LEFT,20);
style->set_default_margin(MARGIN_TOP,20);
pc->add_style_override("panel", style); //get_stylebox("normal","TextEdit"));
h_split->add_child(pc);
class_desc = memnew( RichTextLabel );

View file

@ -1108,6 +1108,11 @@ void EditorNode::_dialog_action(String p_file) {
push_item(res.operator->() );
} break;
case FILE_NEW_INHERITED_SCENE: {
load_scene(p_file,false,true);
} break;
case FILE_OPEN_SCENE: {
@ -1931,6 +1936,7 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
} break;
case FILE_NEW_INHERITED_SCENE:
case FILE_OPEN_SCENE: {
@ -1951,7 +1957,7 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
if (scene) {
file->set_current_path(scene->get_filename());
};
file->set_title("Open Scene");
file->set_title(p_option==FILE_OPEN_SCENE?"Open Scene":"Open Base Scene");
file->popup_centered_ratio();
} break;
@ -3312,7 +3318,7 @@ void EditorNode::fix_dependencies(const String& p_for_file) {
dependency_fixer->edit(p_for_file);
}
Error EditorNode::load_scene(const String& p_scene, bool p_ignore_broken_deps) {
Error EditorNode::load_scene(const String& p_scene, bool p_ignore_broken_deps,bool p_set_inherited) {
if (!is_inside_tree()) {
defer_load_scene = p_scene;
@ -3442,6 +3448,13 @@ Error EditorNode::load_scene(const String& p_scene, bool p_ignore_broken_deps) {
}
*/
if (p_set_inherited) {
Ref<SceneState> state = sdata->get_state();
state->set_path(lpath);
new_scene->set_scene_inherited_state(state);
}
set_edited_scene(new_scene);
_get_scene_metadata();
/*
@ -4404,6 +4417,7 @@ void EditorNode::_scene_tab_changed(int p_tab) {
EditorNode::EditorNode() {
EditorHelp::generate_doc(); //before any editor classes are crated
SceneState::set_disable_placeholders(true);
InputDefault *id = Input::get_singleton()->cast_to<InputDefault>();
@ -4794,6 +4808,7 @@ EditorNode::EditorNode() {
file_menu->set_tooltip("Operations with scene files.");
p=file_menu->get_popup();
p->add_item("New Scene",FILE_NEW_SCENE);
p->add_item("New Inherited Scene..",FILE_NEW_INHERITED_SCENE);
p->add_item("Open Scene..",FILE_OPEN_SCENE,KEY_MASK_CMD+KEY_O);
p->add_separator();
p->add_item("Save Scene",FILE_SAVE_SCENE,KEY_MASK_CMD+KEY_S);

View file

@ -107,6 +107,7 @@ class EditorNode : public Node {
enum MenuOptions {
FILE_NEW_SCENE,
FILE_NEW_INHERITED_SCENE,
FILE_OPEN_SCENE,
FILE_SAVE_SCENE,
FILE_SAVE_AS_SCENE,
@ -565,7 +566,7 @@ public:
void fix_dependencies(const String& p_for_file);
void clear_scene() { _cleanup_scene(); }
Error load_scene(const String& p_scene,bool p_ignore_broken_deps=false);
Error load_scene(const String& p_scene, bool p_ignore_broken_deps=false, bool p_set_inherited=false);
Error load_resource(const String& p_scene);
bool is_scene_open(const String& p_path);

View file

@ -74,6 +74,7 @@ void EditorPlugin::add_custom_control(CustomControlContainer p_location,Control
case CONTAINER_CANVAS_EDITOR_SIDE: {
CanvasItemEditor::get_singleton()->get_palette_split()->add_child(p_control);
CanvasItemEditor::get_singleton()->get_palette_split()->move_child(p_control,0);
} break;
case CONTAINER_CANVAS_EDITOR_BOTTOM: {

View file

@ -710,7 +710,7 @@ void EditorSampleImportPlugin::_compress_ima_adpcm(const Vector<float>& p_data,D
*(out++) =0;
for (i=0;i<datalen;i++) {
int step,diff,vpdiff,signed_nibble,p,mask;
int step,diff,vpdiff,mask;
uint8_t nibble;
int16_t xm_sample;

View file

@ -42,6 +42,8 @@
#include "multi_node_edit.h"
#include "array_property_edit.h"
#include "editor_help.h"
#include "scene/resources/packed_scene.h"
void CustomPropertyEditor::_notification(int p_what) {
@ -1655,25 +1657,101 @@ CustomPropertyEditor::CustomPropertyEditor() {
menu->connect("item_pressed",this,"_menu_option");
}
bool PropertyEditor::_might_be_in_instance() {
Node *PropertyEditor::get_instanced_node() {
//this sucks badly
if (!obj)
return NULL;
Node *node = obj->cast_to<Node>();
Node* edited_scene =EditorNode::get_singleton()->get_edited_scene();
bool might_be=false;
while(node) {
if (node->get_scene_instance_state().is_valid()) {
might_be=true;
break;
}
if (node==edited_scene) {
if (node->get_scene_inherited_state().is_valid()) {
might_be=true;
break;
}
might_be=false;
break;
}
node=node->get_owner();
}
return might_be;
}
bool PropertyEditor::_get_instanced_node_original_property(const StringName& p_prop,Variant& value) {
Node *node = obj->cast_to<Node>();
if (!node)
return NULL;
return false;
if (node->get_filename()=="")
return NULL;
Node *orig=node;
if (!node->get_owner())
return NULL; //scene root i guess
Node* edited_scene =EditorNode::get_singleton()->get_edited_scene();
return node;
bool found=false;
// print_line("for prop - "+String(p_prop));
while(node) {
Ref<SceneState> ss;
if (node==edited_scene) {
ss=node->get_scene_inherited_state();
} else {
ss=node->get_scene_instance_state();
}
// print_line("at - "+String(edited_scene->get_path_to(node)));
if (ss.is_valid()) {
NodePath np = node->get_path_to(orig);
int node_idx = ss->find_node_by_path(np);
// print_line("\t valid, nodeidx "+itos(node_idx));
if (node_idx>=0) {
bool lfound=false;
Variant lvar;
lvar=ss->get_property_value(node_idx,p_prop,lfound);
if (lfound) {
found=true;
value=lvar;
// print_line("\t found value "+String(value));
}
}
}
if (node==edited_scene) {
//just in case
break;
}
node=node->get_owner();
}
return found;
}
bool PropertyEditor::_is_property_different(const Variant& p_current, const Variant& p_orig,int p_usage) {
if (p_orig.get_type()==Variant::NIL) {
//special cases
if (p_current.is_zero() && p_usage&PROPERTY_USAGE_STORE_IF_NONZERO)
return false;
if (p_current.is_one() && p_usage&PROPERTY_USAGE_STORE_IF_NONONE)
return false;
}
return bool(Variant::evaluate(Variant::OP_NOT_EQUAL,p_current,p_orig));
}
TreeItem *PropertyEditor::find_item(TreeItem *p_item,const String& p_name) {
@ -1910,6 +1988,8 @@ void PropertyEditor::set_item_text(TreeItem *p_item, int p_type, const String& p
}
void PropertyEditor::_notification(int p_what) {
if (p_what==NOTIFICATION_ENTER_TREE) {
@ -1950,12 +2030,16 @@ void PropertyEditor::_notification(int p_what) {
if (!item)
continue;
if (get_instanced_node()) {
if (_might_be_in_instance()) {
Dictionary d = get_instanced_node()->get_instance_state();
if (d.has(*k)) {
Variant vorig;
Dictionary d=item->get_metadata(0);
int usage = d.has("usage")?int(int(d["usage"])&(PROPERTY_USAGE_STORE_IF_NONONE|PROPERTY_USAGE_STORE_IF_NONZERO)):0;
if (_get_instanced_node_original_property(*k,vorig) || usage) {
Variant v = obj->get(*k);
Variant vorig = d[*k];
int found=-1;
for(int i=0;i<item->get_button_count(1);i++) {
@ -1966,7 +2050,7 @@ void PropertyEditor::_notification(int p_what) {
}
}
bool changed = ! (v==vorig);
bool changed = _is_property_different(v,vorig,usage);
if ((found!=-1)!=changed) {
@ -2049,12 +2133,14 @@ void PropertyEditor::_refresh_item(TreeItem *p_item) {
if (name!=String()) {
if (get_instanced_node()) {
if (_might_be_in_instance()) {
Dictionary d = get_instanced_node()->get_instance_state();
if (d.has(name)) {
Variant vorig;
Dictionary d=p_item->get_metadata(0);
int usage = d.has("usage")?int(int(d["usage"])&(PROPERTY_USAGE_STORE_IF_NONONE|PROPERTY_USAGE_STORE_IF_NONZERO)):0;
if (_get_instanced_node_original_property(name,vorig) || usage) {
Variant v = obj->get(name);
Variant vorig = d[name];
int found=-1;
for(int i=0;i<p_item->get_button_count(1);i++) {
@ -2065,7 +2151,7 @@ void PropertyEditor::_refresh_item(TreeItem *p_item) {
}
}
bool changed = ! (v==vorig);
bool changed = _is_property_different(v,vorig,usage);
if ((found!=-1)!=changed) {
@ -2326,7 +2412,8 @@ void PropertyEditor::update_tree() {
d["type"]=(int)p.type;
d["hint"]=(int)p.hint;
d["hint_text"]=p.hint_string;
d["usage"]=(int)p.usage;
item->set_metadata( 0, d );
item->set_metadata( 1, p.name );
@ -2777,14 +2864,17 @@ void PropertyEditor::update_tree() {
}
}
if (get_instanced_node()) {
if (_might_be_in_instance()) {
Dictionary d = get_instanced_node()->get_instance_state();
if (d.has(p.name)) {
Variant vorig;
Dictionary d=item->get_metadata(0);
int usage = d.has("usage")?int(int(d["usage"])&(PROPERTY_USAGE_STORE_IF_NONONE|PROPERTY_USAGE_STORE_IF_NONZERO)):0;
if (_get_instanced_node_original_property(p.name,vorig) || usage) {
Variant v = obj->get(p.name);
Variant vorig = d[p.name];
if (! (v==vorig)) {
if (_is_property_different(v,vorig,usage)) {
//print_line("FOR "+String(p.name)+" RELOAD WITH: "+String(v)+"("+Variant::get_type_name(v.get_type())+")=="+String(vorig)+"("+Variant::get_type_name(vorig.get_type())+")");
item->add_button(1,get_icon("Reload","EditorIcons"),3);
}
}
@ -3081,17 +3171,18 @@ void PropertyEditor::_edit_button(Object *p_item, int p_column, int p_button) {
call_deferred("_set_range_def",ti,prop,ti->get_range(p_column)+1.0);
} else if (p_button==3) {
if (!get_instanced_node())
if (!_might_be_in_instance())
return;
if (!d.has("name"))
return;
String prop=d["name"];
Dictionary d2 = get_instanced_node()->get_instance_state();
if (d2.has(prop)) {
Variant vorig;
_edit_set(prop,d2[prop]);
if (_get_instanced_node_original_property(prop,vorig)) {
_edit_set(prop,vorig);
}
} else {

View file

@ -121,6 +121,7 @@ class CustomPropertyEditor : public Popup {
void show_value_editors(int p_amount);
void config_value_editors(int p_amount, int p_columns,int p_label_w,const List<String>& p_strings);
void config_action_buttons(const List<String>& p_strings);
protected:
void _notification(int p_what);
@ -184,13 +185,17 @@ class PropertyEditor : public Control {
virtual void _changed_callback(Object *p_changed,const char * p_what);
virtual void _changed_callbacks(Object *p_changed,const String& p_callback);
void _edit_button(Object *p_item, int p_column, int p_button);
void _node_removed(Node *p_node);
void _edit_set(const String& p_name, const Variant& p_value);
void _draw_flags(Object *ti,const Rect2& p_rect);
Node *get_instanced_node();
bool _might_be_in_instance();
bool _get_instanced_node_original_property(const StringName& p_prop,Variant& value);
bool _is_property_different(const Variant& p_current, const Variant& p_orig,int p_usage=0);
void _refresh_item(TreeItem *p_item);
void _set_range_def(Object *p_item, String prop, float p_frame);

View file

@ -103,6 +103,7 @@ ReparentDialog::ReparentDialog() {
add_child(node_only);
node_only->hide();
tree->set_show_enabled_subscene(true);
//vbc->add_margin_child("Options:",node_only);;

View file

@ -36,8 +36,8 @@
#include "script_editor_debugger.h"
#include "tools/editor/plugins/script_editor_plugin.h"
#include "multi_node_edit.h"
void SceneTreeDock::_unhandled_key_input(InputEvent p_event) {
void SceneTreeDock::_unhandled_key_input(InputEvent p_event) {
uint32_t sc = p_event.key.get_scancode_with_modifiers();
if (!p_event.key.pressed || p_event.key.echo)
@ -71,7 +71,7 @@ Node* SceneTreeDock::instance(const String& p_file) {
Node*instanced_scene=NULL;
Ref<PackedScene> sdata = ResourceLoader::load(p_file);
if (sdata.is_valid())
instanced_scene=sdata->instance();
instanced_scene=sdata->instance(true);
if (!instanced_scene) {
@ -96,7 +96,7 @@ Node* SceneTreeDock::instance(const String& p_file) {
}
}
instanced_scene->generate_instance_state();
//instanced_scene->generate_instance_state();
instanced_scene->set_filename( Globals::get_singleton()->localize_path(p_file) );
editor_data->get_undo_redo().create_action("Instance Scene");
@ -158,8 +158,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
case TOOL_NEW: {
if (!_validate_no_foreign())
break;
//if (!_validate_no_foreign())
// break;
create_dialog->popup_centered_ratio();
} break;
case TOOL_INSTANCE: {
@ -176,8 +176,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
break;
}
if (!_validate_no_foreign())
break;
//if (!_validate_no_foreign())
// break;
file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
List<String> extensions;
@ -202,8 +202,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
if (!current)
break;
if (!_validate_no_foreign())
break;
//if (!_validate_no_foreign())
// break;
connect_dialog->popup_centered_ratio();
connect_dialog->set_node(current);
@ -213,8 +213,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
Node *current = scene_tree->get_selected();
if (!current)
break;
if (!_validate_no_foreign())
break;
//if (!_validate_no_foreign())
// break;
groups_editor->set_current(current);
groups_editor->popup_centered_ratio();
} break;
@ -224,8 +224,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
if (!selected)
break;
if (!_validate_no_foreign())
break;
//if (!_validate_no_foreign())
// break;
Ref<Script> existing = selected->get_script();
if (existing.is_valid())
@ -573,9 +573,9 @@ Node *SceneTreeDock::_duplicate(Node *p_node, Map<Node*,Node*> &duplimap) {
Ref<PackedScene> sd = ResourceLoader::load( p_node->get_filename() );
ERR_FAIL_COND_V(!sd.is_valid(),NULL);
node = sd->instance();
node = sd->instance(true);
ERR_FAIL_COND_V(!node,NULL);
node->generate_instance_state();
//node->generate_instance_state();
} else {
Object *obj = ObjectTypeDB::instance(p_node->get_type());
ERR_FAIL_COND_V(!obj,NULL);
@ -874,6 +874,16 @@ bool SceneTreeDock::_validate_no_foreign() {
return false;
}
if (edited_scene->get_scene_instance_state().is_valid() && edited_scene->get_scene_instance_state()->find_node_by_path(edited_scene->get_path_to(E->get()))>=0) {
accept->get_ok()->set_text("Makes Sense!");
accept->set_text("Can't operate on nodes the current scene inherits from!");
accept->popup_centered_minsize();
return false;
}
}
return true;
@ -1078,14 +1088,15 @@ void SceneTreeDock::_delete_confirm() {
void SceneTreeDock::_update_tool_buttons() {
Node *sel = scene_tree->get_selected();
bool disable = !sel || (sel!=edited_scene && sel->get_owner()!=edited_scene);
bool disable = !sel || (sel!=edited_scene && sel->get_owner()!=edited_scene) || (edited_scene->get_scene_instance_state().is_valid() && edited_scene->get_scene_instance_state()->find_node_by_path(edited_scene->get_path_to(sel))>=0);
bool disable_root = disable || sel->get_parent()==scene_root;
bool disable_edit = !sel;
tool_buttons[TOOL_INSTANCE]->set_disabled(disable);
tool_buttons[TOOL_INSTANCE]->set_disabled(disable_edit);
tool_buttons[TOOL_REPLACE]->set_disabled(disable);
tool_buttons[TOOL_CONNECT]->set_disabled(disable);
tool_buttons[TOOL_GROUP]->set_disabled(disable);
tool_buttons[TOOL_SCRIPT]->set_disabled(disable);
tool_buttons[TOOL_CONNECT]->set_disabled(disable_edit);
tool_buttons[TOOL_GROUP]->set_disabled(disable_edit);
tool_buttons[TOOL_SCRIPT]->set_disabled(disable_edit);
tool_buttons[TOOL_MOVE_UP]->set_disabled(disable_root);
tool_buttons[TOOL_MOVE_DOWN]->set_disabled(disable_root);
tool_buttons[TOOL_DUPLICATE]->set_disabled(disable_root);

View file

@ -34,6 +34,8 @@
#include "scene/main/viewport.h"
#include "tools/editor/plugins/canvas_item_editor_plugin.h"
#include "scene/resources/packed_scene.h"
Node *SceneTreeEditor::get_scene_node() {
ERR_FAIL_COND_V(!is_inside_tree(),NULL);
@ -57,22 +59,58 @@ void SceneTreeEditor::_subscene_option(int p_idx) {
switch(p_idx) {
case SCENE_MENU_SHOW_CHILDREN: {
case SCENE_MENU_EDITABLE_CHILDREN: {
if (node->has_meta("__editor_show_subtree")) {
instance_menu->set_item_checked(0,true);
node->set_meta("__editor_show_subtree",Variant());
_update_tree();
} else {
node->set_meta("__editor_show_subtree",true);
_update_tree();
bool editable = EditorNode::get_singleton()->get_edited_scene()->is_editable_instance(node);
editable = !editable;
//node->set_instance_children_editable(editable);
EditorNode::get_singleton()->get_edited_scene()->set_editable_instance(node,editable);
instance_menu->set_item_checked(0,editable);
if (editable) {
node->set_scene_instance_load_placeholder(false);
instance_menu->set_item_checked(1,false);
}
_update_tree();
} break;
case SCENE_MENU_USE_PLACEHOLDER: {
bool placeholder = node->get_scene_instance_load_placeholder();
placeholder = !placeholder;
//node->set_instance_children_editable(editable);
if (placeholder) {
EditorNode::get_singleton()->get_edited_scene()->set_editable_instance(node,false);
}
node->set_scene_instance_load_placeholder(placeholder);
instance_menu->set_item_checked(0,false);
instance_menu->set_item_checked(1,placeholder);
_update_tree();
} break;
case SCENE_MENU_OPEN: {
emit_signal("open",node->get_filename());
} break;
case SCENE_MENU_CLEAR_INHERITANCE: {
clear_inherit_confirm->popup_centered_minsize();
} break;
case SCENE_MENU_OPEN_INHERITED: {
if (node && node->get_scene_inherited_state().is_valid()) {
emit_signal("open",node->get_scene_inherited_state()->get_path());
}
} break;
case SCENE_MENU_CLEAR_INHERITANCE_CONFIRM: {
if (node && node->get_scene_inherited_state().is_valid()) {
node->set_scene_inherited_state(Ref<SceneState>());
update_tree();
EditorNode::get_singleton()->get_property_editor()->update_tree();
}
} break;
}
@ -94,15 +132,33 @@ void SceneTreeEditor::_cell_button_pressed(Object *p_item,int p_column,int p_id)
Rect2 item_rect = tree->get_item_rect(item,0);
item_rect.pos.y-=tree->get_scroll().y;
item_rect.pos+=tree->get_global_pos();
instance_menu->set_pos(item_rect.pos+Vector2(0,item_rect.size.y));
instance_menu->set_size(Vector2(item_rect.size.x,0));
if (n->has_meta("__editor_show_subtree"))
instance_menu->set_item_checked(0,true);
else
instance_menu->set_item_checked(0,false);
instance_menu->popup();
instance_node=n->get_instance_ID();
if (n==get_scene_node()) {
inheritance_menu->set_pos(item_rect.pos+Vector2(0,item_rect.size.y));
inheritance_menu->set_size(Vector2(item_rect.size.x,0));
inheritance_menu->popup();
instance_node=n->get_instance_ID();
} else {
instance_menu->set_pos(item_rect.pos+Vector2(0,item_rect.size.y));
instance_menu->set_size(Vector2(item_rect.size.x,0));
if (EditorNode::get_singleton()->get_edited_scene()->is_editable_instance(n))
instance_menu->set_item_checked(0,true);
else
instance_menu->set_item_checked(0,false);
if (n->get_owner()==get_scene_node()) {
instance_menu->set_item_checked(1,n->get_scene_instance_load_placeholder());
instance_menu->set_item_disabled(1,false);
} else {
instance_menu->set_item_checked(1,false);
instance_menu->set_item_disabled(1,true);
}
instance_menu->popup();
instance_node=n->get_instance_ID();
}
//emit_signal("open",n->get_filename());
} else if (p_id==BUTTON_SCRIPT) {
RefPtr script=n->get_script();
@ -168,15 +224,17 @@ void SceneTreeEditor::_add_nodes(Node *p_node,TreeItem *p_parent) {
bool part_of_subscene=false;
if (!display_foreign && p_node->get_owner()!=get_scene_node() && p_node!=get_scene_node()) {
if (!display_foreign && p_node->get_owner()!=get_scene_node() && p_node!=get_scene_node()) {
if ((show_enabled_subscene || can_open_instance) && p_node->get_owner() && p_node->get_owner()->get_owner()==get_scene_node() && p_node->get_owner()->has_meta("__editor_show_subtree")) {
if ((show_enabled_subscene || can_open_instance) && p_node->get_owner() && (get_scene_node()->is_editable_instance(p_node->get_owner()))) {
part_of_subscene=true;
//allow
} else {
return;
}
} else {
part_of_subscene = get_scene_node()->get_scene_inherited_state().is_valid() && get_scene_node()->get_scene_inherited_state()->find_node_by_path(get_scene_node()->get_path_to(p_node))>=0;
}
TreeItem *item = tree->create_item(p_parent);
@ -199,6 +257,7 @@ void SceneTreeEditor::_add_nodes(Node *p_node,TreeItem *p_parent) {
icon=get_icon( (has_icon(p_node->get_type(),"EditorIcons")?p_node->get_type():String("Object")),"EditorIcons");
item->set_icon(0, icon );
item->set_metadata( 0,p_node->get_path() );
if (part_of_subscene) {
//item->set_selectable(0,marked_selectable);
@ -221,7 +280,10 @@ void SceneTreeEditor::_add_nodes(Node *p_node,TreeItem *p_parent) {
}
}
if (p_node!=get_scene_node() && p_node->get_filename()!="" && can_open_instance) {
if (p_node==get_scene_node() && p_node->get_scene_inherited_state().is_valid()) {
item->add_button(0,get_icon("InstanceOptions","EditorIcons"),BUTTON_SUBSCENE);
item->set_tooltip(0,"Inherits: "+p_node->get_scene_inherited_state()->get_path()+"\nType: "+p_node->get_type());
} else if (p_node!=get_scene_node() && p_node->get_filename()!="" && can_open_instance) {
item->add_button(0,get_icon("InstanceOptions","EditorIcons"),BUTTON_SUBSCENE);
item->set_tooltip(0,"Instance: "+p_node->get_filename()+"\nType: "+p_node->get_type());
@ -487,8 +549,11 @@ void SceneTreeEditor::_notification(int p_what) {
get_tree()->connect("tree_changed",this,"_tree_changed");
get_tree()->connect("node_removed",this,"_node_removed");
instance_menu->set_item_icon(2,get_icon("Load","EditorIcons"));
instance_menu->set_item_icon(3,get_icon("Load","EditorIcons"));
tree->connect("item_collapsed",this,"_cell_collapsed");
inheritance_menu->set_item_icon(2,get_icon("Load","EditorIcons"));
clear_inherit_confirm->connect("confirmed",this,"_subscene_option",varray(SCENE_MENU_CLEAR_INHERITANCE_CONFIRM));
// get_scene()->connect("tree_changed",this,"_tree_changed",Vector<Variant>(),CONNECT_DEFERRED);
// get_scene()->connect("node_removed",this,"_node_removed",Vector<Variant>(),CONNECT_DEFERRED);
@ -499,6 +564,7 @@ void SceneTreeEditor::_notification(int p_what) {
get_tree()->disconnect("tree_changed",this,"_tree_changed");
get_tree()->disconnect("node_removed",this,"_node_removed");
tree->disconnect("item_collapsed",this,"_cell_collapsed");
clear_inherit_confirm->disconnect("confirmed",this,"_subscene_option");
_update_tree();
}
@ -788,12 +854,27 @@ SceneTreeEditor::SceneTreeEditor(bool p_label,bool p_can_rename, bool p_can_open
blocked=0;
instance_menu = memnew( PopupMenu );
instance_menu->add_check_item("Show Children",SCENE_MENU_SHOW_CHILDREN);
instance_menu->add_check_item("Editable Children",SCENE_MENU_EDITABLE_CHILDREN);
instance_menu->add_check_item("Load As Placeholder",SCENE_MENU_USE_PLACEHOLDER);
instance_menu->add_separator();
instance_menu->add_item("Open in Editor",SCENE_MENU_OPEN);
instance_menu->connect("item_pressed",this,"_subscene_option");
add_child(instance_menu);
inheritance_menu = memnew( PopupMenu );
inheritance_menu->add_item("Clear Inheritance",SCENE_MENU_CLEAR_INHERITANCE);
inheritance_menu->add_separator();
inheritance_menu->add_item("Open in Editor",SCENE_MENU_OPEN_INHERITED);
inheritance_menu->connect("item_pressed",this,"_subscene_option");
add_child(inheritance_menu);
clear_inherit_confirm = memnew( ConfirmationDialog );
clear_inherit_confirm->set_text("Clear Inheritance? (No Undo!)");
clear_inherit_confirm->get_ok()->set_text("Clear!");
add_child(clear_inherit_confirm);
}

View file

@ -52,16 +52,22 @@ class SceneTreeEditor : public Control {
};
enum {
SCENE_MENU_SHOW_CHILDREN,
SCENE_MENU_EDITABLE_CHILDREN,
SCENE_MENU_USE_PLACEHOLDER,
SCENE_MENU_OPEN,
SCENE_MENU_CLEAR_INHERITANCE,
SCENE_MENU_OPEN_INHERITED,
SCENE_MENU_CLEAR_INHERITANCE_CONFIRM,
};
Tree *tree;
Node *selected;
PopupMenu *instance_menu;
PopupMenu *inheritance_menu;
ObjectID instance_node;
AcceptDialog *error;
ConfirmationDialog *clear_inherit_confirm;
int blocked;

View file

@ -104,11 +104,6 @@ class ExportDAE(bpy.types.Operator, ExportHelper):
description="Export only objects on the active layers.",
default=True,
)
use_exclude_ctrl_bones = BoolProperty(
name="Exclude Control Bones",
description="Exclude skeleton bones with names that begin with 'ctrl'.",
default=True,
)
use_anim = BoolProperty(
name="Export Animation",
description="Export keyframe animation",