Esempio n. 1
0
        // Creates a 32x32 texture which defines the water flow (direction + speed).
        private Texture2D GenerateFlowMap()
        {
            const int size = 32;
            var       data = new Color[size * size];

            for (int y = 0; y < size; y++)
            {
                for (int x = 0; x < size; x++)
                {
                    Vector2F flowDirection;
                    float    flowSpeed;
                    GetFlow(new Vector2F(x / (float)size, y / (float)size), out flowDirection, out flowSpeed);

                    // Encode in color. The flow map stores the normalized 2D direction in r and g.
                    // The speed (magnitude of the flow vector) is stored in b, where 0 represents
                    // no movement and 1 represents movement with max speed.

                    flowSpeed = MathHelper.Clamp(flowSpeed, 0, 1);

                    // Convert to byte.
                    data[y * size + x] = new Color(
                        (byte)((flowDirection.X / 2 + 0.5f) * 255),
                        (byte)((flowDirection.Y / 2 + 0.5f) * 255),
                        (byte)(flowSpeed * 255));
                }
            }

            var texture = new Texture2D(GraphicsService.GraphicsDevice, size, size, true, SurfaceFormat.Color);

            texture.SetData(data);

            return(texture);
        }
Esempio n. 2
0
        public Vector3F GetSunlight()
        {
            if (SunDirection.Y >= 0)
            {
                //----- Sun is above horizon.
                return(GetTransmittance(SunDirection) * SunIntensity);
            }

            //----- Sun is below horizon.
            // Get angle.
            float sunAngle = (float)MathHelper.ToDegrees(Math.Asin(SunDirection.Y));

            if (sunAngle < -5)
            {
                return(Vector3F.Zero);
            }

            // Sample horizon instead of real direction.
            Vector3F direction = SunDirection;

            direction.Y = 0;
            if (!direction.TryNormalize())
            {
                return(Vector3F.Zero);
            }

            Vector3F horizonSunlight = GetTransmittance(direction) * SunIntensity;

            // Lerp horizon sunlight to 0 at -5°.
            float f = 1 - MathHelper.Clamp(-sunAngle / 5.0f, 0, 1);

            return(horizonSunlight * f);
        }
Esempio n. 3
0
        private void UpdateSteeringAngle(float deltaTime)
        {
            // TODO: Reduce max steering angle at high speeds.

            const float MaxAngle     = 0.5f;
            const float SteeringRate = 3;

            // We limit the amount of change per frame.
            float change = SteeringRate * deltaTime;

            float direction = 0;

            if (_inputService.IsDown(Keys.A))
            {
                direction += 1;
            }
            if (_inputService.IsDown(Keys.D))
            {
                direction -= 1;
            }

            var gamePadState = _inputService.GetGamePadState(LogicalPlayerIndex.One);

            direction -= gamePadState.ThumbSticks.Left.X;

            if (direction != 0)
            {
                // Increase steering angle.
                _steeringAngle = MathHelper.Clamp(_steeringAngle + direction * change, -MaxAngle, +MaxAngle);
            }
            else
            {
                // Steer back to neutral position (angle 0).
                if (_steeringAngle > 0)
                {
                    _steeringAngle = MathHelper.Clamp(_steeringAngle - change, 0, +MaxAngle);
                }
                else if (_steeringAngle < 0)
                {
                    _steeringAngle = MathHelper.Clamp(_steeringAngle + change, -MaxAngle, 0);
                }

                // TODO: Maybe we steer back with half rate?
                // (Pressing a button steers faster than not pressing a button?)
            }

            Vehicle.SetCarSteeringAngle(_steeringAngle, Vehicle.Wheels[0], Vehicle.Wheels[1], Vehicle.Wheels[2], Vehicle.Wheels[3]);
        }
        private void UpdateOrientation(float deltaTime)
        {
            // Compute new yaw and pitch from mouse movement and gamepad.
            float deltaYaw = -_inputService.MousePositionDelta.X;

            deltaYaw -= _inputService.GetGamePadState(LogicalPlayerIndex.One).ThumbSticks.Right.X *ThumbStickFactor;
            _yaw     += deltaYaw * deltaTime * AngularVelocityMagnitude;

            float deltaPitch = -_inputService.MousePositionDelta.Y;

            deltaPitch += _inputService.GetGamePadState(LogicalPlayerIndex.One).ThumbSticks.Right.Y *ThumbStickFactor;
            _pitch     += deltaPitch * deltaTime * AngularVelocityMagnitude;

            // Limit the pitch angle to +/- 90°.
            _pitch = MathHelper.Clamp(_pitch, -ConstantsF.PiOver2, ConstantsF.PiOver2);
        }
