diff options
29 files changed, 529 insertions, 122 deletions
diff --git a/doc/classes/CylinderShape.xml b/doc/classes/CylinderShape.xml new file mode 100644 index 0000000000..a63cc8831e --- /dev/null +++ b/doc/classes/CylinderShape.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="CylinderShape" inherits="Shape" category="Core" version="3.1"> + <brief_description> + Cylinder shape for collisions. + </brief_description> + <description> + Cylinder shape for collisions. + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <members> + <member name="height" type="float" setter="set_height" getter="get_height"> + The cylinder's height. + </member> + <member name="radius" type="float" setter="set_radius" getter="get_radius"> + The cylinder's radius. + </member> + </members> + <constants> + </constants> +</class> diff --git a/doc/classes/PhysicsServer.xml b/doc/classes/PhysicsServer.xml index 6efbfdb519..d45a3adc9c 100644 --- a/doc/classes/PhysicsServer.xml +++ b/doc/classes/PhysicsServer.xml @@ -1413,16 +1413,19 @@ <constant name="SHAPE_CAPSULE" value="4" enum="ShapeType"> The [Shape] is a [CapsuleShape]. </constant> - <constant name="SHAPE_CONVEX_POLYGON" value="5" enum="ShapeType"> + <constant name="SHAPE_CYLINDER" value="5" enum="ShapeType"> + The [Shape] is a [CylinderShape]. + </constant> + <constant name="SHAPE_CONVEX_POLYGON" value="6" enum="ShapeType"> The [Shape] is a [ConvexPolygonShape]. </constant> - <constant name="SHAPE_CONCAVE_POLYGON" value="6" enum="ShapeType"> + <constant name="SHAPE_CONCAVE_POLYGON" value="7" enum="ShapeType"> The [Shape] is a [ConcavePolygonShape]. </constant> - <constant name="SHAPE_HEIGHTMAP" value="7" enum="ShapeType"> + <constant name="SHAPE_HEIGHTMAP" value="8" enum="ShapeType"> The [Shape] is a [HeightMapShape]. </constant> - <constant name="SHAPE_CUSTOM" value="8" enum="ShapeType"> + <constant name="SHAPE_CUSTOM" value="9" enum="ShapeType"> This constant is used internally by the engine. Any attempt to create this kind of shape results in an error. </constant> <constant name="AREA_PARAM_GRAVITY" value="0" enum="AreaParameter"> diff --git a/doc/classes/PopupMenu.xml b/doc/classes/PopupMenu.xml index 89d8c43c00..83d1246e2a 100644 --- a/doc/classes/PopupMenu.xml +++ b/doc/classes/PopupMenu.xml @@ -507,6 +507,9 @@ </member> <member name="hide_on_state_item_selection" type="bool" setter="set_hide_on_state_item_selection" getter="is_hide_on_state_item_selection"> </member> + <member name="submenu_popup_delay" type="real" setter="set_submenu_popup_delay" getter="get_submenu_popup_delay"> + Sets the delay time for the submenu item to popup on mouse hovering. If the popup menu is added as a child of another (acting as a submenu), it will inherit the delay time of the parent menu item. Default value: [code]0.3[/code] seconds. + </member> </members> <signals> <signal name="id_focused"> diff --git a/drivers/coreaudio/audio_driver_coreaudio.cpp b/drivers/coreaudio/audio_driver_coreaudio.cpp index 6e451eabcd..ef7858b4ca 100644 --- a/drivers/coreaudio/audio_driver_coreaudio.cpp +++ b/drivers/coreaudio/audio_driver_coreaudio.cpp @@ -52,7 +52,9 @@ OSStatus AudioDriverCoreAudio::output_device_address_cb(AudioObjectID inObjectID } #endif -Error AudioDriverCoreAudio::init_device() { +Error AudioDriverCoreAudio::init() { + mutex = Mutex::create(); + AudioComponentDescription desc; zeromem(&desc, sizeof(desc)); desc.componentType = kAudioUnitType_Output; @@ -69,6 +71,16 @@ Error AudioDriverCoreAudio::init_device() { OSStatus result = AudioComponentInstanceNew(comp, &audio_unit); ERR_FAIL_COND_V(result != noErr, FAILED); +#ifdef OSX_ENABLED + AudioObjectPropertyAddress prop; + prop.mSelector = kAudioHardwarePropertyDefaultOutputDevice; + prop.mScope = kAudioObjectPropertyScopeGlobal; + prop.mElement = kAudioObjectPropertyElementMaster; + + result = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &prop, &output_device_address_cb, this); + ERR_FAIL_COND_V(result != noErr, FAILED); +#endif + AudioStreamBasicDescription strdesc; zeromem(&strdesc, sizeof(strdesc)); @@ -135,42 +147,6 @@ Error AudioDriverCoreAudio::init_device() { return OK; } -Error AudioDriverCoreAudio::finish_device() { - OSStatus result; - - if (active) { - result = AudioOutputUnitStop(audio_unit); - ERR_FAIL_COND_V(result != noErr, FAILED); - - active = false; - } - - result = AudioUnitUninitialize(audio_unit); - ERR_FAIL_COND_V(result != noErr, FAILED); - - return OK; -} - -Error AudioDriverCoreAudio::init() { - OSStatus result; - - mutex = Mutex::create(); - active = false; - channels = 2; - -#ifdef OSX_ENABLED - AudioObjectPropertyAddress prop; - prop.mSelector = kAudioHardwarePropertyDefaultOutputDevice; - prop.mScope = kAudioObjectPropertyScopeGlobal; - prop.mElement = kAudioObjectPropertyElementMaster; - - result = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &prop, &output_device_address_cb, this); - ERR_FAIL_COND_V(result != noErr, FAILED); -#endif - - return init_device(); -}; - OSStatus AudioDriverCoreAudio::output_callback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, @@ -370,6 +346,7 @@ void AudioDriverCoreAudio::set_device(String device) { } if (!found) { + // If we haven't found the desired device get the system default one UInt32 size = sizeof(AudioDeviceID); AudioObjectPropertyAddress property = { kAudioHardwarePropertyDefaultOutputDevice, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster }; @@ -406,7 +383,28 @@ bool AudioDriverCoreAudio::try_lock() { void AudioDriverCoreAudio::finish() { OSStatus result; - finish_device(); + lock(); + + AURenderCallbackStruct callback; + zeromem(&callback, sizeof(AURenderCallbackStruct)); + result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, kOutputBus, &callback, sizeof(callback)); + if (result != noErr) { + ERR_PRINT("AudioUnitSetProperty failed"); + } + + if (active) { + result = AudioOutputUnitStop(audio_unit); + if (result != noErr) { + ERR_PRINT("AudioOutputUnitStop failed"); + } + + active = false; + } + + result = AudioUnitUninitialize(audio_unit); + if (result != noErr) { + ERR_PRINT("AudioUnitUninitialize failed"); + } #ifdef OSX_ENABLED AudioObjectPropertyAddress prop; @@ -420,13 +418,13 @@ void AudioDriverCoreAudio::finish() { } #endif - AURenderCallbackStruct callback; - zeromem(&callback, sizeof(AURenderCallbackStruct)); - result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, kOutputBus, &callback, sizeof(callback)); + result = AudioComponentInstanceDispose(audio_unit); if (result != noErr) { - ERR_PRINT("AudioUnitSetProperty failed"); + ERR_PRINT("AudioComponentInstanceDispose failed"); } + unlock(); + if (mutex) { memdelete(mutex); mutex = NULL; diff --git a/drivers/coreaudio/audio_driver_coreaudio.h b/drivers/coreaudio/audio_driver_coreaudio.h index c44e225521..99c910498e 100644 --- a/drivers/coreaudio/audio_driver_coreaudio.h +++ b/drivers/coreaudio/audio_driver_coreaudio.h @@ -68,9 +68,6 @@ class AudioDriverCoreAudio : public AudioDriver { UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData); - Error init_device(); - Error finish_device(); - public: const char *get_name() const { return "CoreAudio"; diff --git a/drivers/gles2/rasterizer_canvas_gles2.cpp b/drivers/gles2/rasterizer_canvas_gles2.cpp index cc8e3277b9..d5232a6511 100644 --- a/drivers/gles2/rasterizer_canvas_gles2.cpp +++ b/drivers/gles2/rasterizer_canvas_gles2.cpp @@ -733,6 +733,9 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur int w = current_clip->final_clip_rect.size.x; int h = current_clip->final_clip_rect.size.y; + if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP]) + y = current_clip->final_clip_rect.position.y; + glScissor(x, y, w, h); reclip = false; @@ -821,7 +824,10 @@ void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, cons if (current_clip) { glEnable(GL_SCISSOR_TEST); - glScissor(current_clip->final_clip_rect.position.x, (rt_size.height - (current_clip->final_clip_rect.position.y + current_clip->final_clip_rect.size.height)), current_clip->final_clip_rect.size.width, current_clip->final_clip_rect.size.height); + int y = storage->frame.current_rt->height - (current_clip->final_clip_rect.position.y + current_clip->final_clip_rect.size.y); + if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP]) + y = current_clip->final_clip_rect.position.y; + glScissor(current_clip->final_clip_rect.position.x, y, current_clip->final_clip_rect.size.width, current_clip->final_clip_rect.size.height); } else { glDisable(GL_SCISSOR_TEST); } @@ -969,7 +975,10 @@ void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, cons if (reclip) { glEnable(GL_SCISSOR_TEST); - glScissor(current_clip->final_clip_rect.position.x, (rt_size.height - (current_clip->final_clip_rect.position.y + current_clip->final_clip_rect.size.height)), current_clip->final_clip_rect.size.width, current_clip->final_clip_rect.size.height); + int y = storage->frame.current_rt->height - (current_clip->final_clip_rect.position.y + current_clip->final_clip_rect.size.y); + if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP]) + y = current_clip->final_clip_rect.position.y; + glScissor(current_clip->final_clip_rect.position.x, y, current_clip->final_clip_rect.size.width, current_clip->final_clip_rect.size.height); } p_item_list = p_item_list->next; diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp index c2377e0c3e..f214943bcf 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.cpp +++ b/drivers/gles3/rasterizer_canvas_gles3.cpp @@ -1000,13 +1000,11 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur glEnable(GL_SCISSOR_TEST); //glScissor(viewport.x+current_clip->final_clip_rect.pos.x,viewport.y+ (viewport.height-(current_clip->final_clip_rect.pos.y+current_clip->final_clip_rect.size.height)), //current_clip->final_clip_rect.size.width,current_clip->final_clip_rect.size.height); - - int x = current_clip->final_clip_rect.position.x; int y = storage->frame.current_rt->height - (current_clip->final_clip_rect.position.y + current_clip->final_clip_rect.size.y); - int w = current_clip->final_clip_rect.size.x; - int h = current_clip->final_clip_rect.size.y; + if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP]) + y = current_clip->final_clip_rect.position.y; - glScissor(x, y, w, h); + glScissor(current_clip->final_clip_rect.position.x, y, current_clip->final_clip_rect.size.x, current_clip->final_clip_rect.size.y); reclip = false; } @@ -1141,7 +1139,11 @@ void RasterizerCanvasGLES3::canvas_render_items(Item *p_item_list, int p_z, cons if (current_clip) { glEnable(GL_SCISSOR_TEST); - glScissor(current_clip->final_clip_rect.position.x, (rt_size.height - (current_clip->final_clip_rect.position.y + current_clip->final_clip_rect.size.height)), current_clip->final_clip_rect.size.width, current_clip->final_clip_rect.size.height); + int y = storage->frame.current_rt->height - (current_clip->final_clip_rect.position.y + current_clip->final_clip_rect.size.y); + if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP]) + y = current_clip->final_clip_rect.position.y; + + glScissor(current_clip->final_clip_rect.position.x, y, current_clip->final_clip_rect.size.x, current_clip->final_clip_rect.size.y); } else { @@ -1518,7 +1520,10 @@ void RasterizerCanvasGLES3::canvas_render_items(Item *p_item_list, int p_z, cons if (reclip) { glEnable(GL_SCISSOR_TEST); - glScissor(current_clip->final_clip_rect.position.x, (rt_size.height - (current_clip->final_clip_rect.position.y + current_clip->final_clip_rect.size.height)), current_clip->final_clip_rect.size.width, current_clip->final_clip_rect.size.height); + int y = storage->frame.current_rt->height - (current_clip->final_clip_rect.position.y + current_clip->final_clip_rect.size.y); + if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP]) + y = current_clip->final_clip_rect.position.y; + glScissor(current_clip->final_clip_rect.position.x, y, current_clip->final_clip_rect.size.width, current_clip->final_clip_rect.size.height); } p_item_list = p_item_list->next; diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index 191c587d98..4a3ebf7a7c 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -3862,7 +3862,7 @@ void RasterizerStorageGLES3::multimesh_allocate(RID p_multimesh, int p_instances multimesh->data.resize(format_floats * p_instances); - for (int i = 0; i < p_instances; i += format_floats) { + for (int i = 0; i < p_instances * format_floats; i += format_floats) { int color_from = 0; int custom_data_from = 0; diff --git a/editor/editor_spin_slider.cpp b/editor/editor_spin_slider.cpp index f212b60c8c..c7a33de3f1 100644 --- a/editor/editor_spin_slider.cpp +++ b/editor/editor_spin_slider.cpp @@ -162,7 +162,7 @@ void EditorSpinSlider::_notification(int p_what) { draw_style_box(sb, Rect2(Vector2(), get_size())); Ref<Font> font = get_font("font", "LineEdit"); - int avail_width = get_size().width - sb->get_minimum_size().width - sb->get_minimum_size().width; + int avail_width = get_size().width - sb->get_minimum_size().width; avail_width -= font->get_string_size(label).width; Ref<Texture> updown = get_icon("updown", "SpinBox"); diff --git a/editor/icons/icon_cylinder_shape.svg b/editor/icons/icon_cylinder_shape.svg new file mode 100644 index 0000000000..abda347ec5 --- /dev/null +++ b/editor/icons/icon_cylinder_shape.svg @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg width="16" height="16" version="1.1" viewBox="0 0 14.999999 14.999999" xmlns="http://www.w3.org/2000/svg"> +<rect fill="#68b6ff" width="13.171325" height="7.6993308" x="0.89037383" y="3.6879442"/> +<ellipse fill="#a2d2ff" cx="7.4772978" cy="3.7229116" rx="6.5864792" ry="2.820821"/> +<ellipse fill="#68b6ff" cx="7.4746876" cy="11.34481" rx="6.5864792" ry="2.8208208"/> +</svg> diff --git a/editor/spatial_editor_gizmos.cpp b/editor/spatial_editor_gizmos.cpp index 17f3b4886e..3b0ac8864a 100644 --- a/editor/spatial_editor_gizmos.cpp +++ b/editor/spatial_editor_gizmos.cpp @@ -36,6 +36,7 @@ #include "scene/resources/box_shape.h" #include "scene/resources/capsule_shape.h" #include "scene/resources/convex_polygon_shape.h" +#include "scene/resources/cylinder_shape.h" #include "scene/resources/plane_shape.h" #include "scene/resources/primitive_meshes.h" #include "scene/resources/ray_shape.h" @@ -1934,6 +1935,11 @@ String CollisionShapeSpatialGizmo::get_handle_name(int p_idx) const { return p_idx == 0 ? "Radius" : "Height"; } + if (Object::cast_to<CylinderShape>(*s)) { + + return p_idx == 0 ? "Radius" : "Height"; + } + if (Object::cast_to<RayShape>(*s)) { return "Length"; @@ -1965,6 +1971,12 @@ Variant CollisionShapeSpatialGizmo::get_handle_value(int p_idx) const { return p_idx == 0 ? cs->get_radius() : cs->get_height(); } + if (Object::cast_to<CylinderShape>(*s)) { + + Ref<CylinderShape> cs = s; + return p_idx == 0 ? cs->get_radius() : cs->get_height(); + } + if (Object::cast_to<RayShape>(*s)) { Ref<RayShape> cs = s; @@ -2045,6 +2057,24 @@ void CollisionShapeSpatialGizmo::set_handle(int p_idx, Camera *p_camera, const P else if (p_idx == 1) cs->set_height(d * 2.0); } + + if (Object::cast_to<CylinderShape>(*s)) { + + Vector3 axis; + axis[p_idx == 0 ? 0 : 1] = 1.0; + Ref<CylinderShape> cs = s; + Vector3 ra, rb; + Geometry::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb); + float d = axis.dot(ra); + + if (d < 0.001) + d = 0.001; + + if (p_idx == 0) + cs->set_radius(d); + else if (p_idx == 1) + cs->set_height(d * 2.0); + } } void CollisionShapeSpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) { Ref<Shape> s = cs->get_shape(); @@ -2106,6 +2136,31 @@ void CollisionShapeSpatialGizmo::commit_handle(int p_idx, const Variant &p_resto ur->commit_action(); } + if (Object::cast_to<CylinderShape>(*s)) { + + Ref<CylinderShape> ss = s; + if (p_cancel) { + if (p_idx == 0) + ss->set_radius(p_restore); + else + ss->set_height(p_restore); + return; + } + + UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo(); + if (p_idx == 0) { + ur->create_action(TTR("Change Cylinder Shape Radius")); + ur->add_do_method(ss.ptr(), "set_radius", ss->get_radius()); + ur->add_undo_method(ss.ptr(), "set_radius", p_restore); + } else { + ur->create_action(TTR("Change Cylinder Shape Height")); + ur->add_do_method(ss.ptr(), "set_height", ss->get_height()); + ur->add_undo_method(ss.ptr(), "set_height", p_restore); + } + + ur->commit_action(); + } + if (Object::cast_to<RayShape>(*s)) { Ref<RayShape> ss = s; @@ -2282,6 +2337,67 @@ void CollisionShapeSpatialGizmo::redraw() { add_handles(handles); } + if (Object::cast_to<CylinderShape>(*s)) { + + Ref<CylinderShape> cs = s; + float radius = cs->get_radius(); + float height = cs->get_height(); + + Vector<Vector3> points; + + Vector3 d(0, height * 0.5, 0); + for (int i = 0; i < 360; i++) { + + float ra = Math::deg2rad((float)i); + float rb = Math::deg2rad((float)i + 1); + Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * radius; + Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * radius; + + points.push_back(Vector3(a.x, 0, a.y) + d); + points.push_back(Vector3(b.x, 0, b.y) + d); + + points.push_back(Vector3(a.x, 0, a.y) - d); + points.push_back(Vector3(b.x, 0, b.y) - d); + + if (i % 90 == 0) { + + points.push_back(Vector3(a.x, 0, a.y) + d); + points.push_back(Vector3(a.x, 0, a.y) - d); + } + } + + add_lines(points, material); + + Vector<Vector3> collision_segments; + + for (int i = 0; i < 64; i++) { + + float ra = i * Math_PI * 2.0 / 64.0; + float rb = (i + 1) * Math_PI * 2.0 / 64.0; + Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * radius; + Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * radius; + + collision_segments.push_back(Vector3(a.x, 0, a.y) + d); + collision_segments.push_back(Vector3(b.x, 0, b.y) + d); + + collision_segments.push_back(Vector3(a.x, 0, a.y) - d); + collision_segments.push_back(Vector3(b.x, 0, b.y) - d); + + if (i % 16 == 0) { + + collision_segments.push_back(Vector3(a.x, 0, a.y) + d); + collision_segments.push_back(Vector3(a.x, 0, a.y) - d); + } + } + + add_collision_segments(collision_segments); + + Vector<Vector3> handles; + handles.push_back(Vector3(cs->get_radius(), 0, 0)); + handles.push_back(Vector3(0, cs->get_height() * 0.5, 0)); + add_handles(handles); + } + if (Object::cast_to<PlaneShape>(*s)) { Ref<PlaneShape> ps = s; diff --git a/misc/dist/ios_xcode/godot_ios/godot_ios-Info.plist b/misc/dist/ios_xcode/godot_ios/godot_ios-Info.plist index 70932c1943..6907ae4a9d 100644 --- a/misc/dist/ios_xcode/godot_ios/godot_ios-Info.plist +++ b/misc/dist/ios_xcode/godot_ios/godot_ios-Info.plist @@ -41,11 +41,15 @@ <array> <string>UIInterfaceOrientationLandscapeLeft</string> <string>UIInterfaceOrientationLandscapeRight</string> + <string>UIInterfaceOrientationPortrait</string> + <string>UIInterfaceOrientationPortraitUpsideDown</string> </array> <key>UISupportedInterfaceOrientations~ipad</key> <array> <string>UIInterfaceOrientationLandscapeLeft</string> <string>UIInterfaceOrientationLandscapeRight</string> + <string>UIInterfaceOrientationPortrait</string> + <string>UIInterfaceOrientationPortraitUpsideDown</string> </array> $additional_plist_content </dict> diff --git a/modules/bullet/bullet_physics_server.cpp b/modules/bullet/bullet_physics_server.cpp index 6246a295ec..54431f93f1 100644 --- a/modules/bullet/bullet_physics_server.cpp +++ b/modules/bullet/bullet_physics_server.cpp @@ -113,6 +113,10 @@ RID BulletPhysicsServer::shape_create(ShapeType p_shape) { shape = bulletnew(CapsuleShapeBullet); } break; + case SHAPE_CYLINDER: { + + shape = bulletnew(CylinderShapeBullet); + } break; case SHAPE_CONVEX_POLYGON: { shape = bulletnew(ConvexPolygonShapeBullet); diff --git a/modules/bullet/rigid_body_bullet.cpp b/modules/bullet/rigid_body_bullet.cpp index 2494063c22..2fc96a77b5 100644 --- a/modules/bullet/rigid_body_bullet.cpp +++ b/modules/bullet/rigid_body_bullet.cpp @@ -226,6 +226,7 @@ void RigidBodyBullet::KinematicUtilities::copyAllOwnerShapes() { case PhysicsServer::SHAPE_SPHERE: case PhysicsServer::SHAPE_BOX: case PhysicsServer::SHAPE_CAPSULE: + case PhysicsServer::SHAPE_CYLINDER: case PhysicsServer::SHAPE_CONVEX_POLYGON: case PhysicsServer::SHAPE_RAY: { shapes[i].shape = static_cast<btConvexShape *>(shape_wrapper->shape->create_bt_shape(owner_scale * shape_wrapper->scale, safe_margin)); diff --git a/modules/bullet/shape_bullet.cpp b/modules/bullet/shape_bullet.cpp index 76d9614465..92e7c2df98 100644 --- a/modules/bullet/shape_bullet.cpp +++ b/modules/bullet/shape_bullet.cpp @@ -113,6 +113,10 @@ btCapsuleShapeZ *ShapeBullet::create_shape_capsule(btScalar radius, btScalar hei return bulletnew(btCapsuleShapeZ(radius, height)); } +btCylinderShape *ShapeBullet::create_shape_cylinder(btScalar radius, btScalar height) { + return bulletnew(btCylinderShape(btVector3(radius, height / 2.0, radius))); +} + btConvexPointCloudShape *ShapeBullet::create_shape_convex(btAlignedObjectArray<btVector3> &p_vertices, const btVector3 &p_local_scaling) { return bulletnew(btConvexPointCloudShape(&p_vertices[0], p_vertices.size(), p_local_scaling)); } @@ -254,6 +258,39 @@ btCollisionShape *CapsuleShapeBullet::create_bt_shape(const btVector3 &p_implici return prepare(ShapeBullet::create_shape_capsule(radius * p_implicit_scale[0] + p_margin, height * p_implicit_scale[1] + p_margin)); } +/* Cylinder */ + +CylinderShapeBullet::CylinderShapeBullet() : + ShapeBullet() {} + +void CylinderShapeBullet::set_data(const Variant &p_data) { + Dictionary d = p_data; + ERR_FAIL_COND(!d.has("radius")); + ERR_FAIL_COND(!d.has("height")); + setup(d["height"], d["radius"]); +} + +Variant CylinderShapeBullet::get_data() const { + Dictionary d; + d["radius"] = radius; + d["height"] = height; + return d; +} + +PhysicsServer::ShapeType CylinderShapeBullet::get_type() const { + return PhysicsServer::SHAPE_CYLINDER; +} + +void CylinderShapeBullet::setup(real_t p_height, real_t p_radius) { + radius = p_radius; + height = p_height; + notifyShapeChanged(); +} + +btCollisionShape *CylinderShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin) { + return prepare(ShapeBullet::create_shape_cylinder(radius * p_implicit_scale[0] + p_margin, height * p_implicit_scale[1] + p_margin)); +} + /* Convex polygon */ ConvexPolygonShapeBullet::ConvexPolygonShapeBullet() : diff --git a/modules/bullet/shape_bullet.h b/modules/bullet/shape_bullet.h index abeea0f9ce..16a5ac1fc6 100644 --- a/modules/bullet/shape_bullet.h +++ b/modules/bullet/shape_bullet.h @@ -82,6 +82,7 @@ public: static class btSphereShape *create_shape_sphere(btScalar radius); static class btBoxShape *create_shape_box(const btVector3 &boxHalfExtents); static class btCapsuleShapeZ *create_shape_capsule(btScalar radius, btScalar height); + static class btCylinderShape *create_shape_cylinder(btScalar radius, btScalar height); /// IMPORTANT: Remember to delete the shape interface by calling: delete my_shape->getMeshInterface(); static class btConvexPointCloudShape *create_shape_convex(btAlignedObjectArray<btVector3> &p_vertices, const btVector3 &p_local_scaling = btVector3(1, 1, 1)); static class btScaledBvhTriangleMeshShape *create_shape_concave(btBvhTriangleMeshShape *p_mesh_shape, const btVector3 &p_local_scaling = btVector3(1, 1, 1)); @@ -158,6 +159,25 @@ private: void setup(real_t p_height, real_t p_radius); }; +class CylinderShapeBullet : public ShapeBullet { + + real_t height; + real_t radius; + +public: + CylinderShapeBullet(); + + _FORCE_INLINE_ real_t get_height() { return height; } + _FORCE_INLINE_ real_t get_radius() { return radius; } + virtual void set_data(const Variant &p_data); + virtual Variant get_data() const; + virtual PhysicsServer::ShapeType get_type() const; + virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin = 0); + +private: + void setup(real_t p_height, real_t p_radius); +}; + class ConvexPolygonShapeBullet : public ShapeBullet { public: diff --git a/platform/iphone/os_iphone.cpp b/platform/iphone/os_iphone.cpp index f618c80a77..4caf4bd933 100644 --- a/platform/iphone/os_iphone.cpp +++ b/platform/iphone/os_iphone.cpp @@ -64,11 +64,6 @@ OSIPhone *OSIPhone::get_singleton() { return (OSIPhone *)OS::get_singleton(); }; -uint8_t OSIPhone::get_orientations() const { - - return supported_orientations; -}; - extern int gl_view_base_fb; // from gl_view.mm void OSIPhone::set_data_dir(String p_dir) { @@ -100,12 +95,6 @@ void OSIPhone::initialize_core() { Error OSIPhone::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) { - supported_orientations = 0; - supported_orientations |= ((GLOBAL_DEF("video_mode/allow_horizontal", true) ? 1 : 0) << LandscapeLeft); - supported_orientations |= ((GLOBAL_DEF("video_mode/allow_horizontal_flipped", false) ? 1 : 0) << LandscapeRight); - supported_orientations |= ((GLOBAL_DEF("video_mode/allow_vertical", false) ? 1 : 0) << PortraitDown); - supported_orientations |= ((GLOBAL_DEF("video_mode/allow_vertical_flipped", false) ? 1 : 0) << PortraitUp); - RasterizerGLES3::register_config(); RasterizerGLES3::make_current(); diff --git a/platform/iphone/os_iphone.h b/platform/iphone/os_iphone.h index 7d73a6fe5c..8dc1ae6dc2 100644 --- a/platform/iphone/os_iphone.h +++ b/platform/iphone/os_iphone.h @@ -47,14 +47,6 @@ class OSIPhone : public OS_Unix { -public: - enum Orientations { - PortraitDown, - PortraitUp, - LandscapeLeft, - LandscapeRight, - }; - private: enum { MAX_MOUSE_COUNT = 8, @@ -64,8 +56,6 @@ private: static HashMap<String, void *> dynamic_symbol_lookup_table; friend void register_dynamic_symbol(char *name, void *address); - uint8_t supported_orientations; - VisualServer *visual_server; AudioDriverCoreAudio audio_driver; diff --git a/platform/iphone/view_controller.mm b/platform/iphone/view_controller.mm index cdaae0cb81..f75f0fd812 100644 --- a/platform/iphone/view_controller.mm +++ b/platform/iphone/view_controller.mm @@ -83,51 +83,36 @@ int add_cmdline(int p_argc, char **p_args) { printf("*********** did receive memory warning!\n"); }; -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)p_orientation { - - if (/*OSIPhone::get_singleton() == NULL*/ TRUE) { - - printf("checking on info.plist\n"); - NSArray *arr = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"UISupportedInterfaceOrientations"]; - switch (p_orientation) { - - case UIInterfaceOrientationLandscapeLeft: - return [arr indexOfObject:@"UIInterfaceOrientationLandscapeLeft"] != NSNotFound ? YES : NO; - - case UIInterfaceOrientationLandscapeRight: - return [arr indexOfObject:@"UIInterfaceOrientationLandscapeRight"] != NSNotFound ? YES : NO; - - case UIInterfaceOrientationPortrait: - return [arr indexOfObject:@"UIInterfaceOrientationPortrait"] != NSNotFound ? YES : NO; - - case UIInterfaceOrientationPortraitUpsideDown: - return [arr indexOfObject:@"UIInterfaceOrientationPortraitUpsideDown"] != NSNotFound ? YES : NO; - - default: - return NO; - } - }; - - uint8_t supported = OSIPhone::get_singleton()->get_orientations(); - switch (p_orientation) { - - case UIInterfaceOrientationLandscapeLeft: - return supported & (1 << OSIPhone::LandscapeLeft) ? YES : NO; - - case UIInterfaceOrientationLandscapeRight: - return supported & (1 << OSIPhone::LandscapeRight) ? YES : NO; - - case UIInterfaceOrientationPortrait: - return supported & (1 << OSIPhone::PortraitDown) ? YES : NO; - - case UIInterfaceOrientationPortraitUpsideDown: - return supported & (1 << OSIPhone::PortraitUp) ? YES : NO; - +- (BOOL)shouldAutorotate { + switch (OS::get_singleton()->get_screen_orientation()) { + case OS::SCREEN_SENSOR: + case OS::SCREEN_SENSOR_LANDSCAPE: + case OS::SCREEN_SENSOR_PORTRAIT: + return YES; default: return NO; } }; +- (UIInterfaceOrientationMask)supportedInterfaceOrientations { + switch (OS::get_singleton()->get_screen_orientation()) { + case OS::SCREEN_PORTRAIT: + return UIInterfaceOrientationMaskPortrait; + case OS::SCREEN_REVERSE_LANDSCAPE: + return UIInterfaceOrientationMaskLandscapeRight; + case OS::SCREEN_REVERSE_PORTRAIT: + return UIInterfaceOrientationMaskPortraitUpsideDown; + case OS::SCREEN_SENSOR_LANDSCAPE: + return UIInterfaceOrientationMaskLandscape; + case OS::SCREEN_SENSOR_PORTRAIT: + return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown; + case OS::SCREEN_SENSOR: + return UIInterfaceOrientationMaskAll; + case OS::SCREEN_LANDSCAPE: + return UIInterfaceOrientationMaskLandscapeLeft; + } +}; + - (BOOL)prefersStatusBarHidden { return YES; } diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp index 4dbcd6c609..507499a324 100644 --- a/scene/2d/audio_stream_player_2d.cpp +++ b/scene/2d/audio_stream_player_2d.cpp @@ -304,6 +304,11 @@ float AudioStreamPlayer2D::get_pitch_scale() const { void AudioStreamPlayer2D::play(float p_from_pos) { + if (!is_playing()) { + // Reset the prev_output_count if the stream is stopped + prev_output_count = 0; + } + if (stream_playback.is_valid()) { setplay = p_from_pos; output_ready = false; diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index 18e609c798..f5890fa2ee 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -398,6 +398,15 @@ void PopupMenu::_notification(int p_what) { switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + + PopupMenu *pm = Object::cast_to<PopupMenu>(get_parent()); + if (pm) { + // Inherit submenu's popup delay time from parent menu + float pm_delay = pm->get_submenu_popup_delay(); + set_submenu_popup_delay(pm_delay); + } + } break; case NOTIFICATION_TRANSLATION_CHANGED: { for (int i = 0; i < items.size(); i++) { @@ -1201,6 +1210,19 @@ bool PopupMenu::is_hide_on_multistate_item_selection() const { return hide_on_multistate_item_selection; } +void PopupMenu::set_submenu_popup_delay(float p_time) { + + if (p_time <= 0) + p_time = 0.01; + + submenu_timer->set_wait_time(p_time); +} + +float PopupMenu::get_submenu_popup_delay() const { + + return submenu_timer->get_wait_time(); +} + String PopupMenu::get_tooltip(const Point2 &p_pos) const { int over = _get_mouse_over(p_pos); @@ -1303,12 +1325,15 @@ void PopupMenu::_bind_methods() { ClassDB::bind_method(D_METHOD("set_hide_on_state_item_selection", "enable"), &PopupMenu::set_hide_on_multistate_item_selection); ClassDB::bind_method(D_METHOD("is_hide_on_state_item_selection"), &PopupMenu::is_hide_on_multistate_item_selection); + ClassDB::bind_method(D_METHOD("set_submenu_popup_delay", "seconds"), &PopupMenu::set_submenu_popup_delay); + ClassDB::bind_method(D_METHOD("get_submenu_popup_delay"), &PopupMenu::get_submenu_popup_delay); ClassDB::bind_method(D_METHOD("_submenu_timeout"), &PopupMenu::_submenu_timeout); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "items", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_items", "_get_items"); ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "hide_on_item_selection"), "set_hide_on_item_selection", "is_hide_on_item_selection"); ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "hide_on_checkable_item_selection"), "set_hide_on_checkable_item_selection", "is_hide_on_checkable_item_selection"); ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "hide_on_state_item_selection"), "set_hide_on_state_item_selection", "is_hide_on_state_item_selection"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "submenu_popup_delay"), "set_submenu_popup_delay", "get_submenu_popup_delay"); ADD_SIGNAL(MethodInfo("id_pressed", PropertyInfo(Variant::INT, "ID"))); ADD_SIGNAL(MethodInfo("id_focused", PropertyInfo(Variant::INT, "ID"))); diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h index d3ee9be1c0..44f02a9d3d 100644 --- a/scene/gui/popup_menu.h +++ b/scene/gui/popup_menu.h @@ -202,6 +202,9 @@ public: void set_hide_on_multistate_item_selection(bool p_enabled); bool is_hide_on_multistate_item_selection() const; + void set_submenu_popup_delay(float p_time); + float get_submenu_popup_delay() const; + virtual void popup(const Rect2 &p_bounds = Rect2()); PopupMenu(); diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index f42c1e0982..a0bac09442 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -135,6 +135,7 @@ #include "scene/resources/concave_polygon_shape_2d.h" #include "scene/resources/convex_polygon_shape.h" #include "scene/resources/convex_polygon_shape_2d.h" +#include "scene/resources/cylinder_shape.h" #include "scene/resources/default_theme/default_theme.h" #include "scene/resources/dynamic_font.h" #include "scene/resources/dynamic_font_stb.h" @@ -541,6 +542,7 @@ void register_scene_types() { ClassDB::register_class<SphereShape>(); ClassDB::register_class<BoxShape>(); ClassDB::register_class<CapsuleShape>(); + ClassDB::register_class<CylinderShape>(); ClassDB::register_class<PlaneShape>(); ClassDB::register_class<ConvexPolygonShape>(); ClassDB::register_class<ConcavePolygonShape>(); diff --git a/scene/resources/cylinder_shape.cpp b/scene/resources/cylinder_shape.cpp new file mode 100644 index 0000000000..f760462d49 --- /dev/null +++ b/scene/resources/cylinder_shape.cpp @@ -0,0 +1,116 @@ +/*************************************************************************/ +/* cylinder_shape.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* 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 "cylinder_shape.h" +#include "servers/physics_server.h" + +Vector<Vector3> CylinderShape::_gen_debug_mesh_lines() { + + float radius = get_radius(); + float height = get_height(); + + Vector<Vector3> points; + + Vector3 d(0, height * 0.5, 0); + for (int i = 0; i < 360; i++) { + + float ra = Math::deg2rad((float)i); + float rb = Math::deg2rad((float)i + 1); + Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * radius; + Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * radius; + + points.push_back(Vector3(a.x, 0, a.y) + d); + points.push_back(Vector3(b.x, 0, b.y) + d); + + points.push_back(Vector3(a.x, 0, a.y) - d); + points.push_back(Vector3(b.x, 0, b.y) - d); + + if (i % 90 == 0) { + + points.push_back(Vector3(a.x, 0, a.y) + d); + points.push_back(Vector3(a.x, 0, a.y) - d); + } + } + + return points; +} + +void CylinderShape::_update_shape() { + + Dictionary d; + d["radius"] = radius; + d["height"] = height; + PhysicsServer::get_singleton()->shape_set_data(get_shape(), d); +} + +void CylinderShape::set_radius(float p_radius) { + + radius = p_radius; + _update_shape(); + notify_change_to_owners(); + _change_notify("radius"); +} + +float CylinderShape::get_radius() const { + + return radius; +} + +void CylinderShape::set_height(float p_height) { + + height = p_height; + _update_shape(); + notify_change_to_owners(); + _change_notify("height"); +} + +float CylinderShape::get_height() const { + + return height; +} + +void CylinderShape::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_radius", "radius"), &CylinderShape::set_radius); + ClassDB::bind_method(D_METHOD("get_radius"), &CylinderShape::get_radius); + ClassDB::bind_method(D_METHOD("set_height", "height"), &CylinderShape::set_height); + ClassDB::bind_method(D_METHOD("get_height"), &CylinderShape::get_height); + + ADD_PROPERTY(PropertyInfo(Variant::REAL, "radius", PROPERTY_HINT_RANGE, "0.01,4096,0.01"), "set_radius", "get_radius"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "height", PROPERTY_HINT_RANGE, "0.01,4096,0.01"), "set_height", "get_height"); +} + +CylinderShape::CylinderShape() : + Shape(PhysicsServer::get_singleton()->shape_create(PhysicsServer::SHAPE_CYLINDER)) { + + radius = 1.0; + height = 2.0; + _update_shape(); +} diff --git a/scene/resources/cylinder_shape.h b/scene/resources/cylinder_shape.h new file mode 100644 index 0000000000..f510758e91 --- /dev/null +++ b/scene/resources/cylinder_shape.h @@ -0,0 +1,57 @@ +/*************************************************************************/ +/* cylinder_shape.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef CYLINDER_SHAPE_H +#define CYLINDER_SHAPE_H + +#include "scene/resources/shape.h" + +class CylinderShape : public Shape { + + GDCLASS(CylinderShape, Shape); + float radius; + float height; + +protected: + static void _bind_methods(); + virtual void _update_shape(); + + virtual Vector<Vector3> _gen_debug_mesh_lines(); + +public: + void set_radius(float p_radius); + float get_radius() const; + void set_height(float p_height); + float get_height() const; + + CylinderShape(); +}; + +#endif // CYLINDER_SHAPE_H diff --git a/servers/physics/physics_server_sw.cpp b/servers/physics/physics_server_sw.cpp index f2dbb635f8..6c25ad43f9 100644 --- a/servers/physics/physics_server_sw.cpp +++ b/servers/physics/physics_server_sw.cpp @@ -65,6 +65,11 @@ RID PhysicsServerSW::shape_create(ShapeType p_shape) { shape = memnew(CapsuleShapeSW); } break; + case SHAPE_CYLINDER: { + + ERR_EXPLAIN("CylinderShape is not supported in GodotPhysics. Please switch to Bullet in the Project Settings."); + ERR_FAIL_V(RID()); + } break; case SHAPE_CONVEX_POLYGON: { shape = memnew(ConvexPolygonShapeSW); diff --git a/servers/physics_server.cpp b/servers/physics_server.cpp index 82c4eb2e13..de173491b2 100644 --- a/servers/physics_server.cpp +++ b/servers/physics_server.cpp @@ -664,6 +664,7 @@ void PhysicsServer::_bind_methods() { BIND_ENUM_CONSTANT(SHAPE_SPHERE); BIND_ENUM_CONSTANT(SHAPE_BOX); BIND_ENUM_CONSTANT(SHAPE_CAPSULE); + BIND_ENUM_CONSTANT(SHAPE_CYLINDER); BIND_ENUM_CONSTANT(SHAPE_CONVEX_POLYGON); BIND_ENUM_CONSTANT(SHAPE_CONCAVE_POLYGON); BIND_ENUM_CONSTANT(SHAPE_HEIGHTMAP); diff --git a/servers/physics_server.h b/servers/physics_server.h index 6712bee8dc..8ecf17c0e6 100644 --- a/servers/physics_server.h +++ b/servers/physics_server.h @@ -228,6 +228,7 @@ public: SHAPE_SPHERE, ///< float:"radius" SHAPE_BOX, ///< vec3:"extents" SHAPE_CAPSULE, ///< dict( float:"radius", float:"height"):capsule + SHAPE_CYLINDER, ///< dict( float:"radius", float:"height"):cylinder SHAPE_CONVEX_POLYGON, ///< array of planes:"planes" SHAPE_CONCAVE_POLYGON, ///< vector3 array:"triangles" , or Dictionary with "indices" (int array) and "triangles" (Vector3 array) SHAPE_HEIGHTMAP, ///< dict( int:"width", int:"depth",float:"cell_size", float_array:"heights" diff --git a/servers/visual/visual_server_viewport.cpp b/servers/visual/visual_server_viewport.cpp index dcc270ca5e..dd6bc3cf26 100644 --- a/servers/visual/visual_server_viewport.cpp +++ b/servers/visual/visual_server_viewport.cpp @@ -268,7 +268,7 @@ void VisualServerViewport::draw_viewports() { ERR_CONTINUE(!vp->render_target.is_valid()); bool visible = vp->viewport_to_screen_rect != Rect2() || vp->update_mode == VS::VIEWPORT_UPDATE_ALWAYS || vp->update_mode == VS::VIEWPORT_UPDATE_ONCE || (vp->update_mode == VS::VIEWPORT_UPDATE_WHEN_VISIBLE && VSG::storage->render_target_was_used(vp->render_target)); - visible = visible && vp->size.x > 0 && vp->size.y > 0; + visible = visible && vp->size.x > 1 && vp->size.y > 1; if (!visible) continue; |