Ejemplo n.º 1
0
        public void RenderDynamicEntitySkin(LitShaderDescription shader, Entity ent, Matrix4 mvMatrix, Matrix4 pMatrix)
        {
            GL.UniformMatrix4(shader.Projection, false, ref pMatrix);

            for (var i = 0; i < ent.Bf.BoneTags.Count; i++)
            {
                var mat0 = mvMatrix * ent.Bt.BtBody[i].GetWorldTransform();
                var tr1 = new Matrix4();
                // Calculate parent transform
                var btag = ent.Bf.BoneTags[i];
                var foundParentTransform = false;
                for (var j = 0; j < ent.Bf.BoneTags.Count; j++)
                {
                    if(ent.Bf.BoneTags[i] == btag.Parent)
                    {
                        tr1 = ent.Bt.BtBody[j].GetWorldTransform();
                        foundParentTransform = true;
                        break;
                    }
                }
                if (!foundParentTransform)
                    tr1 = (Matrix4) ent.Transform;

                var translate = new Transform();
                translate.SetIdentity();
                translate.Origin += btag.Offset;

                var secondTransform = tr1.MultiplyByTransform(translate);
                var mat1 = mvMatrix * secondTransform;

                var transforms = new float[32];
                unsafe
                {
                    Array.Copy(Helper.GetArrayFromPointer(&mat0.Row0.X, 16), transforms, 16);
                    Array.Copy(Helper.GetArrayFromPointer(&mat1.Row0.X, 16), 0, transforms, 16, 16);
                }
                GL.UniformMatrix4(shader.ModelView, 2, false, transforms);

                if (btag.MeshSkin != null)
                {
                    RenderMesh(btag.MeshSkin);
                }
            }
        }
Ejemplo n.º 2
0
        public void RenderHair(Character entity, Matrix4 modelViewMatrix, Matrix4 projection)
        {
            if (entity == null || entity.Hairs.Count == 0) return;

            // Calculate lighting
            var shader = setupEntityLight(entity, modelViewMatrix, true);

            for (var h = 0; h < entity.Hairs.Count; h++)
            {
                // First: Head attachment
                var globalHead = (Matrix4)(entity.Transform * entity.Bf.BoneTags[(int)entity.Hairs[h].OwnerBody].FullTransform);
                var globalAttachment = globalHead.MultiplyByTransform(entity.Hairs[h].OwnerBodyHairRoot);

                var matrixCount = 10;

                var hairModelToGlobalMatrices = Helper.RepeatValue(16, () => new float[matrixCount]);
                unsafe
                {
                    var tmp = modelViewMatrix * globalAttachment;
                    fixed (float* ptr = &hairModelToGlobalMatrices[0][0])
                        Helper.PointerCopy(&tmp.Row0.X, ptr, 16);
                }

                // Then: Individual hair pieces
                for (var i = 0; i < entity.Hairs[h].Elements.Count; i++)
                {
                    StaticFuncs.Assert(i + 1 < matrixCount);
                    /*
                     * Definitions: x_o - as in original file. x_h - as in hair model
                     * (translated)
                     * M_ho - translation matrix. x_g = global position (before modelview)
                     * M_go - global position
                     *
                     * We know:
                     * x_h = M_ho * x_o
                     * x_g = M_go * x_o
                     * We want:
                     * M_hg so that x_g = M_gh * x_m
                     * We have: M_oh, M_g
                     *
                     * x_h = M_ho * x_o => x_o = M_oh^-1 * x_h
                     * x_g = M_go * M_ho^-1 * x_h
                     * (M_ho^-1 = M_oh so x_g = M_go * M_oh * x_h)
                     */

                    var invOriginToHairModel = new Transform();
                    invOriginToHairModel.SetIdentity();
                    // Simplification: Always translation matrix, no invert needed
                    invOriginToHairModel.Origin -= entity.Hairs[h].Elements[i].Position;

                    var globalFromHair =
                        entity.Hairs[h].Elements[i].Body.GetWorldTransform().MultiplyByTransform(invOriginToHairModel);

                    unsafe
                    {
                        var tmp = modelViewMatrix * globalFromHair;
                        fixed (float* ptr = &hairModelToGlobalMatrices[i + 1][0])
                            Helper.PointerCopy(&tmp.Row0.X, ptr, 16);
                    }
                }

                unsafe
                {
                    fixed (float* ptr = &hairModelToGlobalMatrices[0][0])
                        GL.UniformMatrix4(shader.ModelView, entity.Hairs[h].Elements.Count + 1, false, ptr);
                }
                
                GL.UniformMatrix4(shader.Projection, false, ref projection);

                RenderMesh(entity.Hairs[h].Mesh);
            }
        }
