예제 #1
0
        public void Empty()
        {
            Containers.Clear();
            NearRoomList.Clear();
            Portals.Clear();
            Frustum.Clear();
            Mesh = null;

            if (StaticMesh.Count > 0)
            {
                foreach(var sm in StaticMesh)
                {
                    RigidBody body = null;
                    if((body = sm.BtBody) != null)
                    {
                        if(body.MotionState != null)
                        {
                            body.MotionState.Dispose();
                            body.MotionState = null;
                        }
                        body.CollisionShape = null;

                        BtEngineDynamicsWorld.RemoveRigidBody(body);
                        body.Dispose();
                        body = null;
                        sm.BtBody = null;
                    }

                    if(sm.Self != null)
                    {
                        sm.Self.Room = null;
                        sm.Self = null;
                    }
                }
                StaticMesh.Clear();
            }

            if(BtBody != null)
            {
                BtBody.UserObject = null;
                if(BtBody.MotionState != null)
                {
                    BtBody.MotionState.Dispose();
                    BtBody.MotionState = null;
                }
                if(BtBody.CollisionShape != null)
                {
                    BtBody.CollisionShape.Dispose();
                    //BtBody.CollisionShape = null;
                }

                BtEngineDynamicsWorld.RemoveRigidBody(BtBody);
                BtBody = null;
            }

            Sectors.Clear();
            SectorsX = 0;
            SectorsY = 0;

            Sprites.Clear();

            Lights.Clear();

            Self = null;
        }
