// 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); }
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); }
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); }
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; }
// 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)); } }
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(); }
// 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)); } } }); }
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; } } }
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); } }
// 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); }
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 }
// 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 }
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; } }