Esempio n. 5
0
        private void UpdateAcceleration(float deltaTime)
        {
            const float MaxForce         = 2000;
            const float AccelerationRate = 10000;

            // We limit the amount of change per frame.
            float change = AccelerationRate * deltaTime;

            float direction = 0;

            if (_inputService.IsDown(Keys.W))
            {
                direction += 1;
            }
            if (_inputService.IsDown(Keys.S))
            {
                direction -= 1;
            }

            var gamePadState = _inputService.GetGamePadState(LogicalPlayerIndex.One);

            direction += gamePadState.Triggers.Right - gamePadState.Triggers.Left;

            if (direction != 0)
            {
                // Increase motor force.
                _motorForce = MathHelper.Clamp(_motorForce + direction * change, -MaxForce, +MaxForce);
            }
            else
            {
                // No acceleration. Bring motor force down to 0.
                if (_motorForce > 0)
                {
                    _motorForce = MathHelper.Clamp(_motorForce - change, 0, +MaxForce);
                }
                else if (_motorForce < 0)
                {
                    _motorForce = MathHelper.Clamp(_motorForce + change, -MaxForce, 0);
                }
            }

            // We can decide which wheels are motorized. Here we use an all wheel drive:
            Vehicle.Wheels[0].MotorForce = _motorForce;
            Vehicle.Wheels[1].MotorForce = _motorForce;
            Vehicle.Wheels[2].MotorForce = _motorForce;
            Vehicle.Wheels[3].MotorForce = _motorForce;
        }
Esempio n. 6
0
        // Returns the flow vector for a given position.
        // x and y are in the range [0, 1].
        private static void GetFlow(Vector2F position, out Vector2F direction, out float speed)
        {
            // Create a circular movement around (0.5, 0.5).

            // Vector from center to position is:
            var radius = position - new Vector2F(0.5f, 0.5f);

            // The flow direction is orthogonal to the radius vector.
            direction = new Vector2F(radius.Y, -radius.X);
            direction.TryNormalize();

            // The speed is max in the center and is 0 at the texture border.
            speed = 1;
            if (!Numeric.IsZero(radius.Length))
            {
                speed = 1 - InterpolationHelper.HermiteSmoothStep(MathHelper.Clamp((radius.Length - 0.1f) / 0.4f, 0, 1));
            }
        }
Esempio n. 7
0
        private Vector3F GetBaseColor(Vector3F direction)
        {
            // 0 = zenith, 1 = horizon
            float p = 1 - MathHelper.Clamp(
                (float)Math.Acos(direction.Y) / ConstantsF.Pi * 2,
                0,
                1);

            var colorAverage = (BaseHorizonColor + BaseZenithColor) / 2;

            if (p < BaseColorShift)
            {
                return(InterpolationHelper.Lerp(BaseHorizonColor, colorAverage, p / BaseColorShift));
            }
            else
            {
                return(InterpolationHelper.Lerp(colorAverage, BaseZenithColor, (p - BaseColorShift) / (1 - BaseColorShift)));
            }
        }
        protected override void OnUpdate(TimeSpan deltaTime)
        {
            // Mouse centering (controlled by the MenuComponent) is disabled if the game
            // is inactive or if the GUI is active. In these cases, we do not want to move
            // the player.
            if (!_inputService.EnableMouseCentering)
            {
                return;
            }

            if (_inputService.IsPressed(Keys.Enter, true))
            {
                // Toggle between player camera and spectator view.
                _useSpectatorView = !_useSpectatorView;
            }
            else
            {
                float deltaTimeF = (float)deltaTime.TotalSeconds;

                // Compute new yaw and pitch from mouse movement.
                float deltaYaw = 0;
                deltaYaw -= _inputService.MousePositionDelta.X;
                deltaYaw -= _inputService.GetGamePadState(LogicalPlayerIndex.One).ThumbSticks.Right.X * 10;
                _yaw     += deltaYaw * deltaTimeF * 0.1f;

                float deltaPitch = 0;
                deltaPitch -= _inputService.MousePositionDelta.Y;
                deltaPitch += _inputService.GetGamePadState(LogicalPlayerIndex.One).ThumbSticks.Right.Y * 10;
                _pitch     += deltaPitch * deltaTimeF * 0.1f;

                // Limit the pitch angle to less than +/- 90°.
                float limit = ConstantsF.PiOver2 - 0.01f;
                _pitch = MathHelper.Clamp(_pitch, -limit, limit);
            }

            // Update SceneNode.LastPoseWorld - this is required for some effects, like
            // camera motion blur.
            CameraNode.LastPoseWorld = CameraNode.PoseWorld;

            SetCameraPose();
        }