Ejemplo n.º 3
0
        public void DrawListDebugLines()
        {
            if(World == null || !(drawBoxes || drawRoomBoxes || drawPortals || drawFrustums || drawAxis || drawNormals || drawColl))
            {
                return;
            }

            if(World.Character != null)
            {
                DebugDrawer.DrawEntityDebugLines(World.Character, this);
            }

            // Render world debug information
            if(drawNormals && World.SkyBox != null)
            {
                var tr = new Transform();
                tr.SetIdentity();
                tr.Origin = Camera.Position + World.SkyBox.Animations[0].Frames[0].BoneTags[0].Offset;
                tr.Rotation = World.SkyBox.Animations[0].Frames[0].BoneTags[0].QRotate;
                DebugDrawer.DrawMeshDebugLines(World.SkyBox.MeshTree[0].MeshBase, tr, new List<Vector3>(),
                    new List<Vector3>(), this);
            }

            foreach (var room in renderList)
            {
                DebugDrawer.DrawRoomDebugLines(room, this, Camera);
            }

            if(drawColl)
            {
                BtEngineDynamicsWorld.DebugDrawWorld();
            }

            if(!DebugDrawer.IsEmpty)
            {
                var shader = ShaderManager.GetDebugLineShader();
                GL.UseProgram(shader.Program);
                GL.Uniform1(shader.Sampler, 0);
                GL.UniformMatrix4(shader.ModelViewProjection, false, ref Camera.GLViewProjMat);
                GL.BindTexture(TextureTarget.Texture2D, EngineWorld.Textures.Last());
                GL.PointSize(6.0f);
                GL.LineWidth(3.0f);
                DebugDrawer.Render();
            }
        }
Ejemplo n.º 4
0
        public void Draw()
        {
            if (!active) return;

            var item = EngineWorld.GetBaseItemByID((uint)this.item);
            if (item == null) return;

            var anim = item.BoneFrame.Animations.CurrentAnimation;
            var frame = item.BoneFrame.Animations.CurrentFrame;
            var time = item.BoneFrame.Animations.FrameTime;

            item.BoneFrame.Animations.CurrentAnimation = 0;
            item.BoneFrame.Animations.CurrentFrame = 0;
            item.BoneFrame.Animations.FrameTime = 0.0f;

            Gui.Item_Frame(item.BoneFrame, 0.0f);
            var matrix = new Transform();
            matrix.SetIdentity();
            VMath.Mat4_Translate(matrix, currPosX, posY, -2048.0f);
            VMath.Mat4_RotateY(matrix, currRotX + rotX);
            VMath.Mat4_RotateX(matrix, currRotY + rotY);
            Gui.RenderItem(item.BoneFrame, size, matrix);

            item.BoneFrame.Animations.CurrentAnimation = anim;
            item.BoneFrame.Animations.CurrentFrame = frame;
            item.BoneFrame.Animations.FrameTime = time;
        }
Ejemplo n.º 5
0
        public void RenderSkeletalModelSkin(LitShaderDescription shader, Entity ent, Matrix4 mvMatrix, Matrix4 pMatrix)
        {
            GL.UniformMatrix4(shader.Projection, false, ref pMatrix);

            foreach (var btag in ent.Bf.BoneTags)
            {
                var transforms = new float[32];
                var mvTransforms = mvMatrix.MultiplyByTransform(btag.FullTransform);
                unsafe
                {
                    Array.Copy(Helper.GetArrayFromPointer(&mvTransforms.Row0.X, 16), transforms, 16);
                }

                // Calculate parent transform
                var parentTransform = btag.Parent == null ? ent.Transform : btag.Parent.FullTransform;

                var translate = new Transform();
                translate.SetIdentity();
                translate.Origin += btag.Offset;

                var secondTransform = parentTransform * translate;

                var mvTransforms2 = mvMatrix.MultiplyByTransform(secondTransform);
                unsafe
                {
                    Array.Copy(Helper.GetArrayFromPointer(&mvTransforms2.Row0.X, 16), 0, transforms, 16, 16);
                }
                GL.UniformMatrix4(shader.ModelView, 2, false, transforms);

                if(btag.MeshSkin != null)
                {
                    RenderMesh(btag.MeshSkin);
                }
            }
        }
