/// <summary>
        /// Adds all csg constraints to a diff node.
        /// </summary>
        public void AddCsgConstraints(CsgOpDiff diffNode, vec3 refPos)
        {
            Drone refDrone = ReferenceDrone;

            switch (refDrone.Type)
            {
            case DroneType.Chain:
                for (int i = 0; i < drones.Count - 1; ++i)
                {
                    Drone         first  = drones[i];
                    Drone         second = drones[i + 1];
                    CsgExpression expr   = constraintExpression[i];

                    configureVerticalConstraintExpression(refPos, first, second, expr);

                    diffNode.AddNode(expr);
                }
                break;

            default: Debug.Fail("Not implemented/Invalid");
                break;
            }
        }
 /// <summary>
 /// Removes a drone from the constraint.
 /// </summary>
 public void RemoveDrone(Drone drone)
 {
     drones.Remove(drone);
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="UpvoidMiner.DroneConstraint"/> class.
 /// A drone constraint creates a digging/construction constraint between two nearby drones.
 /// </summary>
 /// <param name="_firstDrone">First drone, initially added to this constraint.</param>
 public DroneConstraint(Drone _firstDrone)
 {
     drones.Add(_firstDrone);
 }
        /// <summary>
        /// Updates this constraint, i.e. renderjobs.
        /// </summary>
        public void Update(float _elapsedSeconds)
        {
            if (drones.Count > 0)
            {
                Drone refDrone = ReferenceDrone;

                switch (refDrone.Type)
                {
                case DroneType.Chain:
                    for (int i = 0; i < drones.Count - 1; ++i)
                    {
                        Drone first  = drones[i];
                        Drone second = drones[i + 1];

                        // Swap every other drone.
                        if (i % 2 == 1)
                        {
                            Drone tmp = first;
                            first  = second;
                            second = tmp;
                        }

                        bool addJob = false;
                        if (boundaryIndicators.Count <= i)
                        {
                            boundaryIndicators.Add(new MeshRenderJob(Renderer.Transparent.Mesh,
                                                                     Resources.UseMaterial("Miner/DroneConstraintVertical", UpvoidMiner.ModDomain),
                                                                     Resources.UseMesh("::Debug/Quad", UpvoidMiner.ModDomain),
                                                                     mat4.Identity));
                            boundaryIndicatorsDistort.Add(new MeshRenderJob(Renderer.Distortion.Mesh,
                                                                            Resources.UseMaterial("Miner/DroneConstraintVerticalDistort", UpvoidMiner.ModDomain),
                                                                            Resources.UseMesh("::Debug/Quad", UpvoidMiner.ModDomain),
                                                                            mat4.Identity));

                            // Vertical drones cause a constraint by the intersection of the planes (i.e. the plane between two drones and the two shadow-planes).
                            constraintExpression.Add(new CsgExpression(1, "max((dot(plane1Normal, vec3(x, y, z)) - plane1Dis), max( (dot(plane2Normal, vec3(x, y, z)) - plane2Dis), (dot(plane3Normal, vec3(x, y, z)) - plane3Dis)) )",
                                                                       UpvoidMiner.ModDomain,
                                                                       "plane1Normal:vec3, plane1Dis:float, plane2Normal:vec3, plane2Dis:float, plane3Normal:vec3, plane3Dis:float"));
                            addJob = true;
                        }

                        MeshRenderJob job1 = boundaryIndicators[i];
                        MeshRenderJob job2 = boundaryIndicatorsDistort[i];

                        configureVerticalConstraint(first, second, job1, job2);

                        if (addJob)
                        {
                            LocalScript.world.AddRenderJob(job1);
                            LocalScript.world.AddRenderJob(job2);
                        }
                    }


                    break;

                default:
                    Debug.Fail("Not implemented/Invalid");
                    break;
                }
            }
            // Remove old ones.
            while (boundaryIndicators.Count > Math.Max(0, drones.Count - 1))
            {
                LocalScript.world.RemoveRenderJob(boundaryIndicators[boundaryIndicators.Count - 1]);
                LocalScript.world.RemoveRenderJob(boundaryIndicatorsDistort[boundaryIndicators.Count - 1]);
                boundaryIndicators.RemoveAt(boundaryIndicators.Count - 1);
                boundaryIndicatorsDistort.RemoveAt(boundaryIndicatorsDistort.Count - 1);
                constraintExpression.RemoveAt(constraintExpression.Count - 1);
            }
        }
        /// <summary>
        /// Adds the drone to this constraint.
        /// Drone must be addable (check with IsAddable).
        /// </summary>
        public void AddDrone(Drone _drone)
        {
            Debug.Assert(IsAddable(_drone));

            drones.Add(_drone);
        }