Esempio n. 9
0
        // Handle character-related input and move the character.
        private void ControlCharacter(float deltaTime)
        {
            // Compute new orientation from mouse movement.
            float deltaYaw = -InputService.MousePositionDelta.X;

            _yaw += deltaYaw * deltaTime * 0.1f;
            float deltaPitch = -InputService.MousePositionDelta.Y;

            _pitch += deltaPitch * deltaTime * 0.1f;

            // Limit the pitch angle.
            _pitch = MathHelper.Clamp(_pitch, -ConstantsF.PiOver2, ConstantsF.PiOver2);

            // Compute new orientation of the camera.
            QuaternionF cameraOrientation = QuaternionF.CreateRotationY(_yaw) * QuaternionF.CreateRotationX(_pitch);

            // Create velocity from WASD keys.
            // TODO: Diagonal movement is faster ;-). Fix this.
            Vector3F velocityVector = Vector3F.Zero;

            if (Keyboard.GetState().IsKeyDown(Keys.W))
            {
                velocityVector.Z--;
            }
            if (Keyboard.GetState().IsKeyDown(Keys.S))
            {
                velocityVector.Z++;
            }
            if (Keyboard.GetState().IsKeyDown(Keys.A))
            {
                velocityVector.X--;
            }
            if (Keyboard.GetState().IsKeyDown(Keys.D))
            {
                velocityVector.X++;
            }
            velocityVector *= 10 * deltaTime;

            // Velocity vector is currently in view space. -z is the forward direction.
            // We have to convert this vector to world space by rotating it.
            velocityVector = QuaternionF.CreateRotationY(_yaw).Rotate(velocityVector);

            // New compute desired character controller position in world space:
            Vector3F targetPosition = _character.Position + velocityVector;

            // Check if user wants to jump.
            bool jump = Keyboard.GetState().IsKeyDown(Keys.Space);

            // Call character controller to compute a new valid position. The character
            // controller slides along obstacles, handles stepping up/down, etc.
            _character.Move(targetPosition, deltaTime, jump);

            // ----- Set view matrix for graphics.
            // For third person we move the eye position back, behind the body (+z direction is
            // the "back" direction).
            Vector3F thirdPersonDistance = cameraOrientation.Rotate(new Vector3F(0, 0, 6));

            // Compute camera pose (= position + orientation).
            _cameraNode.PoseWorld = new Pose
            {
                Position = _character.Position        // Floor position of character
                           + new Vector3F(0, 1.6f, 0) // + Eye height
                           + thirdPersonDistance,
                Orientation = cameraOrientation.ToRotationMatrix33()
            };
        }
        private static void ClampHeightsToLineSegments(HeightField terrain, Aabb aabb, List <Vector4F> segments, float padding)
        {
            // TODO: Optimize this (see software rasterizers).

            float originX          = terrain.OriginX;
            float originZ          = terrain.OriginZ;
            int   numberOfSamplesX = terrain.NumberOfSamplesX;
            int   numberOfSamplesZ = terrain.NumberOfSamplesZ;
            int   numberOfCellsX   = numberOfSamplesX - 1;
            int   numberOfCellsZ   = numberOfSamplesZ - 1;
            float widthX           = terrain.WidthX;
            float cellSizeX        = widthX / numberOfCellsX;
            float widthZ           = terrain.WidthZ;
            float cellSizeZ        = widthZ / numberOfCellsZ;

            float[] heights = terrain.Samples;

            // Get min and max indices (inclusive).
            float minX = aabb.Minimum.X;
            float maxX = aabb.Maximum.X;
            float minZ = aabb.Minimum.Z;
            float maxZ = aabb.Maximum.Z;

            // Get min and max indices (inclusive).
            int indexXMin = Math.Max(0, (int)Math.Floor((minX - originX) / cellSizeX));
            int indexZMin = Math.Max(0, (int)Math.Floor((minZ - originZ) / cellSizeZ));
            int indexXMax = Math.Min(numberOfSamplesX - 1, (int)Math.Ceiling((maxX - originX) / cellSizeX));
            int indexZMax = Math.Min(numberOfSamplesZ - 1, (int)Math.Ceiling((maxZ - originZ) / cellSizeZ));

            Parallel.For(indexZMin, indexZMax + 1, indexZ =>
                         //for (int indexZ = indexZMin; indexZ <= indexZMax; indexZ++)
            {
                for (int indexX = indexXMin; indexX <= indexXMax; indexX++)
                {
                    Vector3F terrainPointFlat = new Vector3F(originX + cellSizeX * indexX, 0, originZ + cellSizeZ * indexZ);

                    float bestSegmentInfluence = 0;
                    float bestSegmentHeight    = 0;
                    for (int segmentIndex = 0; segmentIndex < segments.Count / 2; segmentIndex++)
                    {
                        var segmentStartFlat = new Vector3F(segments[segmentIndex * 2].X, 0, segments[segmentIndex * 2].Z);
                        var segmentEndFlat   = new Vector3F(segments[segmentIndex * 2 + 1].X, 0, segments[segmentIndex * 2 + 1].Z);
                        var segment          = new LineSegment(segmentStartFlat, segmentEndFlat);
                        float parameter;
                        GetLineParameter(ref segment, ref terrainPointFlat, out parameter);
                        Vector4F closestPoint     = segments[segmentIndex * 2] + parameter * (segments[segmentIndex * 2 + 1] - segments[segmentIndex * 2]);
                        Vector3F closestPointFlat = new Vector3F(closestPoint.X, 0, closestPoint.Z);
                        float distance            = (closestPointFlat - terrainPointFlat).Length - padding;
                        float influence           = MathHelper.Clamp(1 - distance / (closestPoint.W - padding), 0, 1);
                        if (influence > bestSegmentInfluence)
                        {
                            bestSegmentInfluence = influence;
                            bestSegmentHeight    = closestPoint.Y;
                        }
                    }

                    if (bestSegmentInfluence > 0)
                    {
                        heights[indexZ * numberOfSamplesX + indexX] = InterpolationHelper.Lerp(
                            heights[indexZ * numberOfSamplesX + indexX],
                            bestSegmentHeight,
                            InterpolationHelper.HermiteSmoothStep(bestSegmentInfluence));
                    }
                }
            });
        }
