Merge branch 'master' of https://github.com/okamstudio/godot
This commit is contained in:
commit
4452e26253
|
@ -23,6 +23,9 @@ tools/editor/editor_icons.cpp
|
|||
make.bat
|
||||
log.txt
|
||||
|
||||
# Doxygen generated documentation
|
||||
doc/doxygen/*
|
||||
|
||||
# Javascript specific
|
||||
*.bc
|
||||
|
||||
|
@ -81,6 +84,8 @@ platform/android/libs/play_licensing/gen/*
|
|||
*.suo
|
||||
*.user
|
||||
*.sln.docstates
|
||||
*.sln
|
||||
*.vcxproj*
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
|
|
6
Doxyfile
6
Doxyfile
|
@ -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
|
||||
|
|
|
@ -61,6 +61,7 @@ const char ** tests_get_names() {
|
|||
"gui",
|
||||
"io",
|
||||
"shaderlang",
|
||||
"physics",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
|
|
@ -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)));
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
10
core/list.h
10
core/list.h
|
@ -518,10 +518,16 @@ public:
|
|||
|
||||
if (value->prev_ptr) {
|
||||
value->prev_ptr->next_ptr = value->next_ptr;
|
||||
};
|
||||
}
|
||||
else {
|
||||
_data->first = value->next_ptr;
|
||||
}
|
||||
if (value->next_ptr) {
|
||||
value->next_ptr->prev_ptr = value->prev_ptr;
|
||||
};
|
||||
}
|
||||
else {
|
||||
_data->last = value->prev_ptr;
|
||||
}
|
||||
|
||||
value->next_ptr = where;
|
||||
if (!where) {
|
||||
|
|
|
@ -40,11 +40,11 @@ struct Vector3 {
|
|||
enum Axis {
|
||||
AXIS_X,
|
||||
AXIS_Y,
|
||||
AXIS_Z,
|
||||
AXIS_Z,
|
||||
};
|
||||
|
||||
union {
|
||||
|
||||
|
||||
#ifdef USE_QUAD_VECTORS
|
||||
|
||||
struct {
|
||||
|
@ -52,7 +52,7 @@ struct Vector3 {
|
|||
real_t y;
|
||||
real_t z;
|
||||
real_t _unused;
|
||||
};
|
||||
};
|
||||
real_t coord[4];
|
||||
#else
|
||||
|
||||
|
@ -61,18 +61,18 @@ struct Vector3 {
|
|||
real_t y;
|
||||
real_t z;
|
||||
};
|
||||
|
||||
|
||||
real_t coord[3];
|
||||
#endif
|
||||
};
|
||||
|
||||
_FORCE_INLINE_ const real_t& operator[](int p_axis) const {
|
||||
|
||||
|
||||
return coord[p_axis];
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ real_t& operator[](int p_axis) {
|
||||
|
||||
|
||||
return coord[p_axis];
|
||||
}
|
||||
|
||||
|
@ -84,7 +84,7 @@ struct Vector3 {
|
|||
|
||||
_FORCE_INLINE_ real_t length() const;
|
||||
_FORCE_INLINE_ real_t length_squared() const;
|
||||
|
||||
|
||||
_FORCE_INLINE_ void normalize();
|
||||
_FORCE_INLINE_ Vector3 normalized() const;
|
||||
_FORCE_INLINE_ Vector3 inverse() const;
|
||||
|
@ -107,6 +107,8 @@ struct Vector3 {
|
|||
_FORCE_INLINE_ real_t dot(const Vector3& p_b) const;
|
||||
|
||||
_FORCE_INLINE_ Vector3 abs() const;
|
||||
_FORCE_INLINE_ Vector3 floor() const;
|
||||
_FORCE_INLINE_ Vector3 ceil() const;
|
||||
|
||||
_FORCE_INLINE_ real_t distance_to(const Vector3& p_b) const;
|
||||
_FORCE_INLINE_ real_t distance_squared_to(const Vector3& p_b) const;
|
||||
|
@ -172,7 +174,17 @@ real_t Vector3::dot(const Vector3& p_b) const {
|
|||
Vector3 Vector3::abs() const {
|
||||
|
||||
return Vector3( Math::abs(x), Math::abs(y), Math::abs(z) );
|
||||
}
|
||||
}
|
||||
|
||||
Vector3 Vector3::floor() const {
|
||||
|
||||
return Vector3( Math::floor(x), Math::floor(y), Math::floor(z) );
|
||||
}
|
||||
|
||||
Vector3 Vector3::ceil() const {
|
||||
|
||||
return Vector3( Math::ceil(x), Math::ceil(y), Math::ceil(z) );
|
||||
}
|
||||
|
||||
Vector3 Vector3::linear_interpolate(const Vector3& p_b,float p_t) const {
|
||||
|
||||
|
@ -301,7 +313,7 @@ bool Vector3::operator<(const Vector3& p_v) const {
|
|||
return y<p_v.y;
|
||||
} else
|
||||
return x<p_v.x;
|
||||
|
||||
|
||||
}
|
||||
|
||||
bool Vector3::operator<=(const Vector3& p_v) const {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -359,6 +359,8 @@ static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Var
|
|||
VCALL_LOCALMEM1R(Vector3, dot);
|
||||
VCALL_LOCALMEM1R(Vector3, cross);
|
||||
VCALL_LOCALMEM0R(Vector3, abs);
|
||||
VCALL_LOCALMEM0R(Vector3, floor);
|
||||
VCALL_LOCALMEM0R(Vector3, ceil);
|
||||
VCALL_LOCALMEM1R(Vector3, distance_to);
|
||||
VCALL_LOCALMEM1R(Vector3, distance_squared_to);
|
||||
VCALL_LOCALMEM1R(Vector3, slide);
|
||||
|
@ -753,7 +755,7 @@ static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Var
|
|||
}
|
||||
|
||||
static void Matrix32_init2(Variant& r_ret,const Variant** p_args) {
|
||||
|
||||
|
||||
Matrix32 m(*p_args[0], *p_args[1]);
|
||||
r_ret=m;
|
||||
}
|
||||
|
@ -1133,7 +1135,7 @@ void Variant::get_method_list(List<MethodInfo> *p_list) const {
|
|||
if (fd.returns)
|
||||
ret.name="ret";
|
||||
mi.return_val=ret;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
p_list->push_back(mi);
|
||||
}
|
||||
|
@ -1336,6 +1338,8 @@ _VariantCall::addfunc(Variant::m_vtype,Variant::m_ret,_SCS(#m_method),VCALL(m_cl
|
|||
ADDFUNC1(VECTOR3,REAL,Vector3,dot,VECTOR3,"b",varray());
|
||||
ADDFUNC1(VECTOR3,VECTOR3,Vector3,cross,VECTOR3,"b",varray());
|
||||
ADDFUNC0(VECTOR3,VECTOR3,Vector3,abs,varray());
|
||||
ADDFUNC0(VECTOR3,VECTOR3,Vector3,floor,varray());
|
||||
ADDFUNC0(VECTOR3,VECTOR3,Vector3,ceil,varray());
|
||||
ADDFUNC1(VECTOR3,REAL,Vector3,distance_to,VECTOR3,"b",varray());
|
||||
ADDFUNC1(VECTOR3,REAL,Vector3,distance_squared_to,VECTOR3,"b",varray());
|
||||
ADDFUNC1(VECTOR3,VECTOR3,Vector3,slide,VECTOR3,"by",varray());
|
||||
|
@ -1535,10 +1539,10 @@ _VariantCall::addfunc(Variant::m_vtype,Variant::m_ret,_SCS(#m_method),VCALL(m_cl
|
|||
ADDFUNC1(TRANSFORM,NIL,Transform,xform,NIL,"v",varray());
|
||||
ADDFUNC1(TRANSFORM,NIL,Transform,xform_inv,NIL,"v",varray());
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
#ifdef DEBUG_ENABLED
|
||||
_VariantCall::type_funcs[Variant::TRANSFORM].functions["xform"].returns=true;
|
||||
_VariantCall::type_funcs[Variant::TRANSFORM].functions["xform_inv"].returns=true;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
ADDFUNC0(INPUT_EVENT,BOOL,InputEvent,is_pressed,varray());
|
||||
ADDFUNC1(INPUT_EVENT,BOOL,InputEvent,is_action,STRING,"action",varray());
|
||||
|
@ -1635,9 +1639,3 @@ void unregister_variant_methods() {
|
|||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
filter=false
|
|
@ -91,4 +91,5 @@ func _ready():
|
|||
# Initalization here
|
||||
pass
|
||||
|
||||
|
||||
func _die():
|
||||
queue_free()
|
||||
|
|
Binary file not shown.
|
@ -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>
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
#ifdef __HAIKU__
|
||||
#undef GLEW_ENABLED
|
||||
#endif
|
||||
|
||||
#ifdef GLEW_ENABLED
|
||||
/*
|
||||
** The OpenGL Extension Wrangler Library
|
||||
|
|
|
@ -243,7 +243,7 @@ OS::Date OS_Unix::get_date(bool utc) const {
|
|||
lt=localtime(&t);
|
||||
Date ret;
|
||||
ret.year=1900+lt->tm_year;
|
||||
ret.month=(Month)lt->tm_mon;
|
||||
ret.month=(Month)(lt->tm_mon + 1);
|
||||
ret.day=lt->tm_mday;
|
||||
ret.weekday=(Weekday)lt->tm_wday;
|
||||
ret.dst=lt->tm_isdst;
|
||||
|
|
|
@ -13,7 +13,11 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#ifndef NO_FCNTL
|
||||
#include <sys/fcntl.h>
|
||||
#ifdef __HAIKU__
|
||||
#include <fcntl.h>
|
||||
#else
|
||||
#include <sys/fcntl.h>
|
||||
#endif
|
||||
#else
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
|
|
@ -39,7 +39,11 @@
|
|||
#include <netdb.h>
|
||||
#include <sys/types.h>
|
||||
#ifndef NO_FCNTL
|
||||
#include <sys/fcntl.h>
|
||||
#ifdef __HAIKU__
|
||||
#include <fcntl.h>
|
||||
#else
|
||||
#include <sys/fcntl.h>
|
||||
#endif
|
||||
#else
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
|
|
@ -41,7 +41,11 @@
|
|||
#include <netdb.h>
|
||||
#include <sys/types.h>
|
||||
#ifndef NO_FCNTL
|
||||
#include <sys/fcntl.h>
|
||||
#ifdef __HAIKU__
|
||||
#include <fcntl.h>
|
||||
#else
|
||||
#include <sys/fcntl.h>
|
||||
#endif
|
||||
#else
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -1007,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];
|
||||
}
|
||||
}
|
||||
|
@ -1556,9 +1544,9 @@ bool Main::iteration() {
|
|||
OS::get_singleton()->delay_usec( OS::get_singleton()->get_frame_delay()*1000 );
|
||||
}
|
||||
|
||||
int taret_fps = OS::get_singleton()->get_target_fps();
|
||||
if (taret_fps>0) {
|
||||
uint64_t time_step = 1000000L/taret_fps;
|
||||
int target_fps = OS::get_singleton()->get_target_fps();
|
||||
if (target_fps>0) {
|
||||
uint64_t time_step = 1000000L/target_fps;
|
||||
target_ticks += time_step;
|
||||
uint64_t current_ticks = OS::get_singleton()->get_ticks_usec();
|
||||
if (current_ticks<target_ticks) OS::get_singleton()->delay_usec(target_ticks-current_ticks);
|
||||
|
|
|
@ -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: {
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -220,7 +220,9 @@ void GridMapEditor::_menu_option(int p_option) {
|
|||
|
||||
|
||||
} break;
|
||||
|
||||
case MENU_OPTION_GRIDMAP_SETTINGS: {
|
||||
settings_dialog->popup_centered(settings_vbc->get_combined_minimum_size() + Size2(50, 50));
|
||||
} break;
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -304,7 +306,7 @@ bool GridMapEditor::do_input_action(Camera* p_camera,const Point2& p_point,bool
|
|||
p.d=edit_floor[edit_axis]*node->get_cell_size();
|
||||
|
||||
Vector3 inters;
|
||||
if (!p.intersects_segment(from,from+normal*500,&inters))
|
||||
if (!p.intersects_segment(from, from + normal * settings_pick_distance->get_val(), &inters))
|
||||
return false;
|
||||
|
||||
|
||||
|
@ -1249,6 +1251,24 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) {
|
|||
//options->get_popup()->add_separator();
|
||||
//options->get_popup()->add_item("Configure",MENU_OPTION_CONFIGURE);
|
||||
|
||||
options->get_popup()->add_separator();
|
||||
options->get_popup()->add_item("Settings", MENU_OPTION_GRIDMAP_SETTINGS);
|
||||
|
||||
settings_dialog = memnew(ConfirmationDialog);
|
||||
settings_dialog->set_title("GridMap Settings");
|
||||
add_child(settings_dialog);
|
||||
settings_vbc = memnew(VBoxContainer);
|
||||
settings_vbc->set_custom_minimum_size(Size2(200, 0));
|
||||
settings_dialog->add_child(settings_vbc);
|
||||
settings_dialog->set_child_rect(settings_vbc);
|
||||
|
||||
settings_pick_distance = memnew(SpinBox);
|
||||
settings_pick_distance->set_max(10000.0f);
|
||||
settings_pick_distance->set_min(500.0f);
|
||||
settings_pick_distance->set_step(1.0f);
|
||||
settings_pick_distance->set_val(EDITOR_DEF("gridmap_editor/pick_distance", 5000.0));
|
||||
settings_vbc->add_margin_child("Pick Distance:", settings_pick_distance);
|
||||
|
||||
clip_mode=CLIP_DISABLED;
|
||||
options->get_popup()->connect("item_pressed", this,"_menu_option");
|
||||
|
||||
|
|
|
@ -78,6 +78,9 @@ class GridMapEditor : public VBoxContainer {
|
|||
ToolButton *mode_thumbnail;
|
||||
ToolButton *mode_list;
|
||||
HBoxContainer *spatial_editor_hb;
|
||||
ConfirmationDialog *settings_dialog;
|
||||
VBoxContainer *settings_vbc;
|
||||
SpinBox *settings_pick_distance;
|
||||
|
||||
struct SetItem {
|
||||
|
||||
|
@ -165,8 +168,8 @@ class GridMapEditor : public VBoxContainer {
|
|||
MENU_OPTION_SELECTION_MAKE_AREA,
|
||||
MENU_OPTION_SELECTION_MAKE_EXTERIOR_CONNECTOR,
|
||||
MENU_OPTION_SELECTION_CLEAR,
|
||||
MENU_OPTION_REMOVE_AREA
|
||||
|
||||
MENU_OPTION_REMOVE_AREA,
|
||||
MENU_OPTION_GRIDMAP_SETTINGS
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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'])
|
||||
|
||||
|
|
|
@ -47,8 +47,10 @@ public class PaymentsManager {
|
|||
}
|
||||
|
||||
public PaymentsManager initService(){
|
||||
Intent intent = new Intent("com.android.vending.billing.InAppBillingService.BIND");
|
||||
intent.setPackage("com.android.vending");
|
||||
activity.bindService(
|
||||
new Intent("com.android.vending.billing.InAppBillingService.BIND"),
|
||||
intent,
|
||||
mServiceConn,
|
||||
Context.BIND_AUTO_CREATE);
|
||||
return this;
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
Import('env')
|
||||
|
||||
common_haiku = [
|
||||
'os_haiku.cpp',
|
||||
'context_gl_haiku.cpp',
|
||||
'haiku_application.cpp',
|
||||
'haiku_direct_window.cpp',
|
||||
'haiku_gl_view.cpp',
|
||||
'key_mapping_haiku.cpp',
|
||||
'audio_driver_media_kit.cpp'
|
||||
]
|
||||
|
||||
env.Program(
|
||||
'#bin/godot',
|
||||
['godot_haiku.cpp'] + common_haiku
|
||||
)
|
|
@ -0,0 +1,143 @@
|
|||
/*************************************************************************/
|
||||
/* audio_driver_media_kit.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
#include "audio_driver_media_kit.h"
|
||||
|
||||
#ifdef MEDIA_KIT_ENABLED
|
||||
|
||||
#include "globals.h"
|
||||
|
||||
int32_t* AudioDriverMediaKit::samples_in = NULL;
|
||||
|
||||
Error AudioDriverMediaKit::init() {
|
||||
active = false;
|
||||
|
||||
mix_rate = 44100;
|
||||
output_format = OUTPUT_STEREO;
|
||||
channels = 2;
|
||||
|
||||
int latency = GLOBAL_DEF("audio/output_latency", 25);
|
||||
buffer_size = nearest_power_of_2(latency * mix_rate / 1000);
|
||||
samples_in = memnew_arr(int32_t, buffer_size * channels);
|
||||
|
||||
media_raw_audio_format format;
|
||||
format = media_raw_audio_format::wildcard;
|
||||
format.frame_rate = mix_rate;
|
||||
format.channel_count = channels;
|
||||
format.format = media_raw_audio_format::B_AUDIO_INT;
|
||||
format.byte_order = B_MEDIA_LITTLE_ENDIAN;
|
||||
format.buffer_size = buffer_size * sizeof(int32_t) * channels;
|
||||
|
||||
player = new BSoundPlayer(
|
||||
&format,
|
||||
"godot_sound_server",
|
||||
AudioDriverMediaKit::PlayBuffer,
|
||||
NULL,
|
||||
this
|
||||
);
|
||||
|
||||
if (player->InitCheck() != B_OK) {
|
||||
fprintf(stderr, "MediaKit ERR: can not create a BSoundPlayer instance\n");
|
||||
ERR_FAIL_COND_V(player == NULL, ERR_CANT_OPEN);
|
||||
}
|
||||
|
||||
mutex = Mutex::create();
|
||||
player->Start();
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
void AudioDriverMediaKit::PlayBuffer(void* cookie, void* buffer, size_t size, const media_raw_audio_format& format) {
|
||||
AudioDriverMediaKit* ad = (AudioDriverMediaKit*) cookie;
|
||||
int32_t* buf = (int32_t*) buffer;
|
||||
|
||||
if (!ad->active) {
|
||||
for (unsigned int i = 0; i < ad->buffer_size * ad->channels; i++) {
|
||||
AudioDriverMediaKit::samples_in[i] = 0;
|
||||
}
|
||||
} else {
|
||||
ad->lock();
|
||||
ad->audio_server_process(ad->buffer_size, AudioDriverMediaKit::samples_in);
|
||||
ad->unlock();
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < ad->buffer_size * ad->channels; i++) {
|
||||
buf[i] = AudioDriverMediaKit::samples_in[i];
|
||||
}
|
||||
}
|
||||
|
||||
void AudioDriverMediaKit::start() {
|
||||
active = true;
|
||||
}
|
||||
|
||||
int AudioDriverMediaKit::get_mix_rate() const {
|
||||
return mix_rate;
|
||||
}
|
||||
|
||||
AudioDriverSW::OutputFormat AudioDriverMediaKit::get_output_format() const {
|
||||
return output_format;
|
||||
}
|
||||
|
||||
void AudioDriverMediaKit::lock() {
|
||||
if (!mutex)
|
||||
return;
|
||||
|
||||
mutex->lock();
|
||||
}
|
||||
|
||||
void AudioDriverMediaKit::unlock() {
|
||||
if (!mutex)
|
||||
return;
|
||||
|
||||
mutex->unlock();
|
||||
}
|
||||
|
||||
void AudioDriverMediaKit::finish() {
|
||||
if (player)
|
||||
delete player;
|
||||
|
||||
if (samples_in) {
|
||||
memdelete_arr(samples_in);
|
||||
};
|
||||
|
||||
if (mutex) {
|
||||
memdelete(mutex);
|
||||
mutex = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
AudioDriverMediaKit::AudioDriverMediaKit() {
|
||||
mutex = NULL;
|
||||
player = NULL;
|
||||
}
|
||||
|
||||
AudioDriverMediaKit::~AudioDriverMediaKit() {
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,72 @@
|
|||
/*************************************************************************/
|
||||
/* audio_driver_media_kit.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
#include "servers/audio/audio_server_sw.h"
|
||||
|
||||
#ifdef MEDIA_KIT_ENABLED
|
||||
|
||||
#include "core/os/thread.h"
|
||||
#include "core/os/mutex.h"
|
||||
|
||||
#include <kernel/image.h> // needed for image_id
|
||||
#include <SoundPlayer.h>
|
||||
|
||||
class AudioDriverMediaKit : public AudioDriverSW {
|
||||
Mutex* mutex;
|
||||
|
||||
BSoundPlayer* player;
|
||||
static int32_t* samples_in;
|
||||
|
||||
static void PlayBuffer(void* cookie, void* buffer, size_t size, const media_raw_audio_format& format);
|
||||
|
||||
unsigned int mix_rate;
|
||||
OutputFormat output_format;
|
||||
unsigned int buffer_size;
|
||||
int channels;
|
||||
|
||||
bool active;
|
||||
|
||||
public:
|
||||
|
||||
const char* get_name() const {
|
||||
return "MediaKit";
|
||||
};
|
||||
|
||||
virtual Error init();
|
||||
virtual void start();
|
||||
virtual int get_mix_rate() const;
|
||||
virtual OutputFormat get_output_format() const;
|
||||
virtual void lock();
|
||||
virtual void unlock();
|
||||
virtual void finish();
|
||||
|
||||
AudioDriverMediaKit();
|
||||
~AudioDriverMediaKit();
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,43 @@
|
|||
#include "context_gl_haiku.h"
|
||||
|
||||
#if defined(OPENGL_ENABLED) || defined(LEGACYGL_ENABLED)
|
||||
|
||||
ContextGL_Haiku::ContextGL_Haiku(HaikuDirectWindow* p_window) {
|
||||
window = p_window;
|
||||
|
||||
uint32 type = BGL_RGB | BGL_DOUBLE | BGL_DEPTH;
|
||||
view = new HaikuGLView(window->Bounds(), type);
|
||||
}
|
||||
|
||||
ContextGL_Haiku::~ContextGL_Haiku() {
|
||||
delete view;
|
||||
}
|
||||
|
||||
Error ContextGL_Haiku::initialize() {
|
||||
window->AddChild(view);
|
||||
window->SetHaikuGLView(view);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
void ContextGL_Haiku::release_current() {
|
||||
view->UnlockGL();
|
||||
}
|
||||
|
||||
void ContextGL_Haiku::make_current() {
|
||||
view->LockGL();
|
||||
}
|
||||
|
||||
void ContextGL_Haiku::swap_buffers() {
|
||||
view->SwapBuffers();
|
||||
}
|
||||
|
||||
int ContextGL_Haiku::get_window_width() {
|
||||
return window->Bounds().IntegerWidth();
|
||||
}
|
||||
|
||||
int ContextGL_Haiku::get_window_height() {
|
||||
return window->Bounds().IntegerHeight();
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,29 @@
|
|||
#ifndef CONTEXT_GL_HAIKU_H
|
||||
#define CONTEXT_GL_HAIKU_H
|
||||
|
||||
#if defined(OPENGL_ENABLED) || defined(LEGACYGL_ENABLED)
|
||||
|
||||
#include "drivers/gl_context/context_gl.h"
|
||||
|
||||
#include "haiku_direct_window.h"
|
||||
#include "haiku_gl_view.h"
|
||||
|
||||
class ContextGL_Haiku : public ContextGL {
|
||||
private:
|
||||
HaikuGLView* view;
|
||||
HaikuDirectWindow* window;
|
||||
|
||||
public:
|
||||
ContextGL_Haiku(HaikuDirectWindow* p_window);
|
||||
~ContextGL_Haiku();
|
||||
|
||||
virtual Error initialize();
|
||||
virtual void release_current();
|
||||
virtual void make_current();
|
||||
virtual void swap_buffers();
|
||||
virtual int get_window_width();
|
||||
virtual int get_window_height();
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,61 @@
|
|||
import os
|
||||
import sys
|
||||
|
||||
def is_active():
|
||||
return True
|
||||
|
||||
def get_name():
|
||||
return "Haiku"
|
||||
|
||||
def can_build():
|
||||
if (os.name != "posix"):
|
||||
return False
|
||||
|
||||
if (sys.platform == "darwin"):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def get_opts():
|
||||
return [
|
||||
('debug_release', 'Add debug symbols to release version','no')
|
||||
]
|
||||
|
||||
def get_flags():
|
||||
return [
|
||||
('builtin_zlib', 'no')
|
||||
]
|
||||
|
||||
def configure(env):
|
||||
is64 = sys.maxsize > 2**32
|
||||
|
||||
if (env["bits"]=="default"):
|
||||
if (is64):
|
||||
env["bits"]="64"
|
||||
else:
|
||||
env["bits"]="32"
|
||||
|
||||
env.Append(CPPPATH = ['#platform/haiku'])
|
||||
|
||||
env["CC"] = "gcc"
|
||||
env["CXX"] = "g++"
|
||||
|
||||
if (env["target"]=="release"):
|
||||
if (env["debug_release"]=="yes"):
|
||||
env.Append(CCFLAGS=['-g2'])
|
||||
else:
|
||||
env.Append(CCFLAGS=['-O3','-ffast-math'])
|
||||
elif (env["target"]=="release_debug"):
|
||||
env.Append(CCFLAGS=['-O2','-ffast-math','-DDEBUG_ENABLED'])
|
||||
elif (env["target"]=="debug"):
|
||||
env.Append(CCFLAGS=['-g2', '-Wall','-DDEBUG_ENABLED','-DDEBUG_MEMORY_ENABLED'])
|
||||
|
||||
#env.Append(CCFLAGS=['-DFREETYPE_ENABLED'])
|
||||
env.Append(CPPFLAGS = ['-DGLEW_ENABLED', '-DOPENGL_ENABLED', '-DMEDIA_KIT_ENABLED'])
|
||||
env.Append(CPPFLAGS = ['-DUNIX_ENABLED', '-DGLES2_ENABLED', '-DGLES_OVER_GL'])
|
||||
env.Append(LIBS = ['be', 'game', 'media', 'network', 'bnetapi', 'z', 'GL', 'GLEW'])
|
||||
|
||||
import methods
|
||||
env.Append(BUILDERS = {'GLSL120' : env.Builder(action = methods.build_legacygl_headers, suffix = 'glsl.h',src_suffix = '.glsl')})
|
||||
env.Append(BUILDERS = {'GLSL' : env.Builder(action = methods.build_glsl_headers, suffix = 'glsl.h',src_suffix = '.glsl')})
|
||||
env.Append(BUILDERS = {'GLSL120GLES' : env.Builder(action = methods.build_gles2_headers, suffix = 'glsl.h',src_suffix = '.glsl')})
|
|
@ -0,0 +1,19 @@
|
|||
#include "main/main.h"
|
||||
#include "os_haiku.h"
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
OS_Haiku os;
|
||||
|
||||
Error error = Main::setup(argv[0], argc-1, &argv[1]);
|
||||
if (error != OK) {
|
||||
return 255;
|
||||
}
|
||||
|
||||
if (Main::start()) {
|
||||
os.run();
|
||||
}
|
||||
|
||||
Main::cleanup();
|
||||
|
||||
return os.get_exit_code();
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#include "haiku_application.h"
|
||||
|
||||
HaikuApplication::HaikuApplication()
|
||||
: BApplication("application/x-vnd.Godot")
|
||||
{
|
||||
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
#ifndef HAIKU_APPLICATION_H
|
||||
#define HAIKU_APPLICATION_H
|
||||
|
||||
#include <kernel/image.h> // needed for image_id
|
||||
#include <Application.h>
|
||||
|
||||
class HaikuApplication : public BApplication
|
||||
{
|
||||
public:
|
||||
HaikuApplication();
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,344 @@
|
|||
#include <UnicodeChar.h>
|
||||
|
||||
#include "main/main.h"
|
||||
#include "os/keyboard.h"
|
||||
#include "haiku_direct_window.h"
|
||||
#include "key_mapping_haiku.h"
|
||||
|
||||
HaikuDirectWindow::HaikuDirectWindow(BRect p_frame)
|
||||
: BDirectWindow(p_frame, "Godot", B_TITLED_WINDOW, B_QUIT_ON_WINDOW_CLOSE)
|
||||
{
|
||||
last_mouse_pos_valid = false;
|
||||
last_buttons_state = 0;
|
||||
last_button_mask = 0;
|
||||
last_key_modifier_state = 0;
|
||||
}
|
||||
|
||||
|
||||
HaikuDirectWindow::~HaikuDirectWindow() {
|
||||
if (update_runner) {
|
||||
delete update_runner;
|
||||
}
|
||||
}
|
||||
|
||||
void HaikuDirectWindow::SetHaikuGLView(HaikuGLView* p_view) {
|
||||
view = p_view;
|
||||
}
|
||||
|
||||
void HaikuDirectWindow::StartMessageRunner() {
|
||||
update_runner = new BMessageRunner(BMessenger(this),
|
||||
new BMessage(REDRAW_MSG), 1000000/30 /* 30 fps */);
|
||||
}
|
||||
|
||||
void HaikuDirectWindow::StopMessageRunner() {
|
||||
delete update_runner;
|
||||
}
|
||||
|
||||
void HaikuDirectWindow::SetInput(InputDefault* p_input) {
|
||||
input = p_input;
|
||||
}
|
||||
|
||||
void HaikuDirectWindow::SetMainLoop(MainLoop* p_main_loop) {
|
||||
main_loop = p_main_loop;
|
||||
}
|
||||
|
||||
bool HaikuDirectWindow::QuitRequested() {
|
||||
main_loop->notification(MainLoop::NOTIFICATION_WM_QUIT_REQUEST);
|
||||
return false;
|
||||
}
|
||||
|
||||
void HaikuDirectWindow::DirectConnected(direct_buffer_info* info) {
|
||||
view->DirectConnected(info);
|
||||
view->EnableDirectMode(true);
|
||||
}
|
||||
|
||||
void HaikuDirectWindow::MessageReceived(BMessage* message) {
|
||||
switch (message->what) {
|
||||
case REDRAW_MSG:
|
||||
if (Main::iteration() == true) {
|
||||
view->EnableDirectMode(false);
|
||||
Quit();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
BDirectWindow::MessageReceived(message);
|
||||
}
|
||||
}
|
||||
|
||||
void HaikuDirectWindow::DispatchMessage(BMessage* message, BHandler* handler) {
|
||||
switch (message->what) {
|
||||
case B_MOUSE_DOWN:
|
||||
case B_MOUSE_UP:
|
||||
HandleMouseButton(message);
|
||||
break;
|
||||
|
||||
case B_MOUSE_MOVED:
|
||||
HandleMouseMoved(message);
|
||||
break;
|
||||
|
||||
case B_MOUSE_WHEEL_CHANGED:
|
||||
HandleMouseWheelChanged(message);
|
||||
break;
|
||||
|
||||
case B_KEY_DOWN:
|
||||
case B_KEY_UP:
|
||||
HandleKeyboardEvent(message);
|
||||
break;
|
||||
|
||||
case B_MODIFIERS_CHANGED:
|
||||
HandleKeyboardModifierEvent(message);
|
||||
break;
|
||||
|
||||
case B_WINDOW_RESIZED:
|
||||
HandleWindowResized(message);
|
||||
break;
|
||||
|
||||
case LOCKGL_MSG:
|
||||
view->LockGL();
|
||||
break;
|
||||
|
||||
case UNLOCKGL_MSG:
|
||||
view->UnlockGL();
|
||||
break;
|
||||
|
||||
default:
|
||||
BDirectWindow::DispatchMessage(message, handler);
|
||||
}
|
||||
}
|
||||
|
||||
void HaikuDirectWindow::HandleMouseButton(BMessage* message) {
|
||||
BPoint where;
|
||||
if (message->FindPoint("where", &where) != B_OK) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 modifiers = message->FindInt32("modifiers");
|
||||
uint32 buttons = message->FindInt32("buttons");
|
||||
uint32 button = buttons ^ last_buttons_state;
|
||||
last_buttons_state = buttons;
|
||||
|
||||
// TODO: implement the mouse_mode checks
|
||||
//if (mouse_mode == MOUSE_MODE_CAPTURED) {
|
||||
// event.xbutton.x=last_mouse_pos.x;
|
||||
// event.xbutton.y=last_mouse_pos.y;
|
||||
//}
|
||||
|
||||
InputEvent mouse_event;
|
||||
mouse_event.ID = ++event_id;
|
||||
mouse_event.type = InputEvent::MOUSE_BUTTON;
|
||||
mouse_event.device = 0;
|
||||
|
||||
mouse_event.mouse_button.mod = GetKeyModifierState(modifiers);
|
||||
mouse_event.mouse_button.button_mask = GetMouseButtonState(buttons);
|
||||
mouse_event.mouse_button.x = where.x;
|
||||
mouse_event.mouse_button.y = where.y;
|
||||
mouse_event.mouse_button.global_x = where.x;
|
||||
mouse_event.mouse_button.global_y = where.y;
|
||||
|
||||
switch (button) {
|
||||
default:
|
||||
case B_PRIMARY_MOUSE_BUTTON:
|
||||
mouse_event.mouse_button.button_index = 1;
|
||||
break;
|
||||
|
||||
case B_SECONDARY_MOUSE_BUTTON:
|
||||
mouse_event.mouse_button.button_index = 2;
|
||||
break;
|
||||
|
||||
case B_TERTIARY_MOUSE_BUTTON:
|
||||
mouse_event.mouse_button.button_index = 3;
|
||||
break;
|
||||
}
|
||||
|
||||
mouse_event.mouse_button.pressed = (message->what == B_MOUSE_DOWN);
|
||||
|
||||
if (message->what == B_MOUSE_DOWN && mouse_event.mouse_button.button_index == 1) {
|
||||
int32 clicks = message->FindInt32("clicks");
|
||||
|
||||
if (clicks > 1) {
|
||||
mouse_event.mouse_button.doubleclick=true;
|
||||
}
|
||||
}
|
||||
|
||||
input->parse_input_event(mouse_event);
|
||||
}
|
||||
|
||||
void HaikuDirectWindow::HandleMouseMoved(BMessage* message) {
|
||||
BPoint where;
|
||||
if (message->FindPoint("where", &where) != B_OK) {
|
||||
return;
|
||||
}
|
||||
|
||||
Point2i pos(where.x, where.y);
|
||||
uint32 modifiers = message->FindInt32("modifiers");
|
||||
uint32 buttons = message->FindInt32("buttons");
|
||||
|
||||
if (!last_mouse_pos_valid) {
|
||||
last_mouse_position = pos;
|
||||
last_mouse_pos_valid = true;
|
||||
}
|
||||
|
||||
Point2i rel = pos - last_mouse_position;
|
||||
|
||||
InputEvent motion_event;
|
||||
motion_event.ID = ++event_id;
|
||||
motion_event.type = InputEvent::MOUSE_MOTION;
|
||||
motion_event.device = 0;
|
||||
|
||||
motion_event.mouse_motion.mod = GetKeyModifierState(modifiers);
|
||||
motion_event.mouse_motion.button_mask = GetMouseButtonState(buttons);
|
||||
motion_event.mouse_motion.x = pos.x;
|
||||
motion_event.mouse_motion.y = pos.y;
|
||||
input->set_mouse_pos(pos);
|
||||
motion_event.mouse_motion.global_x = pos.x;
|
||||
motion_event.mouse_motion.global_y = pos.y;
|
||||
motion_event.mouse_motion.speed_x = input->get_mouse_speed().x;
|
||||
motion_event.mouse_motion.speed_y = input->get_mouse_speed().y;
|
||||
|
||||
motion_event.mouse_motion.relative_x = rel.x;
|
||||
motion_event.mouse_motion.relative_y = rel.y;
|
||||
|
||||
last_mouse_position = pos;
|
||||
|
||||
input->parse_input_event(motion_event);
|
||||
}
|
||||
|
||||
void HaikuDirectWindow::HandleMouseWheelChanged(BMessage* message) {
|
||||
float wheel_delta_y = 0;
|
||||
if (message->FindFloat("be:wheel_delta_y", &wheel_delta_y) != B_OK) {
|
||||
return;
|
||||
}
|
||||
|
||||
InputEvent mouse_event;
|
||||
mouse_event.ID = ++event_id;
|
||||
mouse_event.type = InputEvent::MOUSE_BUTTON;
|
||||
mouse_event.device = 0;
|
||||
|
||||
mouse_event.mouse_button.button_index = wheel_delta_y < 0 ? 4 : 5;
|
||||
mouse_event.mouse_button.mod = GetKeyModifierState(last_key_modifier_state);
|
||||
mouse_event.mouse_button.button_mask = last_button_mask;
|
||||
mouse_event.mouse_button.x = last_mouse_position.x;
|
||||
mouse_event.mouse_button.y = last_mouse_position.y;
|
||||
mouse_event.mouse_button.global_x = last_mouse_position.x;
|
||||
mouse_event.mouse_button.global_y = last_mouse_position.y;
|
||||
|
||||
mouse_event.mouse_button.pressed = true;
|
||||
input->parse_input_event(mouse_event);
|
||||
|
||||
mouse_event.ID = ++event_id;
|
||||
mouse_event.mouse_button.pressed = false;
|
||||
input->parse_input_event(mouse_event);
|
||||
}
|
||||
|
||||
void HaikuDirectWindow::HandleKeyboardEvent(BMessage* message) {
|
||||
int32 raw_char = 0;
|
||||
int32 key = 0;
|
||||
int32 modifiers = 0;
|
||||
|
||||
if (message->FindInt32("raw_char", &raw_char) != B_OK) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (message->FindInt32("key", &key) != B_OK) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (message->FindInt32("modifiers", &modifiers) != B_OK) {
|
||||
return;
|
||||
}
|
||||
|
||||
InputEvent event;
|
||||
event.ID = ++event_id;
|
||||
event.type = InputEvent::KEY;
|
||||
event.device = 0;
|
||||
event.key.mod = GetKeyModifierState(modifiers);
|
||||
event.key.pressed = (message->what == B_KEY_DOWN);
|
||||
event.key.scancode = KeyMappingHaiku::get_keysym(raw_char, key);
|
||||
event.key.echo = message->HasInt32("be:key_repeat");
|
||||
event.key.unicode = 0;
|
||||
|
||||
const char* bytes = NULL;
|
||||
if (message->FindString("bytes", &bytes) == B_OK) {
|
||||
event.key.unicode = BUnicodeChar::FromUTF8(&bytes);
|
||||
}
|
||||
|
||||
//make it consistent accross platforms.
|
||||
if (event.key.scancode==KEY_BACKTAB) {
|
||||
event.key.scancode=KEY_TAB;
|
||||
event.key.mod.shift=true;
|
||||
}
|
||||
|
||||
input->parse_input_event(event);
|
||||
}
|
||||
|
||||
void HaikuDirectWindow::HandleKeyboardModifierEvent(BMessage* message) {
|
||||
int32 old_modifiers = 0;
|
||||
int32 modifiers = 0;
|
||||
|
||||
if (message->FindInt32("be:old_modifiers", &old_modifiers) != B_OK) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (message->FindInt32("modifiers", &modifiers) != B_OK) {
|
||||
return;
|
||||
}
|
||||
|
||||
int32 key = old_modifiers ^ modifiers;
|
||||
|
||||
InputEvent event;
|
||||
event.ID = ++event_id;
|
||||
event.type = InputEvent::KEY;
|
||||
event.device = 0;
|
||||
event.key.mod = GetKeyModifierState(modifiers);
|
||||
event.key.pressed = ((modifiers & key) != 0);
|
||||
event.key.scancode = KeyMappingHaiku::get_modifier_keysym(key);
|
||||
event.key.echo = false;
|
||||
event.key.unicode = 0;
|
||||
|
||||
input->parse_input_event(event);
|
||||
}
|
||||
|
||||
void HaikuDirectWindow::HandleWindowResized(BMessage* message) {
|
||||
int32 width = 0;
|
||||
int32 height = 0;
|
||||
|
||||
if ((message->FindInt32("width", &width) != B_OK) || (message->FindInt32("height", &height) != B_OK)) {
|
||||
return;
|
||||
}
|
||||
|
||||
current_video_mode->width = width;
|
||||
current_video_mode->height = height;
|
||||
}
|
||||
|
||||
inline InputModifierState HaikuDirectWindow::GetKeyModifierState(uint32 p_state) {
|
||||
last_key_modifier_state = p_state;
|
||||
InputModifierState state;
|
||||
|
||||
state.shift = (p_state & B_SHIFT_KEY) != 0;
|
||||
state.control = (p_state & B_CONTROL_KEY) != 0;
|
||||
state.alt = (p_state & B_OPTION_KEY) != 0;
|
||||
state.meta = (p_state & B_COMMAND_KEY) != 0;
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
inline int HaikuDirectWindow::GetMouseButtonState(uint32 p_state) {
|
||||
int state = 0;
|
||||
|
||||
if (p_state & B_PRIMARY_MOUSE_BUTTON) {
|
||||
state |= 1 << 0;
|
||||
}
|
||||
|
||||
if (p_state & B_SECONDARY_MOUSE_BUTTON) {
|
||||
state |= 1 << 1;
|
||||
}
|
||||
|
||||
if (p_state & B_TERTIARY_MOUSE_BUTTON) {
|
||||
state |= 1 << 2;
|
||||
}
|
||||
|
||||
last_button_mask = state;
|
||||
|
||||
return state;
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
#ifndef HAIKU_DIRECT_WINDOW_H
|
||||
#define HAIKU_DIRECT_WINDOW_H
|
||||
|
||||
#include <kernel/image.h> // needed for image_id
|
||||
#include <DirectWindow.h>
|
||||
|
||||
#include "core/os/os.h"
|
||||
#include "main/input_default.h"
|
||||
|
||||
#include "haiku_gl_view.h"
|
||||
|
||||
#define REDRAW_MSG 'rdrw'
|
||||
#define LOCKGL_MSG 'glck'
|
||||
#define UNLOCKGL_MSG 'ulck'
|
||||
|
||||
class HaikuDirectWindow : public BDirectWindow
|
||||
{
|
||||
private:
|
||||
unsigned int event_id;
|
||||
Point2i last_mouse_position;
|
||||
bool last_mouse_pos_valid;
|
||||
uint32 last_buttons_state;
|
||||
uint32 last_key_modifier_state;
|
||||
int last_button_mask;
|
||||
OS::VideoMode* current_video_mode;
|
||||
|
||||
MainLoop* main_loop;
|
||||
InputDefault* input;
|
||||
HaikuGLView* view;
|
||||
BMessageRunner* update_runner;
|
||||
|
||||
void HandleMouseButton(BMessage* message);
|
||||
void HandleMouseMoved(BMessage* message);
|
||||
void HandleMouseWheelChanged(BMessage* message);
|
||||
void HandleWindowResized(BMessage* message);
|
||||
void HandleKeyboardEvent(BMessage* message);
|
||||
void HandleKeyboardModifierEvent(BMessage* message);
|
||||
inline InputModifierState GetKeyModifierState(uint32 p_state);
|
||||
inline int GetMouseButtonState(uint32 p_state);
|
||||
|
||||
public:
|
||||
HaikuDirectWindow(BRect p_frame);
|
||||
~HaikuDirectWindow();
|
||||
|
||||
void SetHaikuGLView(HaikuGLView* p_view);
|
||||
void StartMessageRunner();
|
||||
void StopMessageRunner();
|
||||
void SetInput(InputDefault* p_input);
|
||||
void SetMainLoop(MainLoop* p_main_loop);
|
||||
inline void SetVideoMode(OS::VideoMode* video_mode) { current_video_mode = video_mode; };
|
||||
virtual bool QuitRequested();
|
||||
virtual void DirectConnected(direct_buffer_info* info);
|
||||
virtual void MessageReceived(BMessage* message);
|
||||
virtual void DispatchMessage(BMessage* message, BHandler* handler);
|
||||
|
||||
inline Point2i GetLastMousePosition() { return last_mouse_position; };
|
||||
inline int GetLastButtonMask() { return last_button_mask; };
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,18 @@
|
|||
#include "main/main.h"
|
||||
#include "haiku_gl_view.h"
|
||||
|
||||
HaikuGLView::HaikuGLView(BRect frame, uint32 type)
|
||||
: BGLView(frame, "GodotGLView", B_FOLLOW_ALL_SIDES, 0, type)
|
||||
{
|
||||
}
|
||||
|
||||
void HaikuGLView::AttachedToWindow(void) {
|
||||
LockGL();
|
||||
BGLView::AttachedToWindow();
|
||||
UnlockGL();
|
||||
MakeFocus();
|
||||
}
|
||||
|
||||
void HaikuGLView::Draw(BRect updateRect) {
|
||||
Main::force_redraw();
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
#ifndef HAIKU_GL_VIEW_H
|
||||
#define HAIKU_GL_VIEW_H
|
||||
|
||||
#include <kernel/image.h> // needed for image_id
|
||||
#include <GLView.h>
|
||||
|
||||
class HaikuGLView : public BGLView
|
||||
{
|
||||
public:
|
||||
HaikuGLView(BRect frame, uint32 type);
|
||||
virtual void AttachedToWindow(void);
|
||||
virtual void Draw(BRect updateRect);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,193 @@
|
|||
#include <InterfaceDefs.h>
|
||||
|
||||
#include "key_mapping_haiku.h"
|
||||
#include "os/keyboard.h"
|
||||
|
||||
struct _HaikuTranslatePair {
|
||||
unsigned int keysym;
|
||||
int32 keycode;
|
||||
};
|
||||
|
||||
static _HaikuTranslatePair _mod_to_keycode[] = {
|
||||
{ KEY_SHIFT, B_SHIFT_KEY },
|
||||
{ KEY_ALT, B_COMMAND_KEY },
|
||||
{ KEY_CONTROL, B_CONTROL_KEY },
|
||||
{ KEY_CAPSLOCK, B_CAPS_LOCK },
|
||||
{ KEY_SCROLLLOCK, B_SCROLL_LOCK },
|
||||
{ KEY_NUMLOCK, B_NUM_LOCK },
|
||||
{ KEY_SUPER_L, B_OPTION_KEY },
|
||||
{ KEY_MENU, B_MENU_KEY },
|
||||
{ KEY_SHIFT, B_LEFT_SHIFT_KEY },
|
||||
{ KEY_SHIFT, B_RIGHT_SHIFT_KEY },
|
||||
{ KEY_ALT, B_LEFT_COMMAND_KEY },
|
||||
{ KEY_ALT, B_RIGHT_COMMAND_KEY },
|
||||
{ KEY_CONTROL, B_LEFT_CONTROL_KEY },
|
||||
{ KEY_CONTROL, B_RIGHT_CONTROL_KEY },
|
||||
{ KEY_SUPER_L, B_LEFT_OPTION_KEY },
|
||||
{ KEY_SUPER_R, B_RIGHT_OPTION_KEY },
|
||||
{ KEY_UNKNOWN, 0 }
|
||||
};
|
||||
|
||||
static _HaikuTranslatePair _fn_to_keycode[] = {
|
||||
{ KEY_F1, B_F1_KEY },
|
||||
{ KEY_F2, B_F2_KEY },
|
||||
{ KEY_F3, B_F3_KEY },
|
||||
{ KEY_F4, B_F4_KEY },
|
||||
{ KEY_F5, B_F5_KEY },
|
||||
{ KEY_F6, B_F6_KEY },
|
||||
{ KEY_F7, B_F7_KEY },
|
||||
{ KEY_F8, B_F8_KEY },
|
||||
{ KEY_F9, B_F9_KEY },
|
||||
{ KEY_F10, B_F10_KEY },
|
||||
{ KEY_F11, B_F11_KEY },
|
||||
{ KEY_F12, B_F12_KEY },
|
||||
//{ KEY_F13, ? },
|
||||
//{ KEY_F14, ? },
|
||||
//{ KEY_F15, ? },
|
||||
//{ KEY_F16, ? },
|
||||
{ KEY_PRINT, B_PRINT_KEY },
|
||||
{ KEY_SCROLLLOCK, B_SCROLL_KEY },
|
||||
{ KEY_PAUSE, B_PAUSE_KEY },
|
||||
{ KEY_UNKNOWN, 0 }
|
||||
};
|
||||
|
||||
static _HaikuTranslatePair _hb_to_keycode[] = {
|
||||
{ KEY_BACKSPACE, B_BACKSPACE },
|
||||
{ KEY_TAB, B_TAB },
|
||||
{ KEY_RETURN, B_RETURN },
|
||||
{ KEY_CAPSLOCK, B_CAPS_LOCK },
|
||||
{ KEY_ESCAPE, B_ESCAPE },
|
||||
{ KEY_SPACE, B_SPACE },
|
||||
{ KEY_PAGEUP, B_PAGE_UP },
|
||||
{ KEY_PAGEDOWN, B_PAGE_DOWN },
|
||||
{ KEY_END, B_END },
|
||||
{ KEY_HOME, B_HOME },
|
||||
{ KEY_LEFT, B_LEFT_ARROW },
|
||||
{ KEY_UP, B_UP_ARROW },
|
||||
{ KEY_RIGHT, B_RIGHT_ARROW },
|
||||
{ KEY_DOWN, B_DOWN_ARROW },
|
||||
{ KEY_PRINT, B_PRINT_KEY },
|
||||
{ KEY_INSERT, B_INSERT },
|
||||
{ KEY_DELETE, B_DELETE },
|
||||
// { KEY_HELP, ??? },
|
||||
|
||||
{ KEY_0, (0x30) },
|
||||
{ KEY_1, (0x31) },
|
||||
{ KEY_2, (0x32) },
|
||||
{ KEY_3, (0x33) },
|
||||
{ KEY_4, (0x34) },
|
||||
{ KEY_5, (0x35) },
|
||||
{ KEY_6, (0x36) },
|
||||
{ KEY_7, (0x37) },
|
||||
{ KEY_8, (0x38) },
|
||||
{ KEY_9, (0x39) },
|
||||
{ KEY_A, (0x61) },
|
||||
{ KEY_B, (0x62) },
|
||||
{ KEY_C, (0x63) },
|
||||
{ KEY_D, (0x64) },
|
||||
{ KEY_E, (0x65) },
|
||||
{ KEY_F, (0x66) },
|
||||
{ KEY_G, (0x67) },
|
||||
{ KEY_H, (0x68) },
|
||||
{ KEY_I, (0x69) },
|
||||
{ KEY_J, (0x6A) },
|
||||
{ KEY_K, (0x6B) },
|
||||
{ KEY_L, (0x6C) },
|
||||
{ KEY_M, (0x6D) },
|
||||
{ KEY_N, (0x6E) },
|
||||
{ KEY_O, (0x6F) },
|
||||
{ KEY_P, (0x70) },
|
||||
{ KEY_Q, (0x71) },
|
||||
{ KEY_R, (0x72) },
|
||||
{ KEY_S, (0x73) },
|
||||
{ KEY_T, (0x74) },
|
||||
{ KEY_U, (0x75) },
|
||||
{ KEY_V, (0x76) },
|
||||
{ KEY_W, (0x77) },
|
||||
{ KEY_X, (0x78) },
|
||||
{ KEY_Y, (0x79) },
|
||||
{ KEY_Z, (0x7A) },
|
||||
|
||||
/*
|
||||
{ KEY_PLAY, VK_PLAY},// (0xFA)
|
||||
{ KEY_STANDBY,VK_SLEEP },//(0x5F)
|
||||
{ KEY_BACK,VK_BROWSER_BACK},// (0xA6)
|
||||
{ KEY_FORWARD,VK_BROWSER_FORWARD},// (0xA7)
|
||||
{ KEY_REFRESH,VK_BROWSER_REFRESH},// (0xA8)
|
||||
{ KEY_STOP,VK_BROWSER_STOP},// (0xA9)
|
||||
{ KEY_SEARCH,VK_BROWSER_SEARCH},// (0xAA)
|
||||
{ KEY_FAVORITES, VK_BROWSER_FAVORITES},// (0xAB)
|
||||
{ KEY_HOMEPAGE,VK_BROWSER_HOME},// (0xAC)
|
||||
{ KEY_VOLUMEMUTE,VK_VOLUME_MUTE},// (0xAD)
|
||||
{ KEY_VOLUMEDOWN,VK_VOLUME_DOWN},// (0xAE)
|
||||
{ KEY_VOLUMEUP,VK_VOLUME_UP},// (0xAF)
|
||||
{ KEY_MEDIANEXT,VK_MEDIA_NEXT_TRACK},// (0xB0)
|
||||
{ KEY_MEDIAPREVIOUS,VK_MEDIA_PREV_TRACK},// (0xB1)
|
||||
{ KEY_MEDIASTOP,VK_MEDIA_STOP},// (0xB2)
|
||||
{ KEY_LAUNCHMAIL, VK_LAUNCH_MAIL},// (0xB4)
|
||||
{ KEY_LAUNCHMEDIA,VK_LAUNCH_MEDIA_SELECT},// (0xB5)
|
||||
{ KEY_LAUNCH0,VK_LAUNCH_APP1},// (0xB6)
|
||||
{ KEY_LAUNCH1,VK_LAUNCH_APP2},// (0xB7)
|
||||
*/
|
||||
|
||||
{ KEY_SEMICOLON, 0x3B },
|
||||
{ KEY_EQUAL, 0x3D },
|
||||
{ KEY_COLON, 0x2C },
|
||||
{ KEY_MINUS, 0x2D },
|
||||
{ KEY_PERIOD, 0x2E },
|
||||
{ KEY_SLASH, 0x2F },
|
||||
{ KEY_KP_MULTIPLY, 0x2A },
|
||||
{ KEY_KP_ADD, 0x2B },
|
||||
|
||||
{ KEY_QUOTELEFT, 0x60 },
|
||||
{ KEY_BRACKETLEFT, 0x5B },
|
||||
{ KEY_BACKSLASH, 0x5C },
|
||||
{ KEY_BRACKETRIGHT, 0x5D },
|
||||
{ KEY_APOSTROPHE, 0x27 },
|
||||
|
||||
{ KEY_UNKNOWN, 0 }
|
||||
};
|
||||
|
||||
unsigned int KeyMappingHaiku::get_keysym(int32 raw_char, int32 key) {
|
||||
if (raw_char == B_INSERT && key == 0x64) { return KEY_KP_0; }
|
||||
if (raw_char == B_END && key == 0x58) { return KEY_KP_1; }
|
||||
if (raw_char == B_DOWN_ARROW && key == 0x59) { return KEY_KP_2; }
|
||||
if (raw_char == B_PAGE_DOWN && key == 0x5A) { return KEY_KP_3; }
|
||||
if (raw_char == B_LEFT_ARROW && key == 0x48) { return KEY_KP_4; }
|
||||
if (raw_char == 0x35 && key == 0x49) { return KEY_KP_5; }
|
||||
if (raw_char == B_RIGHT_ARROW && key == 0x4A) { return KEY_KP_6; }
|
||||
if (raw_char == B_HOME && key == 0x37) { return KEY_KP_7; }
|
||||
if (raw_char == B_UP_ARROW && key == 0x38) { return KEY_KP_8; }
|
||||
if (raw_char == B_PAGE_UP && key == 0x39) { return KEY_KP_9; }
|
||||
if (raw_char == 0x2F && key == 0x23) { return KEY_KP_DIVIDE; }
|
||||
if (raw_char == 0x2D && key == 0x25) { return KEY_KP_SUBSTRACT; }
|
||||
if (raw_char == B_DELETE && key == 0x65) { return KEY_KP_PERIOD; }
|
||||
|
||||
if (raw_char == 0x10) {
|
||||
for(int i = 0; _fn_to_keycode[i].keysym != KEY_UNKNOWN; i++) {
|
||||
if (_fn_to_keycode[i].keycode == key) {
|
||||
return _fn_to_keycode[i].keysym;
|
||||
}
|
||||
}
|
||||
|
||||
return KEY_UNKNOWN;
|
||||
}
|
||||
|
||||
for(int i = 0; _hb_to_keycode[i].keysym != KEY_UNKNOWN; i++) {
|
||||
if (_hb_to_keycode[i].keycode == raw_char) {
|
||||
return _hb_to_keycode[i].keysym;
|
||||
}
|
||||
}
|
||||
|
||||
return KEY_UNKNOWN;
|
||||
}
|
||||
|
||||
unsigned int KeyMappingHaiku::get_modifier_keysym(int32 key) {
|
||||
for(int i = 0; _mod_to_keycode[i].keysym != KEY_UNKNOWN; i++) {
|
||||
if ((_mod_to_keycode[i].keycode & key) != 0) {
|
||||
return _mod_to_keycode[i].keysym;
|
||||
}
|
||||
}
|
||||
|
||||
return KEY_UNKNOWN;
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
#ifndef KEY_MAPPING_HAIKU_H
|
||||
#define KEY_MAPPING_HAIKU_H
|
||||
|
||||
class KeyMappingHaiku
|
||||
{
|
||||
KeyMappingHaiku() {};
|
||||
|
||||
public:
|
||||
static unsigned int get_keysym(int32 raw_char, int32 key);
|
||||
static unsigned int get_modifier_keysym(int32 key);
|
||||
};
|
||||
|
||||
#endif
|
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
|
@ -0,0 +1,320 @@
|
|||
#include <Screen.h>
|
||||
|
||||
#include "servers/visual/visual_server_raster.h"
|
||||
#include "servers/visual/visual_server_wrap_mt.h"
|
||||
#include "drivers/gles2/rasterizer_gles2.h"
|
||||
#include "servers/physics/physics_server_sw.h"
|
||||
//#include "servers/physics_2d/physics_2d_server_wrap_mt.h"
|
||||
#include "main/main.h"
|
||||
|
||||
#include "os_haiku.h"
|
||||
|
||||
|
||||
OS_Haiku::OS_Haiku() {
|
||||
#ifdef MEDIA_KIT_ENABLED
|
||||
AudioDriverManagerSW::add_driver(&driver_media_kit);
|
||||
#endif
|
||||
};
|
||||
|
||||
void OS_Haiku::run() {
|
||||
if (!main_loop) {
|
||||
return;
|
||||
}
|
||||
|
||||
main_loop->init();
|
||||
context_gl->release_current();
|
||||
|
||||
// TODO: clean up
|
||||
BMessenger* bms = new BMessenger(window);
|
||||
BMessage* msg = new BMessage();
|
||||
bms->SendMessage(LOCKGL_MSG, msg);
|
||||
|
||||
window->StartMessageRunner();
|
||||
app->Run();
|
||||
window->StopMessageRunner();
|
||||
|
||||
delete app;
|
||||
|
||||
delete bms;
|
||||
delete msg;
|
||||
main_loop->finish();
|
||||
}
|
||||
|
||||
String OS_Haiku::get_name() {
|
||||
return "Haiku";
|
||||
}
|
||||
|
||||
int OS_Haiku::get_video_driver_count() const {
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char* OS_Haiku::get_video_driver_name(int p_driver) const {
|
||||
return "GLES2";
|
||||
}
|
||||
|
||||
OS::VideoMode OS_Haiku::get_default_video_mode() const {
|
||||
return OS::VideoMode(800, 600, false);
|
||||
}
|
||||
|
||||
void OS_Haiku::initialize(const VideoMode& p_desired, int p_video_driver, int p_audio_driver) {
|
||||
main_loop = NULL;
|
||||
current_video_mode = p_desired;
|
||||
|
||||
app = new HaikuApplication();
|
||||
|
||||
BRect frame;
|
||||
frame.Set(50, 50, 50 + current_video_mode.width - 1, 50 + current_video_mode.height - 1);
|
||||
|
||||
window = new HaikuDirectWindow(frame);
|
||||
window->SetVideoMode(¤t_video_mode);
|
||||
|
||||
if (current_video_mode.fullscreen) {
|
||||
window->SetFullScreen(true);
|
||||
}
|
||||
|
||||
if (!current_video_mode.resizable) {
|
||||
uint32 flags = window->Flags();
|
||||
flags |= B_NOT_RESIZABLE;
|
||||
window->SetFlags(flags);
|
||||
}
|
||||
|
||||
#if defined(OPENGL_ENABLED) || defined(LEGACYGL_ENABLED)
|
||||
context_gl = memnew(ContextGL_Haiku(window));
|
||||
context_gl->initialize();
|
||||
context_gl->make_current();
|
||||
|
||||
rasterizer = memnew(RasterizerGLES2);
|
||||
#endif
|
||||
|
||||
visual_server = memnew(VisualServerRaster(rasterizer));
|
||||
|
||||
ERR_FAIL_COND(!visual_server);
|
||||
|
||||
// TODO: enable multithreaded VS
|
||||
//if (get_render_thread_mode() != RENDER_THREAD_UNSAFE) {
|
||||
// visual_server = memnew(VisualServerWrapMT(visual_server, get_render_thread_mode() == RENDER_SEPARATE_THREAD));
|
||||
//}
|
||||
|
||||
input = memnew(InputDefault);
|
||||
window->SetInput(input);
|
||||
|
||||
window->Show();
|
||||
visual_server->init();
|
||||
|
||||
physics_server = memnew(PhysicsServerSW);
|
||||
physics_server->init();
|
||||
physics_2d_server = memnew(Physics2DServerSW);
|
||||
// TODO: enable multithreaded PS
|
||||
//physics_2d_server = Physics2DServerWrapMT::init_server<Physics2DServerSW>();
|
||||
physics_2d_server->init();
|
||||
|
||||
AudioDriverManagerSW::get_driver(p_audio_driver)->set_singleton();
|
||||
|
||||
if (AudioDriverManagerSW::get_driver(p_audio_driver)->init() != OK) {
|
||||
ERR_PRINT("Initializing audio failed.");
|
||||
}
|
||||
|
||||
sample_manager = memnew(SampleManagerMallocSW);
|
||||
audio_server = memnew(AudioServerSW(sample_manager));
|
||||
audio_server->init();
|
||||
|
||||
spatial_sound_server = memnew(SpatialSoundServerSW);
|
||||
spatial_sound_server->init();
|
||||
spatial_sound_2d_server = memnew(SpatialSound2DServerSW);
|
||||
spatial_sound_2d_server->init();
|
||||
}
|
||||
|
||||
void OS_Haiku::finalize() {
|
||||
if (main_loop) {
|
||||
memdelete(main_loop);
|
||||
}
|
||||
|
||||
main_loop = NULL;
|
||||
|
||||
spatial_sound_server->finish();
|
||||
memdelete(spatial_sound_server);
|
||||
|
||||
spatial_sound_2d_server->finish();
|
||||
memdelete(spatial_sound_2d_server);
|
||||
|
||||
audio_server->finish();
|
||||
memdelete(audio_server);
|
||||
memdelete(sample_manager);
|
||||
|
||||
visual_server->finish();
|
||||
memdelete(visual_server);
|
||||
memdelete(rasterizer);
|
||||
|
||||
physics_server->finish();
|
||||
memdelete(physics_server);
|
||||
|
||||
physics_2d_server->finish();
|
||||
memdelete(physics_2d_server);
|
||||
|
||||
memdelete(input);
|
||||
|
||||
#if defined(OPENGL_ENABLED) || defined(LEGACYGL_ENABLED)
|
||||
memdelete(context_gl);
|
||||
#endif
|
||||
}
|
||||
|
||||
void OS_Haiku::set_main_loop(MainLoop* p_main_loop) {
|
||||
main_loop = p_main_loop;
|
||||
input->set_main_loop(p_main_loop);
|
||||
window->SetMainLoop(p_main_loop);
|
||||
}
|
||||
|
||||
MainLoop* OS_Haiku::get_main_loop() const {
|
||||
return main_loop;
|
||||
}
|
||||
|
||||
void OS_Haiku::delete_main_loop() {
|
||||
if (main_loop) {
|
||||
memdelete(main_loop);
|
||||
}
|
||||
|
||||
main_loop = NULL;
|
||||
window->SetMainLoop(NULL);
|
||||
}
|
||||
|
||||
void OS_Haiku::release_rendering_thread() {
|
||||
context_gl->release_current();
|
||||
}
|
||||
|
||||
void OS_Haiku::make_rendering_thread() {
|
||||
context_gl->make_current();
|
||||
}
|
||||
|
||||
bool OS_Haiku::can_draw() const {
|
||||
// TODO: implement
|
||||
return true;
|
||||
}
|
||||
|
||||
void OS_Haiku::swap_buffers() {
|
||||
context_gl->swap_buffers();
|
||||
}
|
||||
|
||||
Point2 OS_Haiku::get_mouse_pos() const {
|
||||
return window->GetLastMousePosition();
|
||||
}
|
||||
|
||||
int OS_Haiku::get_mouse_button_state() const {
|
||||
return window->GetLastButtonMask();
|
||||
}
|
||||
|
||||
void OS_Haiku::set_cursor_shape(CursorShape p_shape) {
|
||||
//ERR_PRINT("set_cursor_shape() NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
int OS_Haiku::get_screen_count() const {
|
||||
// TODO: implement get_screen_count()
|
||||
return 1;
|
||||
}
|
||||
|
||||
int OS_Haiku::get_current_screen() const {
|
||||
// TODO: implement get_current_screen()
|
||||
return 0;
|
||||
}
|
||||
|
||||
void OS_Haiku::set_current_screen(int p_screen) {
|
||||
// TODO: implement set_current_screen()
|
||||
}
|
||||
|
||||
Point2 OS_Haiku::get_screen_position(int p_screen) const {
|
||||
// TODO: make this work with the p_screen parameter
|
||||
BScreen* screen = new BScreen(window);
|
||||
BRect frame = screen->Frame();
|
||||
delete screen;
|
||||
return Point2i(frame.left, frame.top);
|
||||
}
|
||||
|
||||
Size2 OS_Haiku::get_screen_size(int p_screen) const {
|
||||
// TODO: make this work with the p_screen parameter
|
||||
BScreen* screen = new BScreen(window);
|
||||
BRect frame = screen->Frame();
|
||||
delete screen;
|
||||
return Size2i(frame.IntegerWidth() + 1, frame.IntegerHeight() + 1);
|
||||
}
|
||||
|
||||
void OS_Haiku::set_window_title(const String& p_title) {
|
||||
window->SetTitle(p_title.utf8().get_data());
|
||||
}
|
||||
|
||||
Size2 OS_Haiku::get_window_size() const {
|
||||
BSize size = window->Size();
|
||||
return Size2i(size.IntegerWidth() + 1, size.IntegerHeight() + 1);
|
||||
}
|
||||
|
||||
void OS_Haiku::set_window_size(const Size2 p_size) {
|
||||
// TODO: why does it stop redrawing after this is called?
|
||||
window->ResizeTo(p_size.x, p_size.y);
|
||||
}
|
||||
|
||||
Point2 OS_Haiku::get_window_position() const {
|
||||
BPoint point(0, 0);
|
||||
window->ConvertToScreen(&point);
|
||||
return Point2i(point.x, point.y);
|
||||
}
|
||||
|
||||
void OS_Haiku::set_window_position(const Point2& p_position) {
|
||||
window->MoveTo(p_position.x, p_position.y);
|
||||
}
|
||||
|
||||
void OS_Haiku::set_window_fullscreen(bool p_enabled) {
|
||||
window->SetFullScreen(p_enabled);
|
||||
current_video_mode.fullscreen = p_enabled;
|
||||
visual_server->init();
|
||||
}
|
||||
|
||||
bool OS_Haiku::is_window_fullscreen() const {
|
||||
return current_video_mode.fullscreen;
|
||||
}
|
||||
|
||||
void OS_Haiku::set_window_resizable(bool p_enabled) {
|
||||
uint32 flags = window->Flags();
|
||||
|
||||
if (p_enabled) {
|
||||
flags &= ~(B_NOT_RESIZABLE);
|
||||
} else {
|
||||
flags |= B_NOT_RESIZABLE;
|
||||
}
|
||||
|
||||
window->SetFlags(flags);
|
||||
current_video_mode.resizable = p_enabled;
|
||||
}
|
||||
|
||||
bool OS_Haiku::is_window_resizable() const {
|
||||
return current_video_mode.resizable;
|
||||
}
|
||||
|
||||
void OS_Haiku::set_window_minimized(bool p_enabled) {
|
||||
window->Minimize(p_enabled);
|
||||
}
|
||||
|
||||
bool OS_Haiku::is_window_minimized() const {
|
||||
return window->IsMinimized();
|
||||
}
|
||||
|
||||
void OS_Haiku::set_window_maximized(bool p_enabled) {
|
||||
window->Minimize(!p_enabled);
|
||||
}
|
||||
|
||||
bool OS_Haiku::is_window_maximized() const {
|
||||
return !window->IsMinimized();
|
||||
}
|
||||
|
||||
void OS_Haiku::set_video_mode(const VideoMode& p_video_mode, int p_screen) {
|
||||
ERR_PRINT("set_video_mode() NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
OS::VideoMode OS_Haiku::get_video_mode(int p_screen) const {
|
||||
return current_video_mode;
|
||||
}
|
||||
|
||||
void OS_Haiku::get_fullscreen_mode_list(List<VideoMode> *p_list, int p_screen) const {
|
||||
ERR_PRINT("get_fullscreen_mode_list() NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
String OS_Haiku::get_executable_path() const {
|
||||
return OS::get_executable_path();
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
#ifndef OS_HAIKU_H
|
||||
#define OS_HAIKU_H
|
||||
|
||||
#include "drivers/unix/os_unix.h"
|
||||
#include "servers/visual_server.h"
|
||||
#include "servers/visual/rasterizer.h"
|
||||
#include "servers/physics_server.h"
|
||||
#include "servers/physics_2d/physics_2d_server_sw.h"
|
||||
#include "servers/audio/audio_server_sw.h"
|
||||
#include "servers/audio/sample_manager_sw.h"
|
||||
#include "servers/spatial_sound/spatial_sound_server_sw.h"
|
||||
#include "servers/spatial_sound_2d/spatial_sound_2d_server_sw.h"
|
||||
#include "main/input_default.h"
|
||||
|
||||
#include "audio_driver_media_kit.h"
|
||||
#include "context_gl_haiku.h"
|
||||
#include "haiku_application.h"
|
||||
#include "haiku_direct_window.h"
|
||||
|
||||
|
||||
class OS_Haiku : public OS_Unix {
|
||||
private:
|
||||
HaikuApplication* app;
|
||||
HaikuDirectWindow* window;
|
||||
MainLoop* main_loop;
|
||||
InputDefault* input;
|
||||
Rasterizer* rasterizer;
|
||||
VisualServer* visual_server;
|
||||
VideoMode current_video_mode;
|
||||
PhysicsServer* physics_server;
|
||||
Physics2DServer* physics_2d_server;
|
||||
AudioServerSW* audio_server;
|
||||
SampleManagerMallocSW* sample_manager;
|
||||
SpatialSoundServerSW* spatial_sound_server;
|
||||
SpatialSound2DServerSW* spatial_sound_2d_server;
|
||||
|
||||
#ifdef MEDIA_KIT_ENABLED
|
||||
AudioDriverMediaKit driver_media_kit;
|
||||
#endif
|
||||
|
||||
#if defined(OPENGL_ENABLED) || defined(LEGACYGL_ENABLED)
|
||||
ContextGL_Haiku* context_gl;
|
||||
#endif
|
||||
|
||||
virtual void delete_main_loop();
|
||||
|
||||
protected:
|
||||
virtual int get_video_driver_count() const;
|
||||
virtual const char* get_video_driver_name(int p_driver) const;
|
||||
virtual VideoMode get_default_video_mode() const;
|
||||
|
||||
virtual void initialize(const VideoMode& p_desired, int p_video_driver, int p_audio_driver);
|
||||
virtual void finalize();
|
||||
|
||||
virtual void set_main_loop(MainLoop* p_main_loop);
|
||||
|
||||
public:
|
||||
OS_Haiku();
|
||||
void run();
|
||||
|
||||
virtual String get_name();
|
||||
|
||||
virtual MainLoop* get_main_loop() const;
|
||||
|
||||
virtual bool can_draw() const;
|
||||
virtual void release_rendering_thread();
|
||||
virtual void make_rendering_thread();
|
||||
virtual void swap_buffers();
|
||||
|
||||
virtual Point2 get_mouse_pos() const;
|
||||
virtual int get_mouse_button_state() const;
|
||||
virtual void set_cursor_shape(CursorShape p_shape);
|
||||
|
||||
virtual int get_screen_count() const;
|
||||
virtual int get_current_screen() const;
|
||||
virtual void set_current_screen(int p_screen);
|
||||
virtual Point2 get_screen_position(int p_screen=0) const;
|
||||
virtual Size2 get_screen_size(int p_screen=0) const;
|
||||
virtual void set_window_title(const String& p_title);
|
||||
virtual Size2 get_window_size() const;
|
||||
virtual void set_window_size(const Size2 p_size);
|
||||
virtual Point2 get_window_position() const;
|
||||
virtual void set_window_position(const Point2& p_position);
|
||||
virtual void set_window_fullscreen(bool p_enabled);
|
||||
virtual bool is_window_fullscreen() const;
|
||||
virtual void set_window_resizable(bool p_enabled);
|
||||
virtual bool is_window_resizable() const;
|
||||
virtual void set_window_minimized(bool p_enabled);
|
||||
virtual bool is_window_minimized() const;
|
||||
virtual void set_window_maximized(bool p_enabled);
|
||||
virtual bool is_window_maximized() 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;
|
||||
virtual String get_executable_path() const;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,6 @@
|
|||
#include <alloca.h>
|
||||
|
||||
// for ifaddrs.h needed in drivers/unix/ip_unix.cpp
|
||||
#define _BSD_SOURCE 1
|
||||
|
||||
#define GLES2_INCLUDE_H <GL/glew.h>
|
|
@ -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;
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -784,8 +784,6 @@ void OS_X11::set_window_size(const Size2 p_size) {
|
|||
void OS_X11::set_window_fullscreen(bool p_enabled) {
|
||||
set_wm_fullscreen(p_enabled);
|
||||
current_videomode.fullscreen = p_enabled;
|
||||
|
||||
visual_server->init();
|
||||
}
|
||||
|
||||
bool OS_X11::is_window_fullscreen() const {
|
||||
|
@ -891,8 +889,14 @@ void OS_X11::set_window_maximized(bool p_enabled) {
|
|||
xev.xclient.data.l[2] = wm_max_vert;
|
||||
|
||||
XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
|
||||
|
||||
/* sorry this does not fix it, fails on multi monitor
|
||||
XWindowAttributes xwa;
|
||||
XGetWindowAttributes(x11_display,DefaultRootWindow(x11_display),&xwa);
|
||||
current_videomode.width = xwa.width;
|
||||
current_videomode.height = xwa.height;
|
||||
*/
|
||||
maximized = p_enabled;
|
||||
|
||||
}
|
||||
|
||||
bool OS_X11::is_window_maximized() const {
|
||||
|
@ -1201,7 +1205,6 @@ void OS_X11::process_xevents() {
|
|||
#ifdef NEW_WM_API
|
||||
if(current_videomode.fullscreen) {
|
||||
set_wm_fullscreen(true);
|
||||
visual_server->init();
|
||||
}
|
||||
#endif
|
||||
main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_IN);
|
||||
|
@ -1218,7 +1221,6 @@ void OS_X11::process_xevents() {
|
|||
if(current_videomode.fullscreen) {
|
||||
set_wm_fullscreen(false);
|
||||
set_window_minimized(true);
|
||||
visual_server->init();
|
||||
}
|
||||
#endif
|
||||
main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_OUT);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
|
|
@ -110,7 +110,10 @@ void ParallaxBackground::_update_scroll() {
|
|||
if (!l)
|
||||
continue;
|
||||
|
||||
l->set_base_offset_and_scale(ofs,scale);
|
||||
if (ignore_camera_zoom)
|
||||
l->set_base_offset_and_scale(ofs, 1.0);
|
||||
else
|
||||
l->set_base_offset_and_scale(ofs, scale);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -165,6 +168,18 @@ Point2 ParallaxBackground::get_limit_end() const {
|
|||
return limit_end;
|
||||
}
|
||||
|
||||
void ParallaxBackground::set_ignore_camera_zoom(bool ignore){
|
||||
|
||||
ignore_camera_zoom = ignore;
|
||||
|
||||
}
|
||||
|
||||
bool ParallaxBackground::is_ignore_camera_zoom(){
|
||||
|
||||
return ignore_camera_zoom;
|
||||
|
||||
}
|
||||
|
||||
void ParallaxBackground::_bind_methods() {
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("_camera_moved"),&ParallaxBackground::_camera_moved);
|
||||
|
@ -178,6 +193,8 @@ void ParallaxBackground::_bind_methods() {
|
|||
ObjectTypeDB::bind_method(_MD("get_limit_begin"),&ParallaxBackground::get_limit_begin);
|
||||
ObjectTypeDB::bind_method(_MD("set_limit_end","ofs"),&ParallaxBackground::set_limit_end);
|
||||
ObjectTypeDB::bind_method(_MD("get_limit_end"),&ParallaxBackground::get_limit_end);
|
||||
ObjectTypeDB::bind_method(_MD("set_ignore_camera_zoom"), &ParallaxBackground::set_ignore_camera_zoom);
|
||||
ObjectTypeDB::bind_method(_MD("is_ignore_camera_zoom"), &ParallaxBackground::is_ignore_camera_zoom);
|
||||
|
||||
|
||||
ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"scroll/offset"),_SCS("set_scroll_offset"),_SCS("get_scroll_offset"));
|
||||
|
@ -185,6 +202,7 @@ void ParallaxBackground::_bind_methods() {
|
|||
ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"scroll/base_scale"),_SCS("set_scroll_base_scale"),_SCS("get_scroll_base_scale"));
|
||||
ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"scroll/limit_begin"),_SCS("set_limit_begin"),_SCS("get_limit_begin"));
|
||||
ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"scroll/limit_end"),_SCS("set_limit_end"),_SCS("get_limit_end"));
|
||||
ADD_PROPERTY( PropertyInfo(Variant::BOOL, "scroll/ignore_camera_zoom"), _SCS("set_ignore_camera_zoom"), _SCS("is_ignore_camera_zoom"));
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -44,6 +44,7 @@ class ParallaxBackground : public CanvasLayer {
|
|||
String group_name;
|
||||
Point2 limit_begin;
|
||||
Point2 limit_end;
|
||||
bool ignore_camera_zoom;
|
||||
|
||||
void _update_scroll();
|
||||
protected:
|
||||
|
@ -72,6 +73,9 @@ public:
|
|||
void set_limit_end(const Point2& p_ofs);
|
||||
Point2 get_limit_end() const;
|
||||
|
||||
void set_ignore_camera_zoom(bool ignore);
|
||||
bool is_ignore_camera_zoom();
|
||||
|
||||
ParallaxBackground();
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -81,7 +81,7 @@ float BakedLightSampler::get_param(Param p_param) const{
|
|||
|
||||
void BakedLightSampler::set_resolution(int p_resolution){
|
||||
|
||||
ERR_FAIL_COND(p_resolution<4 && p_resolution>32);
|
||||
ERR_FAIL_COND(p_resolution<4 || p_resolution>32);
|
||||
resolution=p_resolution;
|
||||
VS::get_singleton()->baked_light_sampler_set_resolution(base,resolution);
|
||||
}
|
||||
|
|
|
@ -126,7 +126,7 @@ void CollisionPolygon::_notification(int p_what) {
|
|||
|
||||
} break;
|
||||
case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: {
|
||||
if (!can_update_body && shape_from>=0 && shape_from>=0) {
|
||||
if (!can_update_body && shape_from>=0 && shape_to>=0) {
|
||||
|
||||
CollisionObject *co = get_parent()->cast_to<CollisionObject>();
|
||||
if (co) {
|
||||
|
|
|
@ -2713,6 +2713,21 @@ void Control::warp_mouse(const Point2& p_to_pos) {
|
|||
get_viewport()->warp_mouse(get_global_transform().xform(p_to_pos));
|
||||
}
|
||||
|
||||
|
||||
bool Control::is_text_field() const {
|
||||
/*
|
||||
if (get_script_instance()) {
|
||||
Variant v=p_point;
|
||||
const Variant *p[2]={&v,&p_data};
|
||||
Variant::CallError ce;
|
||||
Variant ret = get_script_instance()->call("is_text_field",p,2,ce);
|
||||
if (ce.error==Variant::CallError::CALL_OK)
|
||||
return ret;
|
||||
}
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
|
||||
void Control::_bind_methods() {
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("_window_input_event"),&Control::_window_input_event);
|
||||
|
|
|
@ -382,6 +382,8 @@ public:
|
|||
|
||||
void warp_mouse(const Point2& p_to_pos);
|
||||
|
||||
virtual bool is_text_field() const;
|
||||
|
||||
Control();
|
||||
~Control();
|
||||
|
||||
|
|
|
@ -782,6 +782,10 @@ void LineEdit::select(int p_from, int p_to) {
|
|||
update();
|
||||
}
|
||||
|
||||
bool LineEdit::is_text_field() const {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void LineEdit::_bind_methods() {
|
||||
|
||||
|
|
|
@ -112,6 +112,8 @@ public:
|
|||
void select(int p_from=0, int p_to=-1);
|
||||
|
||||
virtual Size2 get_minimum_size() const;
|
||||
|
||||
virtual bool is_text_field() const;
|
||||
LineEdit();
|
||||
~LineEdit();
|
||||
|
||||
|
|
|
@ -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!="") {
|
||||
|
||||
|
@ -738,10 +740,18 @@ int PopupMenu::find_item_by_accelerator(uint32_t p_accel) const {
|
|||
|
||||
void PopupMenu::activate_item(int p_item) {
|
||||
|
||||
|
||||
ERR_FAIL_INDEX(p_item,items.size());
|
||||
ERR_FAIL_COND(items[p_item].separator);
|
||||
emit_signal("item_pressed",items[p_item].ID);
|
||||
|
||||
//hide all parent PopupMenue's
|
||||
Node *next = get_parent();
|
||||
PopupMenu *pop = next->cast_to<PopupMenu>();
|
||||
while (pop) {
|
||||
pop->hide();
|
||||
next = next->get_parent();
|
||||
pop = next->cast_to<PopupMenu>();
|
||||
}
|
||||
hide();
|
||||
|
||||
}
|
||||
|
|
|
@ -1503,10 +1503,10 @@ Error RichTextLabel::append_bbcode(const String& p_bbcode) {
|
|||
|
||||
void RichTextLabel::scroll_to_line(int p_line) {
|
||||
|
||||
p_line -= 1;
|
||||
ERR_FAIL_INDEX(p_line,lines.size());
|
||||
_validate_line_caches();
|
||||
vscroll->set_val(lines[p_line].height_accum_cache);
|
||||
|
||||
vscroll->set_val(lines[p_line].height_accum_cache-lines[p_line].height_cache);
|
||||
|
||||
}
|
||||
|
||||
|
@ -1569,27 +1569,23 @@ bool RichTextLabel::search(const String& p_string,bool p_from_selection) {
|
|||
it=_get_next_item(it);
|
||||
}
|
||||
|
||||
if (!it)
|
||||
line=lines.size()-1;
|
||||
}
|
||||
|
||||
scroll_to_line(line-2);
|
||||
if (line > 1) {
|
||||
line-=1;
|
||||
}
|
||||
|
||||
scroll_to_line(line);
|
||||
|
||||
return true;
|
||||
}
|
||||
} else if (it->type==ITEM_NEWLINE) {
|
||||
|
||||
line=static_cast<ItemNewline*>(it)->line;
|
||||
}
|
||||
|
||||
|
||||
it=_get_next_item(it);
|
||||
charidx=0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
|
|
@ -64,6 +64,15 @@ Size2 Tabs::get_minimum_size() const {
|
|||
ms.width+=bms.width;
|
||||
ms.height=MAX(bms.height+tab_bg->get_minimum_size().height,ms.height);
|
||||
}
|
||||
|
||||
if (tabs[i].close_button.is_valid()) {
|
||||
Ref<Texture> cb=tabs[i].close_button;
|
||||
Size2 bms = cb->get_size()+get_stylebox("button")->get_minimum_size();
|
||||
bms.width+=get_constant("hseparation");
|
||||
|
||||
ms.width+=bms.width;
|
||||
ms.height=MAX(bms.height+tab_bg->get_minimum_size().height,ms.height);
|
||||
}
|
||||
}
|
||||
|
||||
return ms;
|
||||
|
@ -77,22 +86,48 @@ void Tabs::_input_event(const InputEvent& p_event) {
|
|||
|
||||
Point2 pos( p_event.mouse_motion.x, p_event.mouse_motion.y );
|
||||
|
||||
int hover=-1;
|
||||
int hover_buttons=-1;
|
||||
hover=-1;
|
||||
for(int i=0;i<tabs.size();i++) {
|
||||
|
||||
// test hovering tab to display close button if policy says so
|
||||
if (cb_displaypolicy == SHOW_HOVER) {
|
||||
int ofs=tabs[i].ofs_cache;
|
||||
int size = tabs[i].ofs_cache;
|
||||
if (pos.x >=tabs[i].ofs_cache && pos.x<tabs[i].ofs_cache+tabs[i].size_cache) {
|
||||
hover=i;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// test hovering right button and close button
|
||||
if (tabs[i].rb_rect.has_point(pos)) {
|
||||
hover=i;
|
||||
rb_hover=i;
|
||||
hover_buttons = i;
|
||||
break;
|
||||
}
|
||||
else if (tabs[i].cb_rect.has_point(pos)) {
|
||||
cb_hover=i;
|
||||
hover_buttons = i;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (hover!=rb_hover) {
|
||||
rb_hover=hover;
|
||||
update();
|
||||
if (hover_buttons == -1) { // no hover
|
||||
rb_hover= hover_buttons;
|
||||
cb_hover= hover_buttons;
|
||||
}
|
||||
update();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if (rb_pressing && p_event.type==InputEvent::MOUSE_BUTTON &&
|
||||
!p_event.mouse_button.pressed &&
|
||||
p_event.mouse_button.button_index==BUTTON_LEFT) {
|
||||
|
@ -106,6 +141,20 @@ void Tabs::_input_event(const InputEvent& p_event) {
|
|||
update();
|
||||
}
|
||||
|
||||
if (cb_pressing && p_event.type==InputEvent::MOUSE_BUTTON &&
|
||||
!p_event.mouse_button.pressed &&
|
||||
p_event.mouse_button.button_index==BUTTON_LEFT) {
|
||||
|
||||
if (cb_hover!=-1) {
|
||||
//pressed
|
||||
emit_signal("tab_close",cb_hover);
|
||||
}
|
||||
|
||||
cb_pressing=false;
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
if (p_event.type==InputEvent::MOUSE_BUTTON &&
|
||||
p_event.mouse_button.pressed &&
|
||||
p_event.mouse_button.button_index==BUTTON_LEFT) {
|
||||
|
@ -122,6 +171,12 @@ void Tabs::_input_event(const InputEvent& p_event) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (tabs[i].cb_rect.has_point(pos)) {
|
||||
cb_pressing=true;
|
||||
update();
|
||||
return;
|
||||
}
|
||||
|
||||
int ofs=tabs[i].ofs_cache;
|
||||
int size = tabs[i].ofs_cache;
|
||||
if (pos.x >=tabs[i].ofs_cache && pos.x<tabs[i].ofs_cache+tabs[i].size_cache) {
|
||||
|
@ -148,6 +203,8 @@ void Tabs::_notification(int p_what) {
|
|||
|
||||
case NOTIFICATION_MOUSE_EXIT: {
|
||||
rb_hover=-1;
|
||||
cb_hover=-1;
|
||||
hover=-1;
|
||||
update();
|
||||
} break;
|
||||
case NOTIFICATION_DRAW: {
|
||||
|
@ -186,7 +243,7 @@ void Tabs::_notification(int p_what) {
|
|||
|
||||
String s = tabs[i].text;
|
||||
int lsize=0;
|
||||
int slen=font->get_string_size(s).width;;
|
||||
int slen=font->get_string_size(s).width;
|
||||
lsize+=slen;
|
||||
|
||||
Ref<Texture> icon;
|
||||
|
@ -211,6 +268,56 @@ void Tabs::_notification(int p_what) {
|
|||
|
||||
}
|
||||
|
||||
// Close button
|
||||
switch (cb_displaypolicy) {
|
||||
case SHOW_ALWAYS: {
|
||||
if (tabs[i].close_button.is_valid()) {
|
||||
Ref<StyleBox> style = get_stylebox("button");
|
||||
Ref<Texture> rb=tabs[i].close_button;
|
||||
|
||||
lsize+=get_constant("hseparation");
|
||||
lsize+=style->get_margin(MARGIN_LEFT);
|
||||
lsize+=rb->get_width();
|
||||
lsize+=style->get_margin(MARGIN_RIGHT);
|
||||
|
||||
}
|
||||
} break;
|
||||
case SHOW_ACTIVE_ONLY: {
|
||||
if (i==current) {
|
||||
if (tabs[i].close_button.is_valid()) {
|
||||
Ref<StyleBox> style = get_stylebox("button");
|
||||
Ref<Texture> rb=tabs[i].close_button;
|
||||
|
||||
lsize+=get_constant("hseparation");
|
||||
lsize+=style->get_margin(MARGIN_LEFT);
|
||||
lsize+=rb->get_width();
|
||||
lsize+=style->get_margin(MARGIN_RIGHT);
|
||||
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case SHOW_HOVER: {
|
||||
if (i==current || i==hover) {
|
||||
if (tabs[i].close_button.is_valid()) {
|
||||
Ref<StyleBox> style = get_stylebox("button");
|
||||
Ref<Texture> rb=tabs[i].close_button;
|
||||
|
||||
lsize+=get_constant("hseparation");
|
||||
lsize+=style->get_margin(MARGIN_LEFT);
|
||||
lsize+=rb->get_width();
|
||||
lsize+=style->get_margin(MARGIN_RIGHT);
|
||||
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case SHOW_NEVER: // by default, never show close button
|
||||
default: {
|
||||
// do nothing
|
||||
} break;
|
||||
|
||||
}
|
||||
|
||||
|
||||
Ref<StyleBox> sb;
|
||||
int va;
|
||||
Color col;
|
||||
|
@ -273,6 +380,103 @@ void Tabs::_notification(int p_what) {
|
|||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Close button
|
||||
switch (cb_displaypolicy) {
|
||||
case SHOW_ALWAYS: {
|
||||
if (tabs[i].close_button.is_valid()) {
|
||||
Ref<StyleBox> style = get_stylebox("button");
|
||||
Ref<Texture> cb=tabs[i].close_button;
|
||||
|
||||
w+=get_constant("hseparation");
|
||||
|
||||
Rect2 cb_rect;
|
||||
cb_rect.size=style->get_minimum_size()+cb->get_size();
|
||||
cb_rect.pos.x=w;
|
||||
cb_rect.pos.y=sb->get_margin(MARGIN_TOP)+((sb_rect.size.y-sb_ms.y)-(cb_rect.size.y))/2;
|
||||
|
||||
if (cb_hover==i) {
|
||||
if (cb_pressing)
|
||||
get_stylebox("button_pressed")->draw(ci,cb_rect);
|
||||
else
|
||||
style->draw(ci,cb_rect);
|
||||
}
|
||||
|
||||
w+=style->get_margin(MARGIN_LEFT);
|
||||
|
||||
cb->draw(ci,Point2i( w,cb_rect.pos.y+style->get_margin(MARGIN_TOP) ));
|
||||
w+=cb->get_width();
|
||||
w+=style->get_margin(MARGIN_RIGHT);
|
||||
tabs[i].cb_rect=cb_rect;
|
||||
}
|
||||
} break;
|
||||
case SHOW_ACTIVE_ONLY: {
|
||||
if (current==i) {
|
||||
if (tabs[i].close_button.is_valid()) {
|
||||
Ref<StyleBox> style = get_stylebox("button");
|
||||
Ref<Texture> cb=tabs[i].close_button;
|
||||
|
||||
w+=get_constant("hseparation");
|
||||
|
||||
Rect2 cb_rect;
|
||||
cb_rect.size=style->get_minimum_size()+cb->get_size();
|
||||
cb_rect.pos.x=w;
|
||||
cb_rect.pos.y=sb->get_margin(MARGIN_TOP)+((sb_rect.size.y-sb_ms.y)-(cb_rect.size.y))/2;
|
||||
|
||||
if (cb_hover==i) {
|
||||
if (cb_pressing)
|
||||
get_stylebox("button_pressed")->draw(ci,cb_rect);
|
||||
else
|
||||
style->draw(ci,cb_rect);
|
||||
}
|
||||
|
||||
w+=style->get_margin(MARGIN_LEFT);
|
||||
|
||||
cb->draw(ci,Point2i( w,cb_rect.pos.y+style->get_margin(MARGIN_TOP) ));
|
||||
w+=cb->get_width();
|
||||
w+=style->get_margin(MARGIN_RIGHT);
|
||||
tabs[i].cb_rect=cb_rect;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case SHOW_HOVER: {
|
||||
if (current==i || hover==i) {
|
||||
if (tabs[i].close_button.is_valid()) {
|
||||
Ref<StyleBox> style = get_stylebox("button");
|
||||
Ref<Texture> cb=tabs[i].close_button;
|
||||
|
||||
w+=get_constant("hseparation");
|
||||
|
||||
Rect2 cb_rect;
|
||||
cb_rect.size=style->get_minimum_size()+cb->get_size();
|
||||
cb_rect.pos.x=w;
|
||||
cb_rect.pos.y=sb->get_margin(MARGIN_TOP)+((sb_rect.size.y-sb_ms.y)-(cb_rect.size.y))/2;
|
||||
|
||||
if (cb_hover==i) {
|
||||
if (cb_pressing)
|
||||
get_stylebox("button_pressed")->draw(ci,cb_rect);
|
||||
else
|
||||
style->draw(ci,cb_rect);
|
||||
}
|
||||
|
||||
w+=style->get_margin(MARGIN_LEFT);
|
||||
|
||||
cb->draw(ci,Point2i( w,cb_rect.pos.y+style->get_margin(MARGIN_TOP) ));
|
||||
w+=cb->get_width();
|
||||
w+=style->get_margin(MARGIN_RIGHT);
|
||||
tabs[i].cb_rect=cb_rect;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case SHOW_NEVER:
|
||||
default: {
|
||||
// show nothing
|
||||
} break;
|
||||
|
||||
}
|
||||
|
||||
w+=sb->get_margin(MARGIN_RIGHT);
|
||||
|
||||
tabs[i].size_cache=w-tabs[i].ofs_cache;
|
||||
|
@ -358,11 +562,29 @@ Ref<Texture> Tabs::get_tab_right_button(int p_tab) const{
|
|||
|
||||
}
|
||||
|
||||
void Tabs::set_tab_close_button(int p_tab, const Ref<Texture>& p_close_button) {
|
||||
ERR_FAIL_INDEX(p_tab, tabs.size());
|
||||
tabs[p_tab].close_button=p_close_button;
|
||||
update();
|
||||
minimum_size_changed();
|
||||
}
|
||||
|
||||
|
||||
Ref<Texture> Tabs::get_tab_close_button(int p_tab) const{
|
||||
|
||||
ERR_FAIL_INDEX_V(p_tab,tabs.size(),Ref<Texture>());
|
||||
return tabs[p_tab].close_button;
|
||||
|
||||
}
|
||||
|
||||
void Tabs::add_tab(const String& p_str,const Ref<Texture>& p_icon) {
|
||||
|
||||
Tab t;
|
||||
t.text=p_str;
|
||||
t.icon=p_icon;
|
||||
|
||||
t.close_button = get_icon("Close","EditorIcons");
|
||||
|
||||
tabs.push_back(t);
|
||||
|
||||
update();
|
||||
|
@ -394,6 +616,11 @@ void Tabs::remove_tab(int p_idx) {
|
|||
|
||||
}
|
||||
|
||||
void Tabs::set_tab_close_display_policy(CloseButtonDisplayPolicy p_cb_displaypolicy) {
|
||||
cb_displaypolicy = p_cb_displaypolicy;
|
||||
}
|
||||
|
||||
|
||||
void Tabs::set_tab_align(TabAlign p_align) {
|
||||
|
||||
tab_align=p_align;
|
||||
|
@ -423,14 +650,22 @@ void Tabs::_bind_methods() {
|
|||
|
||||
ADD_SIGNAL(MethodInfo("tab_changed",PropertyInfo(Variant::INT,"tab")));
|
||||
ADD_SIGNAL(MethodInfo("right_button_pressed",PropertyInfo(Variant::INT,"tab")));
|
||||
ADD_SIGNAL(MethodInfo("tab_close",PropertyInfo(Variant::INT,"tab")));
|
||||
|
||||
|
||||
ADD_PROPERTY( PropertyInfo(Variant::INT, "current_tab", PROPERTY_HINT_RANGE,"-1,4096,1",PROPERTY_USAGE_EDITOR), _SCS("set_current_tab"), _SCS("get_current_tab") );
|
||||
|
||||
BIND_CONSTANT( ALIGN_LEFT );
|
||||
BIND_CONSTANT( ALIGN_CENTER );
|
||||
BIND_CONSTANT( ALIGN_RIGHT );
|
||||
|
||||
BIND_CONSTANT( SHOW_ACTIVE_ONLY );
|
||||
BIND_CONSTANT( SHOW_ALWAYS );
|
||||
BIND_CONSTANT( SHOW_HOVER );
|
||||
BIND_CONSTANT( SHOW_NEVER );
|
||||
}
|
||||
|
||||
|
||||
Tabs::Tabs() {
|
||||
|
||||
current=0;
|
||||
|
@ -438,4 +673,7 @@ Tabs::Tabs() {
|
|||
rb_hover=-1;
|
||||
rb_pressing=false;
|
||||
|
||||
cb_hover=-1;
|
||||
cb_pressing=false;
|
||||
cb_displaypolicy = SHOW_NEVER; // Default : no close button
|
||||
}
|
||||
|
|
|
@ -42,6 +42,14 @@ public:
|
|||
ALIGN_CENTER,
|
||||
ALIGN_RIGHT
|
||||
};
|
||||
|
||||
enum CloseButtonDisplayPolicy {
|
||||
|
||||
SHOW_ALWAYS,
|
||||
SHOW_ACTIVE_ONLY,
|
||||
SHOW_HOVER,
|
||||
SHOW_NEVER
|
||||
};
|
||||
private:
|
||||
|
||||
|
||||
|
@ -53,6 +61,8 @@ private:
|
|||
int size_cache;
|
||||
Ref<Texture> right_button;
|
||||
Rect2 rb_rect;
|
||||
Ref<Texture> close_button;
|
||||
Rect2 cb_rect;
|
||||
};
|
||||
|
||||
Vector<Tab> tabs;
|
||||
|
@ -63,6 +73,12 @@ private:
|
|||
int rb_hover;
|
||||
bool rb_pressing;
|
||||
|
||||
int cb_hover;
|
||||
bool cb_pressing;
|
||||
CloseButtonDisplayPolicy cb_displaypolicy;
|
||||
|
||||
int hover; // hovered tab
|
||||
|
||||
protected:
|
||||
|
||||
void _input_event(const InputEvent& p_event);
|
||||
|
@ -82,6 +98,10 @@ public:
|
|||
void set_tab_right_button(int p_tab,const Ref<Texture>& p_right_button);
|
||||
Ref<Texture> get_tab_right_button(int p_tab) const;
|
||||
|
||||
void set_tab_close_button(int p_tab, const Ref<Texture>& p_close_button);
|
||||
Ref<Texture> get_tab_close_button(int p_tab) const;
|
||||
void set_tab_close_display_policy(CloseButtonDisplayPolicy p_cb_displaypolicy);
|
||||
|
||||
void set_tab_align(TabAlign p_align);
|
||||
TabAlign get_tab_align() const;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
@ -3568,7 +3568,10 @@ void TextEdit::set_show_line_numbers(bool p_show) {
|
|||
update();
|
||||
}
|
||||
|
||||
bool TextEdit::is_text_field() const {
|
||||
|
||||
return true;
|
||||
}
|
||||
void TextEdit::_bind_methods() {
|
||||
|
||||
|
||||
|
|
|
@ -393,6 +393,7 @@ public:
|
|||
|
||||
String get_text_for_completion();
|
||||
|
||||
virtual bool is_text_field() const;
|
||||
TextEdit();
|
||||
~TextEdit();
|
||||
};
|
||||
|
|
|
@ -1993,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);
|
||||
|
||||
|
|
|
@ -101,7 +101,7 @@ Node *SceneState::instance(bool p_gen_edit_state) const {
|
|||
|
||||
if (i==0 && base_scene_idx>=0) {
|
||||
//scene inheritance on root node
|
||||
print_line("scene inherit");
|
||||
//print_line("scene inherit");
|
||||
Ref<PackedScene> sdata = props[ base_scene_idx ];
|
||||
ERR_FAIL_COND_V( !sdata.is_valid(), NULL);
|
||||
node = sdata->instance(p_gen_edit_state);
|
||||
|
@ -112,7 +112,7 @@ Node *SceneState::instance(bool p_gen_edit_state) const {
|
|||
|
||||
} else if (n.instance>=0) {
|
||||
//instance a scene into this node
|
||||
print_line("instance");
|
||||
//print_line("instance");
|
||||
if (n.instance&FLAG_INSTANCE_IS_PLACEHOLDER) {
|
||||
|
||||
String path = props[n.instance&FLAG_MASK];
|
||||
|
@ -148,7 +148,7 @@ Node *SceneState::instance(bool p_gen_edit_state) const {
|
|||
#endif
|
||||
}
|
||||
} else if (ObjectTypeDB::is_type_enabled(snames[n.type])) {
|
||||
print_line("created");
|
||||
//print_line("created");
|
||||
//node belongs to this scene and must be created
|
||||
Object * obj = ObjectTypeDB::instance(snames[ n.type ]);
|
||||
if (!obj || !obj->cast_to<Node>()) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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) {
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -1375,7 +1375,7 @@ void VisualServerRaster::_update_baked_light_sampler_dp_cache(BakedLightSampler
|
|||
|
||||
void VisualServerRaster::baked_light_sampler_set_resolution(RID p_baked_light_sampler,int p_resolution){
|
||||
|
||||
ERR_FAIL_COND(p_resolution<4 && p_resolution>64);
|
||||
ERR_FAIL_COND(p_resolution<4 || p_resolution>64);
|
||||
VS_CHANGED;
|
||||
BakedLightSampler * blsamp = baked_light_sampler_owner.get(p_baked_light_sampler);
|
||||
ERR_FAIL_COND(!blsamp);
|
||||
|
@ -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.
|
@ -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"
|
|
@ -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 ""
|
|
@ -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())))
|
|
@ -2369,7 +2369,7 @@ void AnimationKeyEditor::_track_editor_input_event(const InputEvent& p_input) {
|
|||
te->update();
|
||||
track_editor->set_tooltip("");
|
||||
|
||||
if (!track_editor->has_focus() && (!get_focus_owner() || !get_focus_owner()->cast_to<LineEdit>()))
|
||||
if (!track_editor->has_focus() && (!get_focus_owner() || !get_focus_owner()->is_text_field()))
|
||||
track_editor->call_deferred("grab_focus");
|
||||
|
||||
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -976,6 +976,7 @@ void EditorNode::_save_scene(String p_file) {
|
|||
//EditorFileSystem::get_singleton()->update_file(p_file,sdata->get_type());
|
||||
set_current_version(editor_data.get_undo_redo().get_version());
|
||||
_update_title();
|
||||
_update_scene_tabs();
|
||||
} else {
|
||||
|
||||
_dialog_display_file_error(p_file,err);
|
||||
|
@ -1399,7 +1400,6 @@ void EditorNode::_dialog_action(String p_file) {
|
|||
} break;
|
||||
default: { //save scene?
|
||||
|
||||
|
||||
if (file->get_mode()==FileDialog::MODE_SAVE_FILE) {
|
||||
|
||||
//_save_scene(p_file);
|
||||
|
@ -3452,6 +3452,9 @@ Error EditorNode::load_scene(const String& p_scene, bool p_ignore_broken_deps,bo
|
|||
Ref<SceneState> state = sdata->get_state();
|
||||
state->set_path(lpath);
|
||||
new_scene->set_scene_inherited_state(state);
|
||||
new_scene->set_filename(String());
|
||||
if (new_scene->get_scene_instance_state().is_valid())
|
||||
new_scene->get_scene_instance_state()->set_path(String());
|
||||
}
|
||||
|
||||
|
||||
|
@ -3931,6 +3934,7 @@ void EditorNode::_bind_methods() {
|
|||
ObjectTypeDB::bind_method("set_current_scene",&EditorNode::set_current_scene);
|
||||
ObjectTypeDB::bind_method("set_current_version",&EditorNode::set_current_version);
|
||||
ObjectTypeDB::bind_method("_scene_tab_changed",&EditorNode::_scene_tab_changed);
|
||||
ObjectTypeDB::bind_method("_scene_tab_closed",&EditorNode::_scene_tab_closed);
|
||||
ObjectTypeDB::bind_method("_scene_tab_script_edited",&EditorNode::_scene_tab_script_edited);
|
||||
ObjectTypeDB::bind_method("_set_main_scene_state",&EditorNode::_set_main_scene_state);
|
||||
ObjectTypeDB::bind_method("_update_scene_tabs",&EditorNode::_update_scene_tabs);
|
||||
|
@ -4385,6 +4389,17 @@ void EditorNode::_scene_tab_script_edited(int p_tab) {
|
|||
edit_resource(script);
|
||||
}
|
||||
|
||||
void EditorNode::_scene_tab_closed(int p_tab) {
|
||||
set_current_scene(p_tab);
|
||||
bool p_confirmed = true;
|
||||
if (unsaved_cache)
|
||||
p_confirmed = false;
|
||||
|
||||
_menu_option_confirm(FILE_CLOSE, p_confirmed);
|
||||
_update_scene_tabs();
|
||||
}
|
||||
|
||||
|
||||
void EditorNode::_scene_tab_changed(int p_tab) {
|
||||
|
||||
|
||||
|
@ -4552,8 +4567,10 @@ EditorNode::EditorNode() {
|
|||
scene_tabs=memnew( Tabs );
|
||||
scene_tabs->add_tab("unsaved");
|
||||
scene_tabs->set_tab_align(Tabs::ALIGN_CENTER);
|
||||
scene_tabs->set_tab_close_display_policy(Tabs::SHOW_HOVER);
|
||||
scene_tabs->connect("tab_changed",this,"_scene_tab_changed");
|
||||
scene_tabs->connect("right_button_pressed",this,"_scene_tab_script_edited");
|
||||
scene_tabs->connect("tab_close", this, "_scene_tab_closed");
|
||||
top_dark_vb->add_child(scene_tabs);
|
||||
//left
|
||||
left_l_hsplit = memnew( HSplitContainer );
|
||||
|
@ -4690,6 +4707,7 @@ EditorNode::EditorNode() {
|
|||
|
||||
main_editor_tabs = memnew( Tabs );
|
||||
main_editor_tabs->connect("tab_changed",this,"_editor_select");
|
||||
main_editor_tabs->set_tab_close_display_policy(Tabs::SHOW_NEVER);
|
||||
HBoxContainer *srth = memnew( HBoxContainer );
|
||||
srt->add_child( srth );
|
||||
Control *tec = memnew( Control );
|
||||
|
|
|
@ -501,6 +501,7 @@ class EditorNode : public Node {
|
|||
void _dock_split_dragged(int ofs);
|
||||
void _dock_popup_exit();
|
||||
void _scene_tab_changed(int p_tab);
|
||||
void _scene_tab_closed(int p_tab);
|
||||
void _scene_tab_script_edited(int p_tab);
|
||||
|
||||
Dictionary _get_main_scene_state();
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -474,6 +474,7 @@ void EditorSettings::_load_defaults() {
|
|||
set("scenetree_editor/duplicate_node_name_num_separator",0);
|
||||
hints["scenetree_editor/duplicate_node_name_num_separator"]=PropertyInfo(Variant::INT,"scenetree_editor/duplicate_node_name_num_separator",PROPERTY_HINT_ENUM, "None,Space,Underscore,Dash");
|
||||
|
||||
set("gridmap_editor/pick_distance", 5000.0);
|
||||
|
||||
set("3d_editor/default_fov",45.0);
|
||||
set("3d_editor/default_z_near",0.1);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -144,6 +144,9 @@ void CanvasItemEditor::_unhandled_key_input(const InputEvent& p_ev) {
|
|||
|
||||
if (!is_visible())
|
||||
return;
|
||||
if (p_ev.key.mod.control)
|
||||
// prevent to change tool mode when control key is pressed
|
||||
return;
|
||||
if (p_ev.key.pressed && !p_ev.key.echo && p_ev.key.scancode==KEY_Q)
|
||||
_tool_select(TOOL_SELECT);
|
||||
if (p_ev.key.pressed && !p_ev.key.echo && p_ev.key.scancode==KEY_W)
|
||||
|
@ -1281,7 +1284,7 @@ void CanvasItemEditor::_viewport_input_event(const InputEvent& p_event) {
|
|||
|
||||
if (p_event.type==InputEvent::MOUSE_MOTION) {
|
||||
|
||||
if (!viewport->has_focus())
|
||||
if (!viewport->has_focus() && (!get_focus_owner() || !get_focus_owner()->is_text_field()))
|
||||
viewport->call_deferred("grab_focus");
|
||||
|
||||
const InputEventMouseMotion &m=p_event.mouse_motion;
|
||||
|
|
|
@ -25,7 +25,7 @@ Ref<Texture> EditorTexturePreviewPlugin::generate(const RES& p_from) {
|
|||
if (img.is_compressed()) {
|
||||
if (img.decompress()!=OK)
|
||||
return Ref<Texture>();
|
||||
} else if (img.get_format()!=Image::FORMAT_RGB && img.get_format()!=Image::FORMAT_RGB) {
|
||||
} else if (img.get_format()!=Image::FORMAT_RGB && img.get_format()!=Image::FORMAT_RGBA) {
|
||||
img.convert(Image::FORMAT_RGBA);
|
||||
}
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue