Esempio n. 1
0
    public override bool ForwardSpatialGuiInput(Camera camera, InputEvent @event)
    {
        if (!IsInstanceValid(path))
        {
            return(false);
        }
        Curve3D c = path.curve;

        if (!IsInstanceValid(c))
        {
            return(false);
        }
        Transform gt = path.GlobalTransform;
        Transform it = gt.AffineInverse();

        if (@event is InputEventMouseButton mb)
        {
            Vector2 mbPos = mb.Position;

            if (!mb.Pressed)
            {
                SetHandleClicked(false);
            }

            if (mb.Pressed && mb.ButtonIndex == (int)ButtonList.Left && (curveCreate.Pressed || (curveEdit.Pressed && mb.Control)))
            {
                //click into curve, break it down
                Vector3[] v3a             = c.Tessellate();
                int       idx             = 0;
                int       rc              = v3a.Length;
                int       closestSeg      = -1;
                Vector3   closestSegPoint = new Vector3();
                float     closest_d       = float.MaxValue;

                if (rc >= 2)
                {
                    if (camera.UnprojectPosition(gt.Xform(c.GetPointPosition(0))).DistanceTo(mbPos) < clickDist)
                    {
                        return(false); //nope, existing
                    }
                    for (int i = 0; i < c.GetPointCount() - 1; i++)
                    {
                        //find the offset and point index of the place to break up
                        int j = idx;
                        if (camera.UnprojectPosition(gt.Xform(c.GetPointPosition(i + 1))).DistanceTo(mbPos) < clickDist)
                        {
                            return(false); //nope, existing
                        }
                        while (j < rc && c.GetPointPosition(i + 1) != v3a[j])
                        {
                            Vector3 from  = v3a[j];
                            Vector3 to    = v3a[j + 1];
                            float   cdist = from.DistanceTo(to);
                            from = gt.Xform(from);
                            to   = gt.Xform(to);
                            if (cdist > 0)
                            {
                                Vector2[] s = new Vector2[2];
                                s[0] = camera.UnprojectPosition(from);
                                s[1] = camera.UnprojectPosition(to);
                                Vector2 inters = GetClosestPointToSegment2D(mbPos, s);
                                float   d      = inters.DistanceTo(mbPos);

                                if (d < 10 && d < closest_d)
                                {
                                    closest_d  = d;
                                    closestSeg = i;
                                    Vector3 ray_from = camera.ProjectRayOrigin(mbPos);
                                    Vector3 ray_dir  = camera.ProjectRayNormal(mbPos);

                                    Vector3 ra, rb;
                                    GetClosestPointsBetweenSegments(ray_from, ray_from + ray_dir * 4096, from, to, out ra, out rb);

                                    closestSegPoint = it.Xform(rb);
                                }
                            }
                            j++;
                        }
                        if (idx == j)
                        {
                            idx++; //force next
                        }
                        else
                        {
                            idx = j; //swap
                        }
                        if (j == rc)
                        {
                            break;
                        }
                    }
                }

                var ur = GetUndoRedo();
                if (closestSeg != -1)
                {
                    //subdivide

                    ur.CreateAction("Split Path");
                    ur.AddDoMethod(c, "add_point", closestSegPoint, new Vector3(), new Vector3(), closestSeg + 1);
                    ur.AddUndoMethod(c, "remove_point", closestSeg + 1);
                    ur.CommitAction();
                    return(true);
                }
                else
                {
                    Vector3 org;
                    if (c.GetPointCount() == 0)
                    {
                        org = path.Transform.origin;
                    }
                    else
                    {
                        org = gt.Xform(c.GetPointPosition(c.GetPointCount() - 1));
                    }
                    Plane p = new Plane();
                    p.Normal = camera.Transform.basis.GetColumn(2);
                    p.D      = p.Normal.Dot(org);
                    Vector3 ray_from = camera.ProjectRayOrigin(mbPos);
                    Vector3 ray_dir  = camera.ProjectRayNormal(mbPos);

                    Vector3?inters = p.IntersectRay(ray_from, ray_dir);
                    if (inters != null)
                    {
                        ur.CreateAction("Add Point to Curve");
                        ur.AddDoMethod(c, "add_point", it.Xform((Vector3)inters), new Vector3(), new Vector3(), -1);
                        ur.AddUndoMethod(c, "remove_point", c.GetPointCount());
                        ur.CommitAction();
                        return(true);
                    }

                    //add new at pos
                }
            }
            else if (mb.Pressed && ((mb.ButtonIndex == (int)ButtonList.Left && curveDel.Pressed) || (mb.ButtonIndex == (int)ButtonList.Right && curveEdit.Pressed)))
            {
                for (int i = 0; i < c.GetPointCount(); i++)
                {
                    float dist_to_p     = camera.UnprojectPosition(gt.Xform(c.GetPointPosition(i))).DistanceTo(mbPos);
                    float dist_to_p_out = camera.UnprojectPosition(gt.Xform(c.GetPointPosition(i) + c.GetPointOut(i))).DistanceTo(mbPos);
                    float dist_to_p_in  = camera.UnprojectPosition(gt.Xform(c.GetPointPosition(i) + c.GetPointIn(i))).DistanceTo(mbPos);

                    // Find the offset and point index of the place to break up.
                    // Also check for the control points.
                    var ur = GetUndoRedo();
                    if (dist_to_p < clickDist)
                    {
                        ur.CreateAction("Remove Path Point");
                        ur.AddDoMethod(c, "remove_point", i);
                        ur.AddUndoMethod(c, "add_point", c.GetPointPosition(i), c.GetPointIn(i), c.GetPointOut(i), i);
                        ur.CommitAction();
                        return(true);
                    }
                    else if (dist_to_p_out < clickDist)
                    {
                        ur.CreateAction(("Remove Out-Control Point"));
                        ur.AddDoMethod(c, "set_point_out", i, new Vector3());
                        ur.AddUndoMethod(c, "set_point_out", i, c.GetPointOut(i));
                        ur.CommitAction();
                        return(true);
                    }
                    else if (dist_to_p_in < clickDist)
                    {
                        ur.CreateAction(("Remove In-Control Point"));
                        ur.AddDoMethod(c, "set_point_in", i, new Vector3());
                        ur.AddUndoMethod(c, "set_point_in", i, c.GetPointOut(i));
                        ur.CommitAction();
                        return(true);
                    }
                }
            }
        }

        return(false);
    }