Esempio n. 11
0
        public override void Update(GameTime gameTime)
        {
            float deltaTime = (float)gameTime.ElapsedGameTime.TotalSeconds;

            var debugRenderer = _graphicsScreen.DebugRenderer;

            debugRenderer.Clear();

            // Change wave height.
            if (InputService.IsDown(Keys.H))
            {
                bool  isShiftDown = (InputService.ModifierKeys & ModifierKeys.Shift) != 0;
                float sign        = isShiftDown ? +1 : -1;
                float delta       = sign * deltaTime * 0.01f;
                var   oceanWaves  = ((OceanWaves)_waterNode.Waves);
                oceanWaves.HeightScale = Math.Max(0, oceanWaves.HeightScale + delta);
            }

            // Switch water color.
            if (InputService.IsPressed(Keys.J, true))
            {
                if (_waterColorType == 0)
                {
                    _waterColorType = 1;
                    _waterNode.Water.UnderwaterFogDensity = new Vector3F(12, 8, 8) * 0.04f;
                    _waterNode.Water.WaterColor           = new Vector3F(10, 30, 79) * 0.002f;
                }
                else
                {
                    _waterColorType = 0;
                    _waterNode.Water.UnderwaterFogDensity = new Vector3F(1, 0.8f, 0.6f);
                    _waterNode.Water.WaterColor           = new Vector3F(0.2f, 0.4f, 0.5f);
                }
            }

            // Toggle reflection.
            if (InputService.IsPressed(Keys.K, true))
            {
                _waterNode.PlanarReflection.IsEnabled = !_waterNode.PlanarReflection.IsEnabled;
            }

            // Switch caustics.
            if (InputService.IsPressed(Keys.L, true))
            {
                if (_causticType == 0)
                {
                    _causticType = 1;
                    _waterNode.Water.CausticsSampleCount = 5;
                    _waterNode.Water.CausticsIntensity   = 10;
                    _waterNode.Water.CausticsPower       = 200;
                }
                else if (_causticType == 1)
                {
                    // Disable caustics
                    _causticType = 2;
                    _waterNode.Water.CausticsIntensity = 0;
                }
                else
                {
                    _causticType = 0;
                    _waterNode.Water.CausticsSampleCount = 3;
                    _waterNode.Water.CausticsIntensity   = 3;
                    _waterNode.Water.CausticsPower       = 100;
                }
            }

            // Move rigid bodies with the waves:
            // The Buoyancy force effect is only designed for a flat water surface.
            // This code applies some impulses to move the bodies. It is not physically
            // correct but looks ok.
            // The code tracks 3 arbitrary positions on each body. Info for the positions
            // are stored in RigidBody.UserData. The wave displacements of the previous
            // frame and the current frame are compared an impulse proportional to the
            // displacement change is applied.
            foreach (var body in Simulation.RigidBodies)
            {
                if (body.MotionType != MotionType.Dynamic)
                {
                    continue;
                }

                // Check how much the body penetrates the water using a simple AABB check.
                Aabb  aabb             = body.Aabb;
                float waterPenetration = (float)Math.Pow(
                    MathHelper.Clamp((_waterNode.PoseWorld.Position.Y - aabb.Minimum.Y) / aabb.Extent.Y, 0, 1),
                    3);

                if (waterPenetration < 0)
                {
                    body.UserData = null;
                    continue;
                }

                // 3 displacement vectors are stored in the UserData.
                var previousDisplacements = body.UserData as Vector3F[];
                if (previousDisplacements == null)
                {
                    previousDisplacements = new Vector3F[3];
                    body.UserData         = previousDisplacements;
                }

                for (int i = 0; i < 3; i++)
                {
                    // Get an arbitrary position on or near the body.
                    Vector3F position = new Vector3F(
                        (i < 2) ? aabb.Minimum.X : aabb.Maximum.X,
                        aabb.Minimum.Y,
                        (i % 2 == 0) ? aabb.Minimum.Z : aabb.Maximum.Z);

                    // Get wave displacement of this position.
                    var      waves = (OceanWaves)_waterNode.Waves;
                    Vector3F displacement, normal;
                    waves.GetDisplacement(position.X, position.Z, out displacement, out normal);

                    // Compute velocity from displacement change.
                    Vector3F currentVelocity = body.GetVelocityOfWorldPoint(position);
                    Vector3F desiredVelocity = (displacement - previousDisplacements[i]) / deltaTime;

                    // Apply impulse proportional to the velocity change of the water.
                    Vector3F velocityDelta = desiredVelocity - currentVelocity;
                    body.ApplyImpulse(
                        velocityDelta * body.MassFrame.Mass * waterPenetration * 0.1f,
                        position);

                    previousDisplacements[i] = displacement;
                }
            }
        }