Ejemplo n.º 6
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;
        }
Ejemplo n.º 7
0
        public void Render()
        {
            if(CurrentState != InventoryState.Disabled && inventory != null && inventory.Count > 0 && Global.FontManager != null)
            {
                var num = 0;
                foreach (var i in inventory)
                {
                    var bi = EngineWorld.GetBaseItemByID(i.ID);
                    if(bi == null || bi.Type != currentItemsType)
                    {
                        continue;
                    }

                    var matrix = new Transform();
                    matrix.SetIdentity();
                    VMath.Mat4_Translate(matrix, 0.0f, 0.0f, -baseRingRadius * 2.0f);
                    //VMath.Mat4_RotateX(matrix, 25.0f);
                    VMath.Mat4_RotateX(matrix, 25.0f + ringVerticalAngle);
                    var ang = ringAngleStep * (-itemsOffset + num) + ringAngle;
                    VMath.Mat4_RotateY(matrix, ang);
                    VMath.Mat4_Translate(matrix, 0.0f, verticalOffset, ringRadius);
                    VMath.Mat4_RotateX(matrix, -90.0f);
                    VMath.Mat4_RotateZ(matrix, 90.0f);
                    if(num == itemsOffset)
                    {
                        if(bi.Name[0] != 0)
                        {
                            LabelItemName.Text = bi.Name;

                            if(i.Count > 1)
                            {
                                var counter = EngineLua.GetString(STR_GEN_MASK_INVHEADER);
                                LabelItemName.Text = Helper.Format(counter, bi.Name, i.Count);
                            }
                        }
                        VMath.Mat4_RotateZ(matrix, 90.0f + itemAngle - ang);
                        Gui.Item_Frame(bi.BoneFrame, 0.0f); // here will be time != 0 for using items animation
                    }
                    else
                    {
                        VMath.Mat4_RotateZ(matrix, 90.0f - ang);
                        Gui.Item_Frame(bi.BoneFrame, 0.0f);
                    }
                    VMath.Mat4_Translate(matrix, -0.5f * bi.BoneFrame.Centre);
                    VMath.Mat4_Scale(matrix, 0.7f, 0.7f, 0.7f);
                    Gui.RenderItem(bi.BoneFrame, 0.0f, matrix);

                    num++;
                }
            }
        }
Ejemplo n.º 8
0
        public ClimbInfo CheckWallsClimbability()
        {
            var ret = new ClimbInfo();
            ret.CanHang = false;
            ret.WallHit = ClimbType.None;
            ret.EdgeHit = false;
            ret.EdgeObject = null;
            ret.FloorLimit = HeightInfo.FloorHit ? HeightInfo.FloorPoint.Z : -9e10f;
            ret.CeilingLimit = HeightInfo.CeilingHit ? HeightInfo.CeilingPoint.Z : 9e10f;
            ret.Point = Climb.Point;

            if (!HeightInfo.WallsClimb)
            {
                return ret;
            }

            ret.Up = Vector3.UnitZ;

            var pos = Transform.Origin;
            var from = pos + Transform.Basis.Column2 * Bf.BBMax.Z - Transform.Basis.Column1 * ClimbR;
            var to = from;
            var t = ForwardSize + Bf.BBMax.Y;
            to += Transform.Basis.Column1 * t;

            var ccb = ConvexCb;
            ccb.ClosestHitFraction = 1.0f;
            ccb.HitCollisionObject = null;

            var tr1 = new Transform();
            tr1.SetIdentity();
            tr1.Origin = from;

            var tr2 = new Transform();
            tr2.SetIdentity();
            tr2.Origin = to;

            BtEngineDynamicsWorld.ConvexSweepTest(ClimbSensor, ((Matrix4) tr1).ToBullet(), ((Matrix4) tr2).ToBullet(), ccb);
            if (!ccb.HasHit)
            {
                return ret;
            }

            ret.Point = ccb.HitPointWorld.ToOpenTK();
            ret.N = ccb.HitNormalWorld.ToOpenTK();
            var wn2 = new[] {ret.N.X, ret.N.Y};
            t = (float) Math.Sqrt(wn2[0] * wn2[0] + wn2[1] * wn2[1]);
            wn2[0] /= t;
            wn2[1] /= t;

            ret.Right.X = -wn2[1];
            ret.Right.Y = wn2[0];
            ret.Right.Z = 0.0f;

            // now we have wall normale in XOY plane. Let us check all flags
            if (HeightInfo.WallsClimbDir.HasFlagSig(SectorFlag.ClimbNorth) && wn2[1] < -0.7f
                || HeightInfo.WallsClimbDir.HasFlagSig(SectorFlag.ClimbEast) && wn2[0] < -0.7f
                || HeightInfo.WallsClimbDir.HasFlagSig(SectorFlag.ClimbSouth) && wn2[1] > 0.7f
                || HeightInfo.WallsClimbDir.HasFlagSig(SectorFlag.ClimbWest) && wn2[0] > 0.7f)
            {
                ret.WallHit = ClimbType.HandsOnly;
            }

            if (ret.WallHit != ClimbType.None)
            {
                t = 0.67f * Height;
                from -= Transform.Basis.Column2 * t;
                to = from;
                t = ForwardSize + Bf.BBMax.Y;
                to += Transform.Basis.Column1 * t;

                ccb.ClosestHitFraction = 1.0f;
                ccb.HitCollisionObject = null;
                tr1.SetIdentity();
                tr1.Origin = from;
                tr2.SetIdentity();
                tr2.Origin = to;
                BtEngineDynamicsWorld.ConvexSweepTest(ClimbSensor, ((Matrix4) tr1).ToBullet(), ((Matrix4) tr2).ToBullet(), ccb);
                if (ccb.HasHit)
                {
                    ret.WallHit = ClimbType.FullBody;
                }
            }

            return ret;
        }