예제 #2
0
        /// <summary>
        /// Creates hair into allocated hair structure, using previously defined setup and entity index.
        /// </summary>
        public bool Create(HairSetup setup, Entity parentEntity)
        {
            // No setup or parent to link to - bypass function.
            if (parentEntity == null || setup == null || setup.LinkBody >= parentEntity.Bf.BoneTags.Count ||
                parentEntity.Bt.BtBody[(int)setup.LinkBody] == null)
                return false;

            var model = EngineWorld.GetModelByID(setup.Model);

            // No model to link to - bypass function.
            if (model == null || model.MeshCount == 0) return false;

            // Setup engine container. FIXME: DOESN'T WORK PROPERLY ATM.
            Container = new EngineContainer();
            Container.Room = parentEntity.Self.Room;
            Container.ObjectType = OBJECT_TYPE.Hair;
            Container.Object = this;

            // Setup initial hair parameters.
            OwnerChar = parentEntity; // Entity to refer to.
            OwnerBody = setup.LinkBody; // Entity body to refer to.

            // Setup initial position / angles.
            var ownerBodyTransform = parentEntity.Transform * parentEntity.Bf.BoneTags[(int) OwnerBody].FullTransform;

            // Number of elements (bodies) is equal to number of hair meshes.
            Elements = new List<HairElement>();
            Elements.Resize(model.MeshCount, () => new HairElement());

            // Root index should be always zero, as it is how engine determines that it is
            // connected to head and renders it properly. Tail index should be always the
            // last element of the hair, as it indicates absence of "child" constraint.
            RootIndex = 0;
            TailIndex = (byte)(Elements.Count - 1);

            // Weight step is needed to determine the weight of each hair body.
            // It is derived from root body weight and tail body weight.
            var weightStep = (setup.RootWeight - setup.TailWeight) / Elements.Count;
            var currentWeight = setup.RootWeight;

            for (var i = 0; i < Elements.Count; i++)
            {
                // Point to corresponding mesh.
                Elements[i].Mesh = model.MeshTree[i].MeshBase;

                // Begin creating ACTUAL physical hair mesh.
                var localInertia = BulletSharp.Math.Vector3.Zero;

                // Make collision shape out of mesh.
                Elements[i].Shape = BT_CSfromMesh(Elements[i].Mesh, true, true, false);
                Elements[i].Shape.CalculateLocalInertia(currentWeight * setup.HairInertia, out localInertia);

                // Decrease next body weight to weight_step parameter.
                currentWeight -= weightStep;

                // Initialize motion state for body.
                var startTransform = ownerBodyTransform;
                var motionState = new DefaultMotionState(((Matrix4)startTransform).ToBullet());

                // Make rigid body.
                Elements[i].Body = new RigidBody(new RigidBodyConstructionInfo(currentWeight, motionState, Elements[i].Shape, localInertia));

                // Damping makes body stop in space by itself, to prevent it from continous movement.
                Elements[i].Body.SetDamping(setup.HairDamping[0], setup.HairDamping[1]);

                // Restitution and friction parameters define "bounciness" and "dullness" of hair.
                Elements[i].Body.Restitution = setup.HairRestitution;
                Elements[i].Body.Friction = setup.HairFriction;

                // Since hair is always moving with Lara, even if she's in still state (like, hanging
                // on a ledge), hair bodies shouldn't deactivate over time.
                Elements[i].Body.ForceActivationState(ActivationState.DisableDeactivation);

                // Hair bodies must not collide with each other, and also collide ONLY with kinematic
                // bodies (e. g. animated meshes), or else Lara's ghost object or anything else will be able to
                // collide with hair!
                Elements[i].Body.UserObject = Container;
                BtEngineDynamicsWorld.AddRigidBody(Elements[i].Body, CollisionFilterGroups.CharacterFilter, CollisionFilterGroups.KinematicFilter);

                Elements[i].Body.Activate();
            }

            // GENERATE CONSTRAINTS.
            // All constraints are generic 6-DOF type, as they seem perfect fit for hair.

            // Joint count is calculated from overall body amount multiplied by per-body constraint
            // count.
            Joints = new List<Generic6DofConstraint>();
            Joints.Resize(Elements.Count);

            // If multiple joints per body is specified, joints are placed in circular manner,
            // with obvious step of (SIMD_2_PI) / joint count. It means that all joints will form
            // circle-like figure.
            var currJoint = 0;

            for (var i = 0; i < Elements.Count; i++)
            {
                float bodyLength;
                var localA = new Transform();
                localA.SetIdentity();
                var localB = new Transform();
                localB.SetIdentity();

                var jointX = 0.0f;
                var jointY = 0.0f;

                RigidBody prevBody;
                if(i == 0) // First joint group
                {
                    // Adjust pivot point A to parent body.
                    localA.Origin = setup.HeadOffset + new Vector3(jointX, 0.0f, jointY);
                    Helper.SetEulerZYX(ref localA.Basis, setup.RootAngle.X, setup.RootAngle.Y, setup.RootAngle.Z);
                    // Stealing this calculation because I need it for drawing
                    OwnerBodyHairRoot = localA;

                    localB.Origin = new Vector3(jointX, 0.0f, jointY);
                    Helper.SetEulerZYX(ref localB.Basis, 0, -HalfPI, 0);

                    prevBody = parentEntity.Bt.BtBody[(int) OwnerBody]; // Previous body is parent body.
                }
                else
                {
                    // Adjust pivot point A to previous mesh's length, considering mesh overlap multiplier.
                    bodyLength = Math.Abs(Elements[i - 1].Mesh.BBMax.Y - Elements[i - 1].Mesh.BBMin.Y) *
                                 setup.JointOverlap;

                    localA.Origin = new Vector3(jointX, bodyLength, jointY);
                    Helper.SetEulerZYX(ref localA.Basis, 0, -HalfPI, 0);

                    // Pivot point B is automatically adjusted by Bullet.
                    localB.Origin = new Vector3(jointX, 0.0f, jointY);
                    Helper.SetEulerZYX(ref localB.Basis, 0, -HalfPI, 0);

                    prevBody = Elements[i - 1].Body; // Previous body is preceding hair mesh.
                }

                // Create 6DOF constraint.
                Joints[currJoint] = new Generic6DofConstraint(prevBody, Elements[i].Body, ((Matrix4) localA).ToBullet(),
                    ((Matrix4) localB).ToBullet(), true);

                // CFM and ERP parameters are critical for making joint "hard" and link
                // to Lara's head. With wrong values, constraints may become "elastic".
                for (var axis = 0; axis < 6; axis++)
                {
                    Joints[currJoint].SetParam(ConstraintParam.StopCfm, setup.JointCfm, axis);
                    Joints[currJoint].SetParam(ConstraintParam.StopErp, setup.JointErp, axis);
                }

                Joints[currJoint].LinearLowerLimit = BulletSharp.Math.Vector3.Zero;
                Joints[currJoint].LinearUpperLimit = BulletSharp.Math.Vector3.Zero;

                if(i == 0)
                {
                    // First joint group should be more limited in motion, as it is connected
                    // right to the head. NB: Should we make it scriptable as well?
                    Joints[currJoint].AngularLowerLimit = new BulletSharp.Math.Vector3(-HalfPI, 0.0f, -HalfPI * 0.4f);
                    Joints[currJoint].AngularLowerLimit = new BulletSharp.Math.Vector3(-HalfPI * 0.3f, 0.0f, HalfPI * 0.4f);

                    // Increased solver iterations make constraint even more stable.
                    Joints[currJoint].OverrideNumSolverIterations = 100;
                }
                else
                {
                    // Normal joint with more movement freedom.
                    Joints[currJoint].AngularLowerLimit = new BulletSharp.Math.Vector3(-HalfPI * 0.5f, 0.0f, -HalfPI * 0.5f);
                    Joints[currJoint].AngularLowerLimit = new BulletSharp.Math.Vector3(HalfPI * 0.5f, 0.0f, HalfPI * 0.5f);
                }

                Joints[currJoint].DebugDrawSize = 5.0f; // Draw constraint axes.

                // Add constraint to the world.
                BtEngineDynamicsWorld.AddConstraint(Joints[currJoint], true);

                currJoint++; // Point to the next joint.
            }

            createHairMesh(model);

            return true;
        }