Esempio n. 12
0
        protected override void OnUpdate(TimeSpan deltaTime)
        {
            // Mouse centering (controlled by the MenuComponent) is disabled if the game
            // is inactive or if the GUI is active. In these cases, we do not want to move
            // the player.
            if (!_inputService.EnableMouseCentering)
            {
                return;
            }

            if (_inputService.IsPressed(Keys.Enter, true))
            {
                // Toggle between player camera and spectator view.
                _useSpectatorView = !_useSpectatorView;
            }
            else
            {
                float deltaTimeF = (float)deltaTime.TotalSeconds;

                // Compute new yaw and pitch from mouse movement.
                float deltaYaw = 0;
                deltaYaw -= _inputService.MousePositionDelta.X;
                deltaYaw -= _inputService.GetGamePadState(LogicalPlayerIndex.One).ThumbSticks.Right.X * 10;
                _yaw     += deltaYaw * deltaTimeF * 0.1f;

                float deltaPitch = 0;
                deltaPitch -= _inputService.MousePositionDelta.Y;
                deltaPitch += _inputService.GetGamePadState(LogicalPlayerIndex.One).ThumbSticks.Right.Y * 10;
                _pitch     += deltaPitch * deltaTimeF * 0.1f;

                // Limit the pitch angle to less than +/- 90°.
                float limit = ConstantsF.PiOver2 - 0.01f;
                _pitch = MathHelper.Clamp(_pitch, -limit, limit);
            }

            // Update SceneNode.LastPoseWorld - this is required for some effects, like
            // camera motion blur.
            CameraNode.LastPoseWorld = CameraNode.PoseWorld;

            var vehiclePose = _vehicle.Pose;

            if (_useSpectatorView)
            {
                // Spectator Mode:
                // Camera is looking at the car from a fixed location in the level.
                Vector3F position = new Vector3F(10, 8, 10);
                Vector3F target   = vehiclePose.Position;
                Vector3F up       = Vector3F.UnitY;

                // Set the new camera view matrix. (Setting the View matrix changes the Pose.
                // The pose is simply the inverse of the view matrix).
                CameraNode.View = Matrix44F.CreateLookAt(position, target, up);
            }
            else
            {
                // Player Camera:
                // Camera moves with the car. The look direction can be changed by moving the mouse.
                Matrix33F yaw         = Matrix33F.CreateRotationY(_yaw);
                Matrix33F pitch       = Matrix33F.CreateRotationX(_pitch);
                Matrix33F orientation = vehiclePose.Orientation * yaw * pitch;
                Vector3F  forward     = orientation * -Vector3F.UnitZ;
                Vector3F  up          = Vector3F.UnitY;
                Vector3F  position    = vehiclePose.Position - 10 * forward + 5 * up;
                Vector3F  target      = vehiclePose.Position + 1 * up;

                CameraNode.View = Matrix44F.CreateLookAt(position, target, up);
            }
        }
Esempio n. 13
0
        // OnUpdate() is called once per frame.
        protected override void OnUpdate(TimeSpan deltaTime)
        {
            // Mouse centering (controlled by the MenuComponent) is disabled if the game
            // is inactive or if the GUI is active. In these cases, we do not want to move
            // the player.
            if (!_inputService.EnableMouseCentering)
            {
                return;
            }

            if (!IsEnabled)
            {
                return;
            }

            float deltaTimeF = (float)deltaTime.TotalSeconds;

            // Compute new orientation from mouse movement, gamepad and touch.
            Vector2F     mousePositionDelta = _inputService.MousePositionDelta;
            GamePadState gamePadState       = _inputService.GetGamePadState(LogicalPlayerIndex.One);
            Vector2F     touchDelta         = Vector2F.Zero;

#if MONOGAME || WINDOWS_PHONE
            foreach (var gesture in _inputService.Gestures)
            {
                if (gesture.GestureType == GestureType.FreeDrag)
                {
                    touchDelta += (Vector2F)gesture.Delta;

                    // If we have touch input, we ignore the mouse movement
                    mousePositionDelta = Vector2F.Zero;
                }
            }
#endif

#if WINDOWS_PHONE || IOS
            // On Windows Phone touch input also sets the mouse input. --> Ignore mouse data.
            mousePositionDelta = Vector2F.Zero;
#endif

            float deltaYaw = -mousePositionDelta.X - touchDelta.X - gamePadState.ThumbSticks.Right.X * ThumbStickFactor;
            _currentYaw += deltaYaw * deltaTimeF * AngularVelocityMagnitude;

            float deltaPitch = -mousePositionDelta.Y - touchDelta.Y + gamePadState.ThumbSticks.Right.Y * ThumbStickFactor;
            _currentPitch += deltaPitch * deltaTimeF * AngularVelocityMagnitude;

            // Limit the pitch angle to +/- 90°.
            _currentPitch = MathHelper.Clamp(_currentPitch, -ConstantsF.PiOver2, ConstantsF.PiOver2);

            // Reset camera position if <Home> or <Right Stick> is pressed.
            if (_inputService.IsPressed(Keys.Home, false) ||
                _inputService.IsPressed(Buttons.RightStick, false, LogicalPlayerIndex.One))
            {
                ResetPose();
            }

            // Compute new orientation of the camera.
            QuaternionF orientation = QuaternionF.CreateRotationY(_currentYaw) * QuaternionF.CreateRotationX(_currentPitch);

            // Create velocity from <W>, <A>, <S>, <D> and <R>, <F> keys.
            // <R> or DPad up is used to move up ("rise").
            // <F> or DPad down is used to move down ("fall").
            Vector3F      velocity      = Vector3F.Zero;
            KeyboardState keyboardState = _inputService.KeyboardState;
            if (keyboardState.IsKeyDown(Keys.W))
            {
                velocity.Z--;
            }
            if (keyboardState.IsKeyDown(Keys.S))
            {
                velocity.Z++;
            }
            if (keyboardState.IsKeyDown(Keys.A))
            {
                velocity.X--;
            }
            if (keyboardState.IsKeyDown(Keys.D))
            {
                velocity.X++;
            }
            if (keyboardState.IsKeyDown(Keys.R) || gamePadState.DPad.Up == ButtonState.Pressed)
            {
                velocity.Y++;
            }
            if (keyboardState.IsKeyDown(Keys.F) || gamePadState.DPad.Down == ButtonState.Pressed)
            {
                velocity.Y--;
            }

            // Add velocity from gamepad sticks.
            velocity.X += gamePadState.ThumbSticks.Left.X;
            velocity.Z -= gamePadState.ThumbSticks.Left.Y;

            // Rotate the velocity vector from view space to world space.
            velocity = orientation.Rotate(velocity);

            if (keyboardState.IsKeyDown(Keys.LeftShift))
            {
                velocity *= SpeedBoost;
            }

            // Multiply the velocity by time to get the translation for this frame.
            Vector3F translation = velocity * LinearVelocityMagnitude * deltaTimeF;

            // Update SceneNode.LastPoseWorld - this is required for some effects, like
            // camera motion blur.
            CameraNode.LastPoseWorld = CameraNode.PoseWorld;

            // Set the new camera pose.
            CameraNode.PoseWorld = new Pose(
                CameraNode.PoseWorld.Position + translation,
                orientation);
        }