Ejemplo n.º 9
0
        public ClimbInfo CheckClimbability(Vector3 offset, HeightInfo nfc, float testHeight)
        {
            Vector3 from, to;
            float d;
            var pos = Transform.Origin;
            var t1 = new Transform();
            var t2 = new Transform();
            byte upFounded;
            var castRay = new float[6];

            // init callbacks functions
            nfc.Cb = RayCb;
            nfc.Ccb = ConvexCb;
            var tmp = pos + offset;

            var ret = new ClimbInfo();
            ret.HeightInfo = CheckNextStep(offset + new Vector3(0, 0, 128), nfc);
            ret.CanHang = false;
            ret.EdgeHit = false;
            ret.EdgeObject = null;
            ret.FloorLimit = HeightInfo.FloorHit ? HeightInfo.FloorPoint.Z : -9e10f;
            ret.CeilingLimit = HeightInfo.CeilingHit ? HeightInfo.CeilingPoint.Z : 9e10f;
            if (nfc.CeilingHit && nfc.CeilingPoint.Z < ret.CeilingLimit)
            {
                ret.CeilingLimit = nfc.CeilingPoint.Z;
            }
            ret.Point = Climb.Point;

            // check max height
            if (HeightInfo.CeilingHit && tmp.Z > HeightInfo.CeilingPoint.Z - ClimbR - 1.0f)
            {
                tmp.Z = HeightInfo.CeilingPoint.Z - ClimbR - 1.0f;
            }

            // let's calculate edge
            from.X = pos.X - Transform.Basis.Column1.X * ClimbR * 2.0f;
            from.Y = pos.Y - Transform.Basis.Column1.Y * ClimbR * 2.0f;
            from.Z = pos.Z;
            to = tmp;

            t1.SetIdentity();
            t2.SetIdentity();
            upFounded = 0;
            testHeight = Math.Max(testHeight, MaxStepUpHeight);
            d = pos.Z + Bf.BBMax.Z - testHeight;
            to.CopyToArray(castRay, 0);
            to.CopyToArray(castRay, 3);
            castRay[5] -= d;
            var n0 = Vector3.Zero;
            var n1 = Vector3.Zero;
            var n0d = 0.0f;
            var n1d = 0.0f;
            do
            {
                t1.Origin = from;
                t2.Origin = to;
                nfc.Ccb.ClosestHitFraction = 1.0f;
                nfc.Ccb.HitCollisionObject = null;
                BtEngineDynamicsWorld.ConvexSweepTest(ClimbSensor, ((Matrix4) t1).ToBullet(), ((Matrix4) t2).ToBullet(), nfc.Ccb);
                if (nfc.Ccb.HasHit)
                {
                    if (nfc.Ccb.HitNormalWorld.Z >= 0.1f)
                    {
                        upFounded = 1;
                        n0 = nfc.Ccb.HitNormalWorld.ToOpenTK();
                        n0d = -n0.Dot(nfc.Ccb.HitPointWorld.ToOpenTK());
                    }
                    if (upFounded != 0 && nfc.Ccb.HitNormalWorld.Z < 0.001f)
                    {
                        n1 = nfc.Ccb.HitNormalWorld.ToOpenTK();
                        n1d = -n1.Dot(nfc.Ccb.HitPointWorld.ToOpenTK());
                        Climb.EdgeObject = nfc.Ccb.HitCollisionObject;
                        upFounded = 2;
                        break;
                    }
                }
                else
                {
                    tmp.X = to.X;
                    tmp.Y = to.Y;
                    tmp.Z = d;
                    t1.Origin = to;
                    t2.Origin = tmp;
                    t1.Origin = from;
                    t2.Origin = to;
                    nfc.Ccb.ClosestHitFraction = 1.0f;
                    nfc.Ccb.HitCollisionObject = null;
                    BtEngineDynamicsWorld.ConvexSweepTest(ClimbSensor, ((Matrix4) t1).ToBullet(), ((Matrix4) t2).ToBullet(), nfc.Ccb);
                    if (nfc.Ccb.HasHit)
                    {
                        upFounded = 1;
                        n0 = nfc.Ccb.HitNormalWorld.ToOpenTK();
                        n0d = -n0.Dot(nfc.Ccb.HitPointWorld.ToOpenTK());
                    }
                    else
                    {
                        return ret;
                    }
                }

                // mult 0.66 is magic, but it must be less than 1.0 and greater than 0.0;
                // close to 1.0 - bad precision, good speed;
                // close to 0.0 - bad speed, bad precision;
                // close to 0.5 - middle speed, good precision
                from.Z -= 0.66f * ClimbR;
                to.Z -= 0.66f * ClimbR;
            } while (to.Z >= d); // we can't climb under floor!

            if (upFounded != 2)
            {
                return ret;
            }

            // get the character plane equation
            var n2 = Transform.Basis.Column0;
            var n2d = -n2.Dot(pos);

            Assert(!n0.FuzzyZero());
            Assert(!n1.FuzzyZero());
            Assert(!n2.FuzzyZero());

            /*
             * Solve system of the linear equations by Kramer method!
             * I know - It may be slow, but it has a good precision!
             * The root is point of 3 planes intersection.
             */
            d = -n0[0] * (n1[1] * n2[2] - n1[2] * n2[1]) +
                n1[0] * (n0[1] * n2[2] - n0[2] * n2[1]) -
                n2[0] * (n0[1] * n1[2] - n0[2] * n1[1]);

            if (Math.Abs(d) < 0.005f)
            {
                return ret;
            }

            ret.EdgePoint[0] = n0d * (n1[1] * n2[2] - n1[2] * n2[1]) -
                               n1d * (n0[1] * n2[2] - n0[2] * n2[1]) +
                               n2d * (n0[1] * n1[2] - n0[2] * n1[1]);
            ret.EdgePoint[0] /= d;

            ret.EdgePoint[1] = n0[0] * (n1d * n2[2] - n1[2] * n2d) -
                               n1[0] * (n0d * n2[2] - n0[2] * n2d) +
                               n2[0] * (n0d * n1[2] - n0[2] * n1d);
            ret.EdgePoint[1] /= d;

            ret.EdgePoint[2] = n0[0] * (n1[1] * n2d - n1d * n2[1]) -
                               n1[0] * (n0[1] * n2d - n0d * n2[1]) +
                               n2[0] * (n0[1] * n1d - n0d * n1[1]);
            ret.EdgePoint[2] /= d;
            ret.Point = ret.EdgePoint;
            ret.Point.CopyToArray(castRay, 3);
            /*
             * unclimbable edge slant %)
             */
            n2 = n0.Cross(n1);
            d = CriticalSlantZComponent;
            d *= d * (n2[0] * n2[0] + n2[1] * n2[1] + n2[2] * n2[2]);
            if (n2[2] * n2[2] > d)
            {
                return ret;
            }

            /*
             * Now, let us calculate z_angle
             */
            ret.EdgeHit = true;

            n2.Z = n2.X;
            n2.X = n2.Y;
            n2.Y = -n2.Z;
            n2.Z = 0.0f;
            if (n2.X * Transform.Basis.Column1.X + n2.Y * Transform.Basis.Column1.Y > 0) // direction fixing
            {
                n2.X = -n2.X;
                n2.Y = -n2.Y;
            }

            ret.N = n2;
            ret.Up.X = 0.0f;
            ret.Up.Y = 0.0f;
            ret.Up.Z = 1.0f;
            ret.EdgeZAngle = Helper.Atan2(n2.X, -n2.Y) * DegPerRad;
            ret.EdgeTanXY.X = -n2.Y;
            ret.EdgeTanXY.Y = n2.X;
            ret.EdgeTanXY.Z = 0.0f;
            ret.EdgeTanXY /= (float) Math.Sqrt(n2.X * n2.X + n2.Y * n2.Y);
            ret.Right = ret.EdgeTanXY;

            if (!HeightInfo.FloorHit || ret.EdgePoint.Z - HeightInfo.FloorPoint.Z >= Height)
            {
                ret.CanHang = true;
            }

            ret.NextZSpace = 2.0f * Height;
            if (nfc.FloorHit && nfc.CeilingHit)
            {
                ret.NextZSpace = nfc.CeilingPoint.Z - nfc.FloorPoint.Z;
            }

            return ret;
        }