예제 #3
0
        public void Dispose()
        {
            Bt.LastCollisions.Clear();

            if (Bt.BtJoints.Count > 0)
            {
                DeleteRagdoll();
            }

            foreach (var ghost in Bt.GhostObjects)
            {
                ghost.UserObject = null;
                BtEngineDynamicsWorld?.RemoveCollisionObject(ghost);
            }
            Bt.GhostObjects.Clear();

            Bt.Shapes.Clear();

            Bt.ManifoldArray?.Clear();

            if (Bt.BtBody.Count > 0)
            {
                foreach (var body in Bt.BtBody)
                {
                    if (body != null)
                    {
                        body.UserObject = null;
                        if (body.MotionState != null)
                        {
                            body.MotionState.Dispose();
                            body.MotionState = null;
                        }
                        body.CollisionShape = null;

                        BtEngineDynamicsWorld.RemoveRigidBody(body);
                    }
                }
                Bt.BtBody.Clear();
            }

            Self = null;

            Bf.BoneTags.Clear();

            for (var ssAnim = Bf.Animations.Next; ssAnim != null;)
            {
                var ssAnimNext = ssAnim.Next;
                ssAnim.Next = null;
                ssAnim = ssAnimNext;
            }
            Bf.Animations.Next = null;
        }
예제 #4
0
        public Entity(uint id)
        {
            ID = id;
            MoveType = MoveType.OnFloor;
            Self = new EngineContainer();

            Transform = new Transform();
            Transform.SetIdentity();
            Self.Object = this;
            Self.ObjectType = OBJECT_TYPE.Entity;
            Self.Room = null;
            Self.CollisionType = COLLISION_TYPE.None;
            OBB = new OBB();
            OBB.Transform = Transform;
            Bt = new BtEntityData();
            Bt.BtBody = new List<RigidBody>();
            Bt.BtJoints = new List<TypedConstraint>();
            Bt.NoFixAll = false;
            Bt.NoFixBodyParts = 0x0000000;
            Bt.ManifoldArray = null;
            Bt.Shapes = new List<CollisionShape>();
            Bt.GhostObjects = new List<PairCachingGhostObject>();
            Bt.LastCollisions = new List<EntityCollisionNode>();

            Bf = new SSBoneFrame();
            Bf.Animations = new SSAnimation();
            Bf.Animations.Model = null;
            Bf.Animations.ClearOnFrame();
            Bf.Animations.FrameTime = 0.0f;
            Bf.Animations.LastState = TR_STATE.LaraWalkForward;
            Bf.Animations.NextState = TR_STATE.LaraWalkForward;
            Bf.Animations.Lerp = 0.0f;
            Bf.Animations.CurrentAnimation = TR_ANIMATION.LaraRun;
            Bf.Animations.CurrentFrame = 0;
            Bf.Animations.NextAnimation = TR_ANIMATION.LaraRun;
            Bf.Animations.NextFrame = 0;
            Bf.Animations.Next = null;
            Bf.BoneTags = new List<SSBoneTag>();
            Bf.BBMax = Vector3.Zero;
            Bf.BBMin = Vector3.Zero;
            Bf.Centre = Vector3.Zero;
            Bf.Position = Vector3.Zero;
            Speed = Vector3.Zero;
        }