Esempio n. 14
0
        protected override void OnHandleInput(InputContext context)
        {
#if !WP7 && !XBOX
#if PORTABLE
            if (GlobalSettings.PlatformID != PlatformID.WindowsPhone8)
#endif
            {
                ContinueDraggingSelection(context);
            }
#endif

            base.OnHandleInput(context);

            if (!IsLoaded)
            {
                return;
            }

            var inputService = InputService;

#if !WP7 && !XBOX
#if PORTABLE
            if (GlobalSettings.PlatformID != PlatformID.WindowsStore &&
                GlobalSettings.PlatformID != PlatformID.WindowsPhone8 &&
                GlobalSettings.PlatformID != PlatformID.Android &&
                GlobalSettings.PlatformID != PlatformID.iOS)
#endif
            {
                var  screen      = Screen;
                bool isMouseOver = IsMouseOver;
                if (isMouseOver && !inputService.IsMouseOrTouchHandled)
                {
                    if (inputService.IsDoubleClick(MouseButtons.Left) &&
                        !_mouseDownPosition.IsNaN &&
                        (_mouseDownPosition - context.MousePosition).LengthSquared < MinDragDistanceSquared)
                    {
                        // Double-click with left mouse button --> Select word or white-space.
                        inputService.IsMouseOrTouchHandled = true;
                        int index = GetIndex(context.MousePosition, screen);
                        SelectWordOrWhiteSpace(index);
                        StartDraggingSelection(context);
                    }
                    else if (inputService.IsPressed(MouseButtons.Left, false))
                    {
                        // Left mouse button pressed --> Position caret.
                        inputService.IsMouseOrTouchHandled = true;
                        int index = GetIndex(context.MousePosition, screen);
                        _selectionStart = index;
                        CaretIndex      = index;
                        StartDraggingSelection(context);
                    }
                    else
                    {
                        // Check for other mouse interactions.
                        _isDraggingSelection = false;
                        if (inputService.MouseWheelDelta != 0 && IsMultiline)
                        {
                            // Mouse wheel over the text box --> Scroll vertically.
                            inputService.IsMouseOrTouchHandled = true;

                            float delta = inputService.MouseWheelDelta / screen.MouseWheelScrollDelta * screen.MouseWheelScrollLines;
                            delta                   *= _verticalScrollBar.SmallChange;
                            VisualOffset             = MathHelper.Clamp(VisualOffset - delta, 0, _verticalScrollBar.Maximum);
                            _verticalScrollBar.Value = VisualOffset;
                            InvalidateArrange();
                        }
                    }
                }

                if (!_isDraggingSelection && IsFocusWithin)
                {
                    HandleKeyboardInput();
                }
            }
#endif
#if WP7 || PORTABLE
#if PORTABLE
            else
#endif
            {
                // Windows phone: The guide is shown when the touch is released over the box.
                bool isMouseOver = IsMouseOver;
                if (inputService.IsMouseOrTouchHandled)
                {
                    _isPressed = false;
                }
                else if (_isPressed && isMouseOver && inputService.IsReleased(MouseButtons.Left))
                {
                    ShowGuide(inputService.GetLogicalPlayer(context.AllowedPlayer));
                    inputService.IsMouseOrTouchHandled = true;
                    _isPressed = false;
                }
                else if (_isPressed && (!isMouseOver || inputService.IsUp(MouseButtons.Left)))
                {
                    _isPressed = false;
                }
                else if (isMouseOver && inputService.IsPressed(MouseButtons.Left, false))
                {
                    _isPressed = true;
                    inputService.IsMouseOrTouchHandled = true;
                }
            }
#endif

#if XBOX
            // Xbox: Guide is shown when gamepad A is pressed.
            if (IsFocusWithin)
            {
                if (!inputService.IsGamePadHandled(context.AllowedPlayer) && inputService.IsPressed(Buttons.A, false, context.AllowedPlayer))
                {
                    ShowGuide(inputService.GetLogicalPlayer(context.AllowedPlayer));
                    inputService.SetGamePadHandled(context.AllowedPlayer, true);
                }
            }
#endif
        }