Ejemplo n.º 10
0
        public static void Cam_FollowEntity(Camera cam, Entity ent, float dx, float dz)
        {
            var cameraFrom = new Transform();
            var cameraTo = new Transform();

            // Reset to initial
            cameraFrom.SetIdentity();
            cameraTo.SetIdentity();

            var cb = ent.CallbackForCamera();

            var camPos = cam.Position;

            // Basic camera override, completely placeholder until a system classic-like is created
            if (!ControlStates.MouseLook) // If mouse look is off
            {
                var currentAngle = CamAngles.X * RadPerDeg; // Current is the current cam angle
                var targetAngle = ent.Angles.X * RadPerDeg;
                    // Target is the target angle which is the entity's angle itself
                var rotSpeed = 2.0f; // Speed of rotation

                //@FIXME
                // If Lara is in a specific state we want to rotate -75 deg or +75 deg depending on camera collision
                if(ent.Bf.Animations.LastState == TR_STATE.LaraReach)
                {
                    if(cam.TargetDir == TR_CAM_TARG.Back)
                    {
                        var camPos2 = camPos;
                        cameraFrom.Origin = camPos2;
                        camPos2.X += (float) (Math.Sin((ent.Angles.X - 90.0f) * RadPerDeg) *
                                              ControlStates.CamDistance);
                        camPos2.Y -= (float) (Math.Cos((ent.Angles.X - 90.0f) * RadPerDeg) *
                                              ControlStates.CamDistance);
                        cameraTo.Origin = camPos2;

                        // If collided we want to go right otherwise stay left
                        if(Cam_HasHit(cb, cameraFrom, cameraTo))
                        {
                            camPos2 = camPos;
                            cameraFrom.Origin = camPos2;
                            camPos2.X += (float)(Math.Sin((ent.Angles.X + 90.0f) * RadPerDeg) *
                                             ControlStates.CamDistance);
                            camPos2.Y -= (float)(Math.Cos((ent.Angles.X + 90.0f) * RadPerDeg) *
                                                  ControlStates.CamDistance);
                            cameraTo.Origin = camPos2;

                            // If collided we want to go to back else right
                            cam.TargetDir = Cam_HasHit(cb, cameraFrom, cameraTo) ? TR_CAM_TARG.Back : TR_CAM_TARG.Right;
                        }
                        else
                        {
                            cam.TargetDir = TR_CAM_TARG.Left;
                        }
                    }
                }
                else if(ent.Bf.Animations.LastState == TR_STATE.LaraJumpBack)
                {
                    cam.TargetDir = TR_CAM_TARG.Front;
                }
                // ReSharper disable once RedundantCheckBeforeAssignment
                else if(cam.TargetDir != TR_CAM_TARG.Back)
                {
                    cam.TargetDir = TR_CAM_TARG.Back; // Reset to back
                }

                // If target mis-matches current we need to update the camera's angle to reach target!
                if (currentAngle != targetAngle)
                {
                    switch (cam.TargetDir)
                    {
                        case TR_CAM_TARG.Back:
                            targetAngle = ent.Angles.X * RadPerDeg;
                            break;
                        case TR_CAM_TARG.Front:
                            targetAngle = (ent.Angles.X - 180.0f) * RadPerDeg;
                            break;
                        case TR_CAM_TARG.Left:
                            targetAngle = (ent.Angles.X - 75.0f) * RadPerDeg;
                            break;
                        case TR_CAM_TARG.Right:
                            targetAngle = (ent.Angles.X + 75.0f) * RadPerDeg;
                            break;
                        default:
                            targetAngle = ent.Angles.X * RadPerDeg; // Same as TR_CAM_TARG_BACK (default pos)
                            break;
                    }

                    var dAngle = CamAngles.X - targetAngle;
                    if (dAngle > Rad90)
                    {
                        dAngle -= 1 * RadPerDeg;
                    }
                    else
                    {
                        dAngle += 1 * RadPerDeg;
                    }
                    CamAngles.X =
                        (CamAngles.X +
                         Helper.Atan2((float) Math.Sin(currentAngle - dAngle), (float) Math.Cos(currentAngle + dAngle)) *
                         EngineFrameTime * rotSpeed) % Rad360; // Update camera's angle
                }
            }

            camPos = ent.CamPosForFollowing(dz);

            // Code to manage screen shaking effects
            if(Renderer.Camera.ShakeTime > 0.0f && Renderer.Camera.ShakeValue > 0.0f)
            {
                camPos = camPos.AddF((Helper.CPPRand() % Math.Abs(Renderer.Camera.ShakeValue) -
                                     Renderer.Camera.ShakeValue / 2.0f) * Renderer.Camera.ShakeTime);
                Renderer.Camera.ShakeTime = Renderer.Camera.ShakeTime < 0.0f
                    ? 0.0f
                    : Renderer.Camera.ShakeTime - EngineFrameTime;
            }

            cameraFrom.Origin = camPos;
            camPos.Z += dz;
            cameraTo.Origin = camPos;
            if(Cam_HasHit(cb, cameraFrom, cameraTo))
            {
                Helper.SetInterpolate3(out camPos, cameraFrom.Origin, cameraTo.Origin, cb.ClosestHitFraction);
                camPos += (cb.HitNormalWorld * 2.0f).ToOpenTK();
            }

            if(dx != 0.0f)
            {
                cameraFrom.Origin = camPos;
                camPos += dx * cam.RightDirection;
                cameraTo.Origin = camPos;
                if (Cam_HasHit(cb, cameraFrom, cameraTo))
                {
                    Helper.SetInterpolate3(out camPos, cameraFrom.Origin, cameraTo.Origin, cb.ClosestHitFraction);
                    camPos += (cb.HitNormalWorld * 2.0f).ToOpenTK();
                }

                cameraFrom.Origin = camPos;

                var cosAy = Math.Cos(CamAngles.Y);
                var camDx = Math.Sin(CamAngles.X) * cosAy;
                var camDy = -Math.Cos(CamAngles.X) * cosAy;
                var camDz = -Math.Sin(CamAngles.Y);
                camPos.X += (float) (camDx * ControlStates.CamDistance);
                camPos.Y += (float) (camDy * ControlStates.CamDistance);
                camPos.Z += (float) (camDz * ControlStates.CamDistance);

                cameraTo.Origin = camPos;
                if (Cam_HasHit(cb, cameraFrom, cameraTo))
                {
                    Helper.SetInterpolate3(out camPos, cameraFrom.Origin, cameraTo.Origin, cb.ClosestHitFraction);
                    camPos += (cb.HitNormalWorld * 2.0f).ToOpenTK();
                }
            }

            // Update cam pos
            cam.Position = camPos;

            // Modify cam pos for quicksand rooms
            cam.CurrentRoom = Room.FindPosCogerrence(cam.Position - new Vector3(0, 0, 128), cam.CurrentRoom);
            if(cam.CurrentRoom != null && cam.CurrentRoom.Flags.HasFlagUns(RoomFlag.Quicksand))
            {
                var pos = cam.Position;
                pos.Z = cam.CurrentRoom.BBMax.Z + 2.0f * 64.0f;
                cam.Position = pos;
            }

            cam.SetRotation(CamAngles);
            cam.CurrentRoom = Room.FindPosCogerrence(cam.Position, cam.CurrentRoom);
        }
Ejemplo n.º 11
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;
        }
Ejemplo n.º 12
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;
        }