예제 #5
0
 public BtEngineClosestConvexResultCallback(EngineContainer cont, bool skipGhost = false)
     : base(ref Helper.ZeroB, ref Helper.ZeroB)
 {
     Container = cont;
     SkipGhost = skipGhost;
 }
예제 #6
0
        public static void SecondaryMouseDown()
        {
            var from = EngineCamera.Position;
            var to = from + EngineCamera.ViewDirection * 32768.0f;

            var camCont = new EngineContainer {Room = EngineCamera.CurrentRoom};

            var cbc = new BtEngineClosestRayResultCallback(camCont);
            //cbc.CollisionFilterMask = CollisionFilterGroups.StaticFilter | CollisionFilterGroups.KinematicFilter;
            BtEngineDynamicsWorld.RayTest(from.ToBullet(), to.ToBullet(), cbc);
            if(cbc.HasHit)
            {
                var castRay = new float[6];

                Vector3 place;
                Helper.SetInterpolate3(out place, from, to, cbc.ClosestHitFraction);
                place.CopyToArray(castRay, 0);
                (place + 100.0f * cbc.HitNormalWorld.ToOpenTK()).CopyToArray(castRay, 3);

                var c0 = (EngineContainer) cbc.CollisionObject.UserObject;
                if(c0 != null)
                {
                    if(c0.ObjectType == OBJECT_TYPE.BulletMisc)
                    {
                        var obj = cbc.CollisionObject;
                        var body = RigidBody.Upcast(obj);
                        body?.MotionState?.Dispose();
                        body?.CollisionShape?.Dispose();

                        if(body != null)
                        {
                            body.UserObject = null;
                        }
                        c0.Room = null;
                        c0 = null;

                        BtEngineDynamicsWorld.RemoveCollisionObject(obj);
                        obj.Dispose();
                    }
                    else
                    {
                        LastContainer = c0;
                    }
                }
            }
        }
예제 #7
0
        public static void PrimaryMouseDown()
        {
            var cont = new EngineContainer();
            var dbgR = 128.0f;
            var v = EngineCamera.Position;
            var dir = EngineCamera.ViewDirection;
            var localInertia = BulletSharp.Math.Vector3.Zero;

            var cshape = new SphereShape(dbgR);
            cshape.Margin = COLLISION_MARGIN_DEFAULT;

            var startTransform = new Transform();
            startTransform.SetIdentity();
            var newPos = v;
            startTransform.Origin = newPos;
            cshape.CalculateLocalInertia(12.0f, out localInertia);
            var motionState = new DefaultMotionState(((Matrix4)startTransform).ToBullet());
            var body = new RigidBody(new RigidBodyConstructionInfo(12.0f, motionState, cshape, localInertia));
            BtEngineDynamicsWorld.AddRigidBody(body);
            body.LinearVelocity = (dir * 6000).ToBullet();
            cont.Room = Room.FindPosCogerrence(newPos, EngineCamera.CurrentRoom);
            cont.ObjectType = OBJECT_TYPE.BulletMisc; // bullet have to destroy this user pointer
            body.UserObject = cont;
            body.CcdMotionThreshold = dbgR; // disable tunneling effect
            body.CcdSweptSphereRadius = dbgR;
        }