Esempio n. 15
0
        // OnUpdate() is called once per frame.
        protected override void OnUpdate(TimeSpan deltaTime)
        {
#if !WINDOWS_PHONE
            // Mouse centering (controlled by the MenuComponent) is disabled if the game
            // is inactive or if the GUI is active. In these cases, we do not want to move
            // the player.
            if (!_inputService.EnableMouseCentering)
            {
                return;
            }
#endif

            if (!IsEnabled)
            {
                return;
            }

            float deltaTimeF = (float)deltaTime.TotalSeconds;

            // Compute new orientation from mouse movement and gamepad.
            Vector2F mousePositionDelta = _inputService.MousePositionDelta;

#if !WINDOWS_PHONE
            GamePadState gamePadState = _inputService.GetGamePadState(LogicalPlayerIndex.One);

            float deltaYaw = -mousePositionDelta.X - gamePadState.ThumbSticks.Right.X * ThumbStickFactor;
            _currentYaw += deltaYaw * deltaTimeF * AngularVelocityMagnitude;

            float deltaPitch = -mousePositionDelta.Y + gamePadState.ThumbSticks.Right.Y * ThumbStickFactor;
            _currentPitch += deltaPitch * deltaTimeF * AngularVelocityMagnitude;

            // Limit the pitch angle to +/- 90°.
            _currentPitch = MathHelper.Clamp(_currentPitch, -ConstantsF.PiOver2, ConstantsF.PiOver2);

            // Reset camera position if <Home> or <Right Stick> is pressed.
            if (_inputService.IsPressed(Keys.Home, false) ||
                _inputService.IsPressed(Buttons.RightStick, false, LogicalPlayerIndex.One))
            {
                ResetPose();
            }

            // Compute new orientation of the camera.
            QuaternionF orientation = QuaternionF.CreateRotationY(_currentYaw) * QuaternionF.CreateRotationX(_currentPitch);

            // Create velocity from <W>, <A>, <S>, <D> and <R>, <F> keys.
            // <R> or DPad up is used to move up ("rise").
            // <F> or DPad down is used to move down ("fall").
            Vector3F      velocity      = Vector3F.Zero;
            KeyboardState keyboardState = _inputService.KeyboardState;
            if (keyboardState.IsKeyDown(Keys.W))
            {
                velocity.Z--;
            }
            if (keyboardState.IsKeyDown(Keys.S))
            {
                velocity.Z++;
            }
            if (keyboardState.IsKeyDown(Keys.A))
            {
                velocity.X--;
            }
            if (keyboardState.IsKeyDown(Keys.D))
            {
                velocity.X++;
            }
            if (keyboardState.IsKeyDown(Keys.R) || gamePadState.DPad.Up == ButtonState.Pressed)
            {
                velocity.Y++;
            }
            if (keyboardState.IsKeyDown(Keys.F) || gamePadState.DPad.Down == ButtonState.Pressed)
            {
                velocity.Y--;
            }

            // Add velocity from gamepad sticks.
            velocity.X += gamePadState.ThumbSticks.Left.X;
            velocity.Z -= gamePadState.ThumbSticks.Left.Y;

            // Rotate the velocity vector from view space to world space.
            velocity = orientation.Rotate(velocity);

            if (keyboardState.IsKeyDown(Keys.LeftShift))
            {
                velocity *= SpeedBoost;
            }

            // Multiply the velocity by time to get the translation for this frame.
            Vector3F translation = velocity * LinearVelocityMagnitude * deltaTimeF;

            // Update SceneNode.LastPoseWorld - this is required for some effects, like
            // camera motion blur.
            CameraNode.LastPoseWorld = CameraNode.PoseWorld;

            // Set the new camera pose.
            CameraNode.PoseWorld = new Pose(
                CameraNode.PoseWorld.Position + translation,
                orientation);
#else
            // Only handle mouse movement is mouse button was down the last frame.
            if (!_inputService.IsPressed(MouseButtons.Left, false))
            {
                float deltaYaw = -mousePositionDelta.X;
                _currentYaw += deltaYaw * deltaTimeF * AngularVelocityMagnitude;
                float deltaPitch = -mousePositionDelta.Y;
                _currentPitch += deltaPitch * deltaTimeF * AngularVelocityMagnitude;

                // Limit the pitch angle.
                _currentPitch = MathHelper.Clamp(_currentPitch, -1, 1);

                // Compute new orientation of the camera.
                QuaternionF orientation = QuaternionF.CreateRotationY(_currentYaw) * QuaternionF.CreateRotationX(_currentPitch);

                var radius = CameraNode.PoseWorld.Position.Length;

                // Update SceneNode.LastPoseWorld - this is required for some effects, like
                // camera motion blur.
                CameraNode.LastPoseWorld = CameraNode.PoseWorld;

                // Set the new camera pose.
                CameraNode.PoseWorld = new Pose(orientation.Rotate(new Vector3F(0, 0, radius)), orientation);
            }
#endif
        }
Esempio n. 16
0
        private void Stroke(FigureNode node, ArrayList <Vector3F> strokeVertices, ArrayList <int> strokeIndices)
        {
            if (_mode != RenderMode.Stroke)
            {
                Flush();
                _strokeEffect.CurrentTechnique.Passes[0].Apply();
                _mode = RenderMode.Stroke;
            }

            // Use cached vertex buffer if available.
            var nodeRenderData = node.RenderData as FigureNodeRenderData;

            if (nodeRenderData != null && nodeRenderData.IsValid)
            {
                Flush();
                var graphicsDevice = _graphicsService.GraphicsDevice;
                graphicsDevice.SetVertexBuffer(nodeRenderData.StrokeVertexBuffer);
                graphicsDevice.Indices = nodeRenderData.StrokeIndexBuffer;
                int primitiveCount = nodeRenderData.StrokeIndexBuffer.IndexCount / 3;
#if MONOGAME
                graphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, primitiveCount);
#else
                int vertexCount = nodeRenderData.StrokeVertexBuffer.VertexCount;
                graphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, vertexCount, 0, primitiveCount);