Esempio n. 2
0
    public override void Redraw( )
    {
        Clear();
        //GD.Print($"Redraw {GD.Randi()%100}");
        var     pathMaterial     = gizmoPlugin.GetMaterial("path_material", this);
        var     pathThinMaterial = gizmoPlugin.GetMaterial("path_thin_material", this);
        var     handlesMaterial  = gizmoPlugin.GetMaterial("handles", this);
        Curve3D c = path.curve;

        if (!IsInstanceValid(c))
        {
            GD.Print("Invalid curve");
            return;
        }

        var v3a = c.Tessellate();
        //PoolVector<Vector3> v3a=c.get_baked_points();

        int v3s = v3a.Length;

        if (v3s == 0)
        {
            return;
        }
        var v3p      = new Vector3[v3s * 2];
        int v3pCount = 0;

        // BUG: the following won't work when v3s, avoid drawing as a temporary workaround.
        for (int i = 0; i < v3s - 1; i++)
        {
            v3p = v3p.Add(ref v3pCount, v3a[i]);
            v3p = v3p.Add(ref v3pCount, v3a[i + 1]);
            //v3p.push_back(r[i]);
            //v3p.push_back(r[i]+Vector3(0,0.2,0));
        }

        if (v3pCount > 1)
        {
            v3p = v3p.Trim(ref v3pCount);
            AddLines((Vector3[])v3p.Clone(), pathMaterial);
            AddCollisionSegments((Vector3[])v3p.Clone());
        }

        if (plugin.path == path)
        {
            v3p = v3p.Clear(ref v3pCount, true);
            int pointCount      = c.GetPointCount();
            var handles         = new Vector3[pointCount];
            int handlesCount    = 0;
            var secHandles      = new Vector3[pointCount];
            int secHandlesCount = 0;

            for (int i = 0; i < pointCount; i++)
            {
                Vector3 p = c.GetPointPosition(i);
                handles = handles.Add(ref handlesCount, p);
                if (i > 0)
                {
                    v3p        = v3p.Add(ref v3pCount, p);
                    v3p        = v3p.Add(ref v3pCount, p + c.GetPointIn(i));
                    secHandles = secHandles.Add(ref secHandlesCount, p + c.GetPointIn(i));
                }

                if (i < pointCount - 1)
                {
                    v3p        = v3p.Add(ref v3pCount, p);
                    v3p        = v3p.Add(ref v3pCount, p + c.GetPointOut(i));
                    secHandles = secHandles.Add(ref secHandlesCount, p + c.GetPointOut(i));
                }
            }

            v3p        = v3p.Trim(ref v3pCount);
            handles    = handles.Trim(ref handlesCount);
            secHandles = secHandles.Trim(ref secHandlesCount);

            if (v3pCount > 1)
            {
                AddLines(v3p, pathThinMaterial);
            }
            if (handlesCount > 0)
            {
                AddHandles(handles, handlesMaterial);
            }
            if (secHandlesCount > 0)
            {
                AddHandles(secHandles, handlesMaterial, false, true);
            }
        }
    }
    public override void _PhysicsProcess(float delta)
    {
        base._PhysicsProcess(delta);

        var ribbonCurve = new Curve3D();

        // based on the gap between the two controllers, the control points move further away from the origin as the controllers are moved apart
        // without dynamically adjusting the control points, the curve would get straighter as the controllers moved apart.
        var gapWidth = (RightController.GlobalTransform.origin - LeftController.GlobalTransform.origin).Length();

        // control point locations are offset from the origin point (i.e not global coordinates)
        ribbonCurve.AddPoint(LeftController.RibbonGlobalOrigin,
                             AdjustControlPoint(LeftController.ControlPointInOffset, gapWidth),
                             AdjustControlPoint(LeftController.ControlPointOutOffset, gapWidth));

        ribbonCurve.AddPoint(RightController.RibbonGlobalOrigin,
                             AdjustControlPoint(RightController.ControlPointInOffset, gapWidth),
                             AdjustControlPoint(RightController.ControlPointOutOffset, gapWidth));


        // figure out a vector at 90 degrees to origin and control point. Vector will be used to offset one side of the ribbon, and give it a consistent width and orientation
        // need this for both controllers, and then gradually rotate from one to the other over the course of the ribbon length

        // Curve points pass through the centre of the Ribbon, as it appears on-screen.
        // To get the vertices to draw, need to offset from curvePoints for the front and back edges of the Ribbon, as below
        RibbonPoints = ribbonCurve.Tessellate();

        // will interpolate between these edges to give the ribbon a smooth "twist" over its length
        var leftRibbonFrontEdgeOffset = LeftController.RibbonFrontEdgeOffset;
        var leftRibbonBackEdgeOffset  = LeftController.RibbonBackEdgeOffset;

        var rightRibbonFrontEdgeOffset = RightController.RibbonFrontEdgeOffset;
        var rightRibbonBackEdgeOffset  = RightController.RibbonBackEdgeOffset;

        var triStripPoints        = new Vector3[RibbonPoints.Length * 2];
        var curvePointLengthFloat = (float)RibbonPoints.Length;

        for (var i = 0; i < RibbonPoints.Length; i++)
        {
            // Offset front and back from curvePoints, as curvePoints pass through the centre of the ribbon
            var frontEdgePoint = RibbonPoints[i] + leftRibbonFrontEdgeOffset.LinearInterpolate(rightRibbonFrontEdgeOffset, i / curvePointLengthFloat);
            var backEdgePoint  = RibbonPoints[i] + leftRibbonBackEdgeOffset.LinearInterpolate(rightRibbonBackEdgeOffset, i / curvePointLengthFloat);

            triStripPoints[i * 2]       = frontEdgePoint;
            triStripPoints[(i * 2) + 1] = backEdgePoint;
        }

        RibbonMesh.Clear();         // without Clear, triangles from previous loops accumulate on screen
        RibbonMesh.Begin(Mesh.PrimitiveType.TriangleStrip);
        for (var i = 0; i < triStripPoints.Length; i++)
        {
            // pass vertices to Normal function in anti-clockwise order
            // this will vary depending on which side of the ribbon the vertex is added, hence the i % 2... condition. i.e.:
            // - odd number: n, n-1, n-2
            // - even number: n-2, n-1, n
            var normal = i < 3 ? GetTriangleNormal(triStripPoints[2], triStripPoints[1], triStripPoints[0])
                                                                : (i % 2 == 0 ? GetTriangleNormal(triStripPoints[i], triStripPoints[i - 1], triStripPoints[i - 2])
                                                                        : GetTriangleNormal(triStripPoints[i - 2], triStripPoints[i - 1], triStripPoints[i]));

            RibbonMesh.SetNormal(normal);
            RibbonMesh.AddVertex(triStripPoints[i]);
        }
        RibbonMesh.End();
    }