#endif
                return;
            }

            var batchVertices = _strokeBatch.Vertices;

            var world     = node.PoseWorld * Matrix44F.CreateScale(node.ScaleWorld);
            var worldView = _view * world;

            var  thickness       = node.StrokeThickness;
            var  color3F         = node.StrokeColor * node.StrokeAlpha;
            var  color           = new HalfVector4(color3F.X, color3F.Y, color3F.Z, node.StrokeAlpha);
            var  dash            = node.StrokeDashPattern * node.StrokeThickness;
            bool usesDashPattern = (dash.Y + dash.Z) != 0;
            var  dashSum         = new HalfVector4(
                dash.X,
                dash.X + dash.Y,
                dash.X + dash.Y + dash.Z,
                dash.X + dash.Y + dash.Z + dash.W);

            // Convert to vertices.
            float    lastDistance  = 0;
            Vector3F lastPosition  = new Vector3F(float.NaN);
            Vector3F lastWorld     = new Vector3F();
            Vector3F lastView      = new Vector3F();
            Vector3F lastProjected = new Vector3F();

            var data0 = new HalfVector4(0, 1, thickness, 0);
            var data1 = new HalfVector4(0, 0, thickness, 0);
            var data2 = new HalfVector4(1, 0, thickness, 0);
            var data3 = new HalfVector4(1, 1, thickness, 0);

            Vector3F[] figurePoints         = strokeVertices.Array;
            int[]      figureIndices        = strokeIndices.Array;
            int        numberOfLineSegments = strokeIndices.Count / 2;

            for (int i = 0; i < numberOfLineSegments; i++)
            {
                var startIndex = figureIndices[i * 2 + 0];
                var endIndex   = figureIndices[i * 2 + 1];
                var start      = figurePoints[startIndex];
                var end        = figurePoints[endIndex];

                var notConnectedWithLast = start != lastPosition;
                lastPosition = end;

                Vector3F startWorld = notConnectedWithLast ? world.TransformPosition(start) : lastWorld;
                Vector3F endWorld   = world.TransformPosition(end);
                lastWorld = endWorld;

                // Compute start/end distances of lines from beginning of line strip
                // for dash patterns.
                float startDistance = 0;
                float endDistance   = 1;
                if (usesDashPattern)
                {
                    if (!node.DashInWorldSpace)
                    {
                        Vector3F startView = notConnectedWithLast ? worldView.TransformPosition(start) : lastView;
                        var      endView   = worldView.TransformPosition(end);
                        lastView = endView;

                        // Clip to near plane - otherwise lines which end near the camera origin
                        // (where planar z == 0) will disappear. (Projection singularity!)
                        float deltaZ = Math.Abs(startView.Z - endView.Z);
                        float pStart = MathHelper.Clamp((startView.Z - (-_cameraNear)) / deltaZ, 0, 1);
                        startView = InterpolationHelper.Lerp(startView, endView, pStart);
                        float pEnd = MathHelper.Clamp((endView.Z - (-_cameraNear)) / deltaZ, 0, 1);
                        endView = InterpolationHelper.Lerp(endView, startView, pEnd);

                        Vector3F startProjected;
                        if (notConnectedWithLast)
                        {
                            lastDistance   = 0;
                            startProjected = _viewport.ProjectToViewport(startView, _projection);
                        }
                        else
                        {
                            startProjected = lastProjected;
                        }
                        var endProjected = _viewport.ProjectToViewport(endView, _projection);
                        lastProjected = endProjected;

                        startDistance = lastDistance;
                        endDistance   = startDistance + (endProjected - startProjected).Length;
                        lastDistance  = endDistance;
                    }
                    else
                    {
                        if (notConnectedWithLast)
                        {
                            lastDistance = 0;
                        }

                        startDistance = lastDistance;
                        endDistance   = startDistance + (endWorld - startWorld).Length;
                        lastDistance  = endDistance;

                        // The shader needs to know that DashInWorldSpace is true. To avoid
                        // effect parameter changes, we store the value in the sign of the distance!
                        startDistance = -startDistance;
                        endDistance   = -endDistance;
                    }
                }

                var s = new Vector4(startWorld.X, startWorld.Y, startWorld.Z, startDistance);
                var e = new Vector4(endWorld.X, endWorld.Y, endWorld.Z, endDistance);

                int index, dummy;
                _strokeBatch.Submit(PrimitiveType.TriangleList, 4, 6, out index, out dummy);

                batchVertices[index + 0].Start = s;
                batchVertices[index + 0].End   = e;
                batchVertices[index + 0].Data  = data0;
                batchVertices[index + 0].Color = color;
                batchVertices[index + 0].Dash  = dashSum;

                batchVertices[index + 1].Start = s;
                batchVertices[index + 1].End   = e;
                batchVertices[index + 1].Data  = data1;
                batchVertices[index + 1].Color = color;
                batchVertices[index + 1].Dash  = dashSum;

                batchVertices[index + 2].Start = s;
                batchVertices[index + 2].End   = e;
                batchVertices[index + 2].Data  = data2;
                batchVertices[index + 2].Color = color;
                batchVertices[index + 2].Dash  = dashSum;

                batchVertices[index + 3].Start = s;
                batchVertices[index + 3].End   = e;
                batchVertices[index + 3].Data  = data3;
                batchVertices[index + 3].Color = color;
                batchVertices[index + 3].Dash  = dashSum;
            }
        }