public void SetBlock(Vector3 position, Block value) { position = position.Floor(); Vector3 relativePosition = position; position.X = (int)(position.X) / Chunk.Width; position.Y = 0; position.Z = (int)(position.Z) / Chunk.Depth; relativePosition.X = (int)(relativePosition.X) % Chunk.Width; relativePosition.Z = (int)(relativePosition.Z) % Chunk.Depth; if (!Chunks.ContainsKey(position)) Chunks.Add(position, WorldGenerator.GenerateChunk(position, this)); Chunks[position].SetBlock(relativePosition, value); }
private static void GenerateCurvedIllusionPlaneVertexData(HardwareVertexBuffer vertexBuffer, int ySegments, int xSegments, float xSpace, float halfWidth, float ySpace, float halfHeight, Matrix4 xform, bool firstTime, bool normals, Quaternion orientation, float cameraPosition, float sphereRadius, float uTiles, float vTiles, int numberOfTexCoordSets, ref Vector3 min, ref Vector3 max, ref float maxSquaredLength) { Vector3 vec; Vector3 norm; float sphereDistance; unsafe { // lock the vertex buffer IntPtr data = vertexBuffer.Lock(BufferLocking.Discard); float* pData = (float*)data.ToPointer(); for (int y = 0; y < ySegments + 1; ++y) { for (int x = 0; x < xSegments + 1; ++x) { // centered on origin vec.x = (x * xSpace) - halfWidth; vec.y = (y * ySpace) - halfHeight; vec.z = 0.0f; // transform by orientation and distance vec = xform * vec; // assign to geometry *pData++ = vec.x; *pData++ = vec.y; *pData++ = vec.z; // build bounds as we go if (firstTime) { min = vec; max = vec; maxSquaredLength = vec.LengthSquared; firstTime = false; } else { min.Floor(vec); max.Ceil(vec); maxSquaredLength = MathUtil.Max(maxSquaredLength, vec.LengthSquared); } if (normals) { norm = Vector3.UnitZ; norm = orientation * norm; *pData++ = vec.x; *pData++ = vec.y; *pData++ = vec.z; } // generate texture coordinates, normalize position, modify by orientation to return +y up vec = orientation.Inverse() * vec; vec.Normalize(); // find distance to sphere sphereDistance = MathUtil.Sqrt(cameraPosition * cameraPosition * (vec.y * vec.y - 1.0f) + sphereRadius * sphereRadius) - cameraPosition * vec.y; vec.x *= sphereDistance; vec.z *= sphereDistance; // use x and y on sphere as texture coordinates, tiled float s = vec.x * (0.01f * uTiles); float t = vec.z * (0.01f * vTiles); for (int i = 0; i < numberOfTexCoordSets; i++) { *pData++ = s; *pData++ = (1 - t); } } // x } // y // unlock the buffer vertexBuffer.Unlock(); } // unsafe }
public override void NotifyCurrentCamera( Camera cam ) { if ( this.mForcedRenderLevel >= 0 ) { this.mRenderLevel = this.mForcedRenderLevel; return; } var cpos = cam.DerivedPosition; var aabb = GetWorldBoundingBox( true ); var diff = new Vector3( 0, 0, 0 ); diff.Floor( cpos - aabb.Minimum ); diff.Ceil( cpos - aabb.Maximum ); var L = diff.LengthSquared; this.mRenderLevel = -1; for ( var i = 0; i < this.mOptions.maxGeoMipMapLevel; i++ ) { if ( this.mMinLevelDistSqr[ i ] > L ) { this.mRenderLevel = i - 1; break; } } if ( this.mRenderLevel < 0 ) { this.mRenderLevel = this.mOptions.maxGeoMipMapLevel - 1; } if ( this.mOptions.lodMorph ) { // Get the next LOD level down var nextLevel = this.mNextLevelDown[ this.mRenderLevel ]; if ( nextLevel == 0 ) { // No next level, so never morph this.mLODMorphFactor = 0; } else { // Set the morph such that the morph happens in the last 0.25 of // the distance range var range = this.mMinLevelDistSqr[ nextLevel ] - this.mMinLevelDistSqr[ this.mRenderLevel ]; if ( range > 0 ) { var percent = ( L - this.mMinLevelDistSqr[ this.mRenderLevel ] )/range; // scale result so that msLODMorphStart == 0, 1 == 1, clamp to 0 below that var rescale = 1.0f/( 1.0f - this.mOptions.lodMorphStart ); this.mLODMorphFactor = Math.Max( ( percent - this.mOptions.lodMorphStart )*rescale, 0.0 ); } else { // Identical ranges this.mLODMorphFactor = 0.0f; } //assert(mLODMorphFactor >= 0 && mLODMorphFactor <= 1); } // Bind the correct delta buffer if it has changed // nextLevel - 1 since the first entry is for LOD 1 (since LOD 0 never needs it) if ( this.mLastNextLevel != nextLevel ) { if ( nextLevel > 0 ) { this.mTerrain.vertexBufferBinding.SetBinding( (short)DELTA_BINDING, this.mDeltaBuffers[ nextLevel - 1 ] ); } else { // bind dummy (incase bindings checked) this.mTerrain.vertexBufferBinding.SetBinding( (short)DELTA_BINDING, this.mDeltaBuffers[ 0 ] ); } } this.mLastNextLevel = nextLevel; } }
public override void Update(IUpdateArgs args) { if (WaitingOnChunk && Age % 4 == 0) { NoAi = true; if (Level.GetChunk(KnownPosition.GetCoordinates3D(), true) != null) { Velocity = Vector3.Zero; WaitingOnChunk = false; NoAi = false; } } ChunkCoordinates oldChunkCoordinates = new ChunkCoordinates(base.KnownPosition); bool sprint = IsSprinting; bool sneak = IsSneaking; if (!CanFly && IsFlying) { IsFlying = false; } Controller.Update(args.GameTime); //KnownPosition.HeadYaw = KnownPosition.Yaw; if (IsSprinting && !sprint) { FOVModifier = 10; Network.EntityAction((int)EntityId, EntityAction.StartSprinting); } else if (!IsSprinting && sprint) { FOVModifier = 0; Network.EntityAction((int)EntityId, EntityAction.StopSprinting); } if (IsSneaking != sneak) { if (IsSneaking) { Network.EntityAction((int)EntityId, EntityAction.StartSneaking); Camera.UpdateOffset(new Vector3(0f, -0.15f, 0.35f)); } else { Network.EntityAction((int)EntityId, EntityAction.StopSneaking); Camera.UpdateOffset(Vector3.Zero); } } var previousCheckedInput = _prevCheckedInput; if ((Controller.CheckInput && Controller.CheckMovementInput)) { _prevCheckedInput = true; if (!previousCheckedInput || World.FormManager.IsShowingForm) { return; } UpdateRayTracer(); //if (Controller.InputManager.IsDown(InputCommand.LeftClick) && DateTime.UtcNow - _lastAnimate >= TimeSpan.FromMilliseconds(500)) //{ // SwingArm(true); //} var hitEntity = HitEntity; if (hitEntity != null && Controller.InputManager.IsPressed(InputCommand.LeftClick)) { if (_destroyingBlock) { StopBreakingBlock(forceCanceled: true); } InteractWithEntity(hitEntity, true); } else if (hitEntity != null && Controller.InputManager.IsPressed(InputCommand.RightClick)) { if (_destroyingBlock) { StopBreakingBlock(forceCanceled: true); } InteractWithEntity(hitEntity, false); } else if (hitEntity == null && !_destroyingBlock && Controller.InputManager.IsPressed(InputCommand.LeftClick) && !HasRaytraceResult) { SwingArm(true); } else if (hitEntity == null && !_destroyingBlock && Controller.InputManager.IsDown(InputCommand.LeftClick) && !IsWorldImmutable && HasRaytraceResult) //Destroying block. { StartBreakingBlock(); } else if (_destroyingBlock && Controller.InputManager.IsUp(InputCommand.LeftClick)) { StopBreakingBlock(); } else if (_destroyingBlock && Controller.InputManager.IsDown(InputCommand.LeftClick)) { if (_destroyingTarget != new BlockCoordinates(Vector3.Floor(Raytraced))) { StopBreakingBlock(true, true); if (Gamemode != Gamemode.Creative) { StartBreakingBlock(); } } else { if ((DateTime.UtcNow - _lastAnimate).TotalMilliseconds > 500) { _lastAnimate = DateTime.UtcNow; SwingArm(true); } var timeRan = (DateTime.UtcNow - _destroyingTick).TotalMilliseconds / 50d; if (timeRan >= _destroyTimeNeeded) { StopBreakingBlock(true); } } } else if (Controller.InputManager.IsPressed(InputCommand.RightClick)) { bool handledClick = false; var item = Inventory[Inventory.SelectedSlot]; // Log.Debug($"Right click!"); if (item != null) { handledClick = HandleRightClick(item, Inventory.SelectedSlot); } /*if (!handledClick && Inventory.OffHand != null && !(Inventory.OffHand is ItemAir)) * { * handledClick = HandleRightClick(Inventory.OffHand, 1); * }*/ } if (hitEntity != null && HasCollision) { if (IsColliding(hitEntity)) { //var distance = DistanceToHorizontal(hitEntity); // Velocity += (KnownPosition.ToVector3() - hitEntity.KnownPosition.ToVector3()); } } } else { if (_destroyingBlock) { StopBreakingBlock(); } _prevCheckedInput = false; _lastTimeWithoutInput = DateTime.UtcNow; } if (PreviousSlot != Inventory.SelectedSlot) { var slot = Inventory.SelectedSlot; Network?.HeldItemChanged(Inventory[Inventory.SelectedSlot], (short)slot); PreviousSlot = slot; } base.Update(args); }
public static Vector3 Floor(this Vector3 vector) { return(vector.Floor(Axes.XYZW)); }
private static void GenerateCurvedIllusionPlaneVertexData(HardwareVertexBuffer vertexBuffer, int ySegments, int xSegments, float xSpace, float halfWidth, float ySpace, float halfHeight, Matrix4 xform, bool firstTime, bool normals, Quaternion orientation, float cameraPosition, float sphereRadius, float uTiles, float vTiles, int numberOfTexCoordSets, ref Vector3 min, ref Vector3 max, ref float maxSquaredLength) { Vector3 vec; Vector3 norm; float sphereDistance; unsafe { // lock the vertex buffer IntPtr data = vertexBuffer.Lock(BufferLocking.Discard); float *pData = (float *)data.ToPointer(); for (int y = 0; y < ySegments + 1; ++y) { for (int x = 0; x < xSegments + 1; ++x) { // centered on origin vec.x = (x * xSpace) - halfWidth; vec.y = (y * ySpace) - halfHeight; vec.z = 0.0f; // transform by orientation and distance vec = xform * vec; // assign to geometry *pData++ = vec.x; *pData++ = vec.y; *pData++ = vec.z; // build bounds as we go if (firstTime) { min = vec; max = vec; maxSquaredLength = vec.LengthSquared; firstTime = false; } else { min.Floor(vec); max.Ceil(vec); maxSquaredLength = MathUtil.Max(maxSquaredLength, vec.LengthSquared); } if (normals) { norm = Vector3.UnitZ; norm = orientation * norm; *pData++ = vec.x; *pData++ = vec.y; *pData++ = vec.z; } // generate texture coordinates, normalize position, modify by orientation to return +y up vec = orientation.Inverse() * vec; vec.Normalize(); // find distance to sphere sphereDistance = MathUtil.Sqrt(cameraPosition * cameraPosition * (vec.y * vec.y - 1.0f) + sphereRadius * sphereRadius) - cameraPosition * vec.y; vec.x *= sphereDistance; vec.z *= sphereDistance; // use x and y on sphere as texture coordinates, tiled float s = vec.x * (0.01f * uTiles); float t = vec.z * (0.01f * vTiles); for (int i = 0; i < numberOfTexCoordSets; i++) { *pData++ = s; *pData++ = (1 - t); } } // x } // y // unlock the buffer vertexBuffer.Unlock(); } // unsafe }
private void _generateCurvedIllusionPlaneVertexData( HardwareVertexBuffer vertexBuffer, int ySegments, int xSegments, float xSpace, float halfWidth, float ySpace, float halfHeight, Matrix4 xform, bool firstTime, bool normals, Quaternion orientation, float curvature, float uTiles, float vTiles, int numberOfTexCoordSets, ref Vector3 min, ref Vector3 max, ref float maxSquaredLength ) { // Imagine a large sphere with the camera located near the top // The lower the curvature, the larger the sphere // Use the angle from viewer to the points on the plane // Credit to Aftershock for the general approach Real cameraPosition; // Camera position relative to sphere center // Derive sphere radius //Vector3 vertPos; // position relative to camera //Real sphDist; // Distance from camera to sphere along box vertex vector // Vector3 camToSph; // camera position to sphere Real sphereRadius;// Sphere radius // Actual values irrelevant, it's the relation between sphere radius and camera position that's important Real sphRadius = 100.0f; Real camDistance = 5.0f; sphereRadius = sphRadius - curvature; cameraPosition = sphereRadius - camDistance; Vector3 vec; Vector3 norm; float sphereDistance; unsafe { // lock the vertex buffer IntPtr data = vertexBuffer.Lock( BufferLocking.Discard ); float* pData = (float*)data.ToPointer(); for ( int y = 0; y < ySegments + 1; ++y ) { for ( int x = 0; x < xSegments + 1; ++x ) { // centered on origin vec.x = ( x * xSpace ) - halfWidth; vec.y = ( y * ySpace ) - halfHeight; vec.z = 0.0f; // transform by orientation and distance vec = xform * vec; // assign to geometry *pData++ = vec.x; *pData++ = vec.y; *pData++ = vec.z; // build bounds as we go if ( firstTime ) { min = vec; max = vec; maxSquaredLength = vec.LengthSquared; firstTime = false; } else { min.Floor( vec ); max.Ceil( vec ); maxSquaredLength = Utility.Max( maxSquaredLength, vec.LengthSquared ); } if ( normals ) { norm = Vector3.UnitZ; norm = orientation * norm; *pData++ = vec.x; *pData++ = vec.y; *pData++ = vec.z; } // generate texture coordinates, normalize position, modify by orientation to return +y up vec = orientation.Inverse() * vec; vec.Normalize(); // find distance to sphere sphereDistance = Utility.Sqrt( cameraPosition * cameraPosition * ( vec.y * vec.y - 1.0f ) + sphereRadius * sphereRadius ) - cameraPosition * vec.y; vec.x *= sphereDistance; vec.z *= sphereDistance; // use x and y on sphere as texture coordinates, tiled float s = vec.x * ( 0.01f * uTiles ); float t = vec.z * ( 0.01f * vTiles ); for ( int i = 0; i < numberOfTexCoordSets; i++ ) { *pData++ = s; *pData++ = ( 1 - t ); } } // x } // y // unlock the buffer vertexBuffer.Unlock(); } // unsafe }
private void _generatePlaneVertexData( HardwareVertexBuffer vbuf, int ySegments, int xSegments, float xSpace, float halfWidth, float ySpace, float halfHeight, Matrix4 transform, bool firstTime, bool normals, Matrix4 rotation, int numTexCoordSets, float xTexCoord, float yTexCoord, SubMesh subMesh, ref Vector3 min, ref Vector3 max, ref float maxSquaredLength ) { Vector3 vec; unsafe { // lock the vertex buffer IntPtr data = vbuf.Lock( BufferLocking.Discard ); float* pData = (float*)data.ToPointer(); for ( int y = 0; y <= ySegments; y++ ) { for ( int x = 0; x <= xSegments; x++ ) { // centered on origin vec.x = ( x * xSpace ) - halfWidth; vec.y = ( y * ySpace ) - halfHeight; vec.z = 0.0f; vec = transform.TransformAffine( vec ); *pData++ = vec.x; *pData++ = vec.y; *pData++ = vec.z; // Build bounds as we go if ( firstTime ) { min = vec; max = vec; maxSquaredLength = vec.LengthSquared; firstTime = false; } else { min.Floor( vec ); max.Ceil( vec ); maxSquaredLength = Utility.Max( maxSquaredLength, vec.LengthSquared ); } if ( normals ) { vec = Vector3.UnitZ; vec = rotation.TransformAffine( vec ); *pData++ = vec.x; *pData++ = vec.y; *pData++ = vec.z; } for ( int i = 0; i < numTexCoordSets; i++ ) { *pData++ = x * xTexCoord; *pData++ = 1 - ( y * yTexCoord ); } // for texCoords } // for x } // for y // unlock the buffer vbuf.Unlock(); subMesh.useSharedVertices = true; } // unsafe }
private void InitDebugInfo() { string gameVersion = VersionUtils.GetVersion(); _debugInfo.AddDebugLeft( () => { double avg = 0; /* if (World.ChunkManager.TotalChunkUpdates > 0) * { * avg = (World.ChunkManager.ChunkUpdateTime / World.ChunkManager.TotalChunkUpdates) * .TotalMilliseconds; * }*/ return ($"Alex {gameVersion} ({Alex.FpsMonitor.Value:##} FPS, {World.Ticker.TicksPerSecond:##} TPS, Chunk Updates: {World.EnqueuedChunkUpdates} queued, {World.ConcurrentChunkUpdates} active)"); }, TimeSpan.FromMilliseconds(50)); _debugInfo.AddDebugLeft(() => { var pos = World.Player.KnownPosition; var blockPos = pos.GetCoordinates3D(); return($"Position: (X={pos.X:F2}, Y={pos.Y:F2}, Z={pos.Z:F2}, OnGround={pos.OnGround}) / Block: ({blockPos.X:D}, {blockPos.Y:D}, {blockPos.Z:D})"); }); _debugInfo.AddDebugLeft(() => { var pos = World.Player.KnownPosition; return($"Facing: {GetCardinalDirection(pos)} (HeadYaw={pos.HeadYaw:F2}, Yaw={pos.Yaw:F2}, Pitch={pos.Pitch:F2})"); }); _debugInfo.AddDebugLeft(() => { var pos = World.Player.Velocity; return($"Velocity: (X={pos.X:F2}, Y={pos.Y:F2}, Z={pos.Z:F2}) ({World.Player.CurrentSpeed:F3} m/s)"); // / Target Speed: {(World.Player.CalculateMovementSpeed() * 20f):F3} m/s"; }); _debugInfo.AddDebugLeft(() => $"Vertices: {World.Vertices:N0} ({GetBytesReadable((long)(World.Vertices * BlockShaderVertex.VertexDeclaration.VertexStride))})", TimeSpan.FromMilliseconds(500)); // _debugInfo.AddDebugLeft(() => $"IndexBuffer Elements: {World.IndexBufferSize:N0} ({GetBytesReadable(World.IndexBufferSize * 4)})"); _debugInfo.AddDebugLeft(() => $"Chunks: {World.ChunkCount}, {World.ChunkManager.RenderedChunks}", TimeSpan.FromMilliseconds(500)); _debugInfo.AddDebugLeft(() => $"Entities: {World.EntityManager.EntityCount}, {World.EntityManager.EntitiesRendered}", TimeSpan.FromMilliseconds(500)); _debugInfo.AddDebugLeft(() => { return($"Biome: {_currentBiome.Name} ({_currentBiomeId})"); }, TimeSpan.FromMilliseconds(500)); //_debugInfo.AddDebugLeft(() => { return $"Do DaylightCycle: {World.DoDaylightcycle}"; }); _debugInfo.AddDebugRight(Alex.OperatingSystem); _debugInfo.AddDebugRight(Alex.Gpu); _debugInfo.AddDebugRight($"{Alex.DotnetRuntime}\n"); _debugInfo.AddDebugRight(Alex.RenderingEngine); //_debugInfo.AddDebugRight(() => MemoryUsageDisplay); _debugInfo.AddDebugRight(() => $"RAM: {GetBytesReadable(_ramUsage, 2)}", TimeSpan.FromMilliseconds(1000)); _debugInfo.AddDebugRight(() => $"GPU: {GetBytesReadable(GpuResourceManager.GetMemoryUsage, 2)}", TimeSpan.FromMilliseconds(1000)); _debugInfo.AddDebugRight(() => { return ($"Threads: {(_threadsUsed):00}/{_maxThreads}"); }, TimeSpan.FromMilliseconds(50)); _debugInfo.AddDebugRight(() => { var player = World?.Player; if (player == null) { return(""); } if (player.HasRaytraceResult) { var raytracedBlock = player.RaytracedBlock; var adjacentBlock = player.AdjacentRaytraceBlock; var adj = Vector3.Floor(adjacentBlock) - Vector3.Floor(raytracedBlock); adj.Normalize(); var face = adj.GetBlockFace(); StringBuilder sb = new StringBuilder(); sb.AppendLine($"Target: {raytracedBlock} Face: {face}"); sb.AppendLine( $"Skylight: {World.GetSkyLight(raytracedBlock)} Face Skylight: {World.GetSkyLight(adjacentBlock)}"); sb.AppendLine( $"Blocklight: {World.GetBlockLight(raytracedBlock)} Face Blocklight: {World.GetBlockLight(adjacentBlock)}"); //sb.AppendLine($"Skylight scheduled: {World.IsScheduled((int) _raytracedBlock.X, (int) _raytracedBlock.Y, (int) _raytracedBlock.Z)}"); foreach (var bs in World .GetBlockStates((int)raytracedBlock.X, (int)raytracedBlock.Y, (int)raytracedBlock.Z)) { var blockstate = bs.State; if (blockstate != null && blockstate.Block.HasHitbox) { sb.AppendLine($"{blockstate.Name} (S: {bs.Storage})"); /*if (blockstate.IsMultiPart) * { * sb.AppendLine($"MultiPart=true"); * sb.AppendLine(); * * sb.AppendLine("Models:"); * * foreach (var model in blockstate.AppliedModels) * { * sb.AppendLine(model); * } * }*/ var dict = blockstate.ToDictionary(); if (dict.Count > 0) { sb.AppendLine(); sb.AppendLine("Blockstate:"); foreach (var kv in dict) { sb.AppendLine($"{kv.Key}={kv.Value}"); } } } } return(sb.ToString()); } else { return(string.Empty); } }, TimeSpan.FromMilliseconds(500)); _debugInfo.AddDebugRight(() => { var player = World.Player; if (player == null || player.HitEntity == null) { return(string.Empty); } var entity = player.HitEntity; return($"Hit entity: {entity.EntityId} / {entity.ToString()}"); }, TimeSpan.FromMilliseconds(500)); }
private bool HandleClick(Item slot, int hand, bool canModifyWorld = true, bool isLeftClick = false) { SwingArm(true); //if (ItemFactory.ResolveItemName(slot.ItemID, out string itemName)) { var flooredAdj = Vector3.Floor(AdjacentRaytrace); var raytraceFloored = Vector3.Floor(Raytraced); var adj = flooredAdj - raytraceFloored; adj.Normalize(); var face = adj.GetBlockFace(); var remainder = new Vector3(AdjacentRaytrace.X - flooredAdj.X, AdjacentRaytrace.Y - flooredAdj.Y, AdjacentRaytrace.Z - flooredAdj.Z); var coordR = new BlockCoordinates(raytraceFloored); //IBlock block = null; if (!IsWorldImmutable && HasRaytraceResult) { var existingBlock = Level.GetBlock(coordR); bool isBlockItem = slot is ItemBlock; if (existingBlock.CanInteract && (!isBlockItem || IsSneaking)) { Network?.WorldInteraction(coordR, face, hand, remainder); return(true); } if (slot is ItemBlock ib && canModifyWorld) { BlockState blockState = ib.Block; if (blockState != null && !(blockState.Block is Air) && HasRaytraceResult) { if (existingBlock.IsReplacible || !existingBlock.Solid) { if (CanPlaceBlock(coordR, (Block)blockState.Block)) { Level.SetBlockState(coordR, blockState); Network?.BlockPlaced(coordR.BlockDown(), BlockFace.Up, hand, remainder, this); return(true); } } else { var target = new BlockCoordinates(raytraceFloored + adj); if (CanPlaceBlock(target, (Block)blockState.Block)) { Level.SetBlockState(target, blockState); Network?.BlockPlaced(coordR, face, hand, remainder, this); return(true); } } } } } if (!(slot is ItemAir) && slot.Id > 0 && slot.Count > 0) { ItemUseAction action; if (isLeftClick) { action = HasRaytraceResult ? ItemUseAction.ClickBlock : ItemUseAction.ClickAir; } else { action = HasRaytraceResult ? ItemUseAction.RightClickBlock : ItemUseAction.RightClickAir; } Network?.UseItem(slot, hand, action); return(true); } } return(false); }
public static Vector3 Frac(this Vector3 v) => v - v.Floor();
private void SetHighlightBlockPos() { HighlightBlockPos = new Vector3Int(-1, -1, -1); Vector3 dir = cam.forward; List <float> ts = new List <float>(); float x = cam.position.x % 1; float y = cam.position.y % 1; float z = cam.position.z % 1; if (dir.x != 0) { for (float r = 1; r < Range; r++) { if (dir.x > 0) { ts.Add((r - x) / dir.x + 0.01f); } else { ts.Add((-r - x + 1) / dir.x + 0.01f); } } } if (dir.y != 0) { for (float r = 1; r < Range; r++) { if (dir.y > 0) { ts.Add((r - y) / dir.y + 0.01f); } else { ts.Add((-r - y + 1) / dir.y + 0.01f); } } } if (dir.z != 0) { for (float r = 1; r < Range; r++) { if (dir.z > 0) { ts.Add((r - z) / dir.z + 0.01f); } else { ts.Add((-r - z + 1) / dir.z + 0.01f); } } } ts.Sort(); int t = 0; while (HighlightBlockPos.x < 0 && t < ts.Count && ts[t] < Range) { LookAtPoint = (dir * ts[t] + cam.position); Vector3Int block = LookAtPoint.Floor(); if (world.GetBlockTypeAt(block) != 0) { HighlightBlockPos = block; } ++t; } HighlightBlock.position = HighlightBlockPos + new Vector3(0.5f, 0.5f, 0.5f); }
protected virtual void _updateFrustum() { Real vpTop, vpRight, vpBottom, vpLeft; CalculateProjectionParameters( out vpLeft, out vpRight, out vpBottom, out vpTop ); if ( !this._customProjectionMatrix ) { // The code below will dealing with general projection // parameters, similar glFrustum and glOrtho. // Doesn't optimise manually except division operator, so the // code more self-explaining. Real inv_w = 1.0f/( vpRight - vpLeft ); Real inv_h = 1.0f/( vpTop - vpBottom ); Real inv_d = 1.0f/( this._farDistance - this._nearDistance ); // Recalc if frustum params changed if ( this._projectionType == Projection.Perspective ) { // Calc matrix elements Real A = 2.0f*this._nearDistance*inv_w; Real B = 2.0f*this._nearDistance*inv_h; Real C = ( vpRight + vpLeft )*inv_w; Real D = ( vpTop + vpBottom )*inv_h; Real q, qn; if ( this._farDistance == 0.0f ) { // Infinite far plane q = Frustum.InfiniteFarPlaneAdjust - 1.0f; qn = this._nearDistance*( Frustum.InfiniteFarPlaneAdjust - 2.0f ); } else { q = -( this._farDistance + this._nearDistance )*inv_d; qn = -2.0f*( this._farDistance*this._nearDistance )*inv_d; } // NB: This creates 'uniform' perspective projection matrix, // which depth range [-1,1], right-handed rules // // [ A 0 C 0 ] // [ 0 B D 0 ] // [ 0 0 q qn ] // [ 0 0 -1 0 ] // // A = 2 * near / (right - left) // B = 2 * near / (top - bottom) // C = (right + left) / (right - left) // D = (top + bottom) / (top - bottom) // q = - (far + near) / (far - near) // qn = - 2 * (far * near) / (far - near) this._projectionMatrix = Matrix4.Zero; this._projectionMatrix.m00 = A; this._projectionMatrix.m02 = C; this._projectionMatrix.m11 = B; this._projectionMatrix.m12 = D; this._projectionMatrix.m22 = q; this._projectionMatrix.m23 = qn; this._projectionMatrix.m32 = -1.0f; if ( this.useObliqueDepthProjection ) { // Translate the plane into view space // Don't use getViewMatrix here, incase overrided by // camera and return a cull frustum view matrix UpdateView(); var plane = this._viewMatrix*this.obliqueProjPlane; // Thanks to Eric Lenyel for posting this calculation // at www.terathon.com // Calculate the clip-space corner point opposite the // clipping plane // as (sgn(clipPlane.x), sgn(clipPlane.y), 1, 1) and // transform it into camera space by multiplying it // by the inverse of the projection matrix /* generalised version Vector4 q = matrix.inverse() * Vector4(Math::Sign(plane.normal.x), Math::Sign(plane.normal.y), 1.0f, 1.0f); */ var q1 = new Vector4(); q1.x = ( System.Math.Sign( plane.Normal.x ) + this._projectionMatrix.m02 )/this._projectionMatrix.m00; q1.y = ( System.Math.Sign( plane.Normal.y ) + this._projectionMatrix.m12 )/this._projectionMatrix.m11; q1.z = -1.0f; q1.w = ( 1.0f + this._projectionMatrix.m22 )/this._projectionMatrix.m23; // Calculate the scaled plane vector var clipPlane4d = new Vector4( plane.Normal.x, plane.Normal.y, plane.Normal.z, plane.D ); var c = clipPlane4d*( 2.0f/( clipPlane4d.Dot( q1 ) ) ); // Replace the third row of the projection matrix this._projectionMatrix.m20 = c.x; this._projectionMatrix.m21 = c.y; this._projectionMatrix.m22 = c.z + 1.0f; this._projectionMatrix.m23 = c.w; } } // perspective else if ( this._projectionType == Projection.Orthographic ) { var A = 2.0f*inv_w; var B = 2.0f*inv_h; Real C = -( vpRight + vpLeft )*inv_w; Real D = -( vpTop + vpBottom )*inv_h; Real q, qn; if ( this._farDistance == 0.0f ) { // Can not do infinite far plane here, avoid divided zero only q = -Frustum.InfiniteFarPlaneAdjust/this._nearDistance; qn = -Frustum.InfiniteFarPlaneAdjust - 1.0f; } else { q = -2.0f*inv_d; qn = -( this._farDistance + this._nearDistance )*inv_d; } // NB: This creates 'uniform' orthographic projection matrix, // which depth range [-1,1], right-handed rules // // [ A 0 0 C ] // [ 0 B 0 D ] // [ 0 0 q qn ] // [ 0 0 0 1 ] // // A = 2 * / (right - left) // B = 2 * / (top - bottom) // C = - (right + left) / (right - left) // D = - (top + bottom) / (top - bottom) // q = - 2 / (far - near) // qn = - (far + near) / (far - near) this._projectionMatrix = Matrix4.Zero; this._projectionMatrix.m00 = A; this._projectionMatrix.m03 = C; this._projectionMatrix.m11 = B; this._projectionMatrix.m13 = D; this._projectionMatrix.m22 = q; this._projectionMatrix.m23 = qn; this._projectionMatrix.m33 = 1.0f; } // ortho } // if !_customProjectionMatrix // grab a reference to the current render system var renderSystem = Root.Instance.RenderSystem; // API specific renderSystem.ConvertProjectionMatrix( this._projectionMatrix, out this._projectionMatrixRS ); // API specific for Gpu Programs renderSystem.ConvertProjectionMatrix( this._projectionMatrix, out this._projectionMatrixRSDepth, true ); // Calculate bounding box (local) // Box is from 0, down -Z, max dimensions as determined from far plane // If infinite view frustum just pick a far value var farDist = ( this._farDistance == 0.0f ) ? InfiniteFarPlaneDistance : this._farDistance; // Near plane bounds var min = new Vector3( vpLeft, vpBottom, -farDist ); var max = new Vector3( vpRight, vpTop, 0 ); if ( this._customProjectionMatrix ) { // Some custom projection matrices can have unusual inverted settings // So make sure the AABB is the right way around to start with var tmp = min; min.Floor( max ); max.Ceil( tmp ); } var radio = 1.0f; if ( this._projectionType == Projection.Perspective ) { // Merge with far plane bounds radio = this._farDistance/this._nearDistance; min.Floor( new Vector3( vpLeft*radio, vpBottom*radio, -this._farDistance ) ); max.Ceil( new Vector3( vpRight*radio, vpTop*radio, 0 ) ); } this._boundingBox.SetExtents( min, max ); this._recalculateFrustum = false; // Signal to update frustum clipping planes this._recalculateFrustumPlanes = true; }
/// <summary> /// Sets up the surface by defining it's control points, type and initial subdivision level. /// </summary> /// <remarks> /// This method initialises the surface by passing it a set of control points. The type of curves to be used /// are also defined here, although the only supported option currently is a bezier patch. You can also /// specify a global subdivision level here if you like, although it is recommended that the parameter /// is left as AUTO_LEVEL, which means the system decides how much subdivision is required (based on the /// curvature of the surface). /// </remarks> /// <param name="controlPoints"> /// A pointer to a buffer containing the vertex data which defines control points /// of the curves rather than actual vertices. Note that you are expected to provide not /// just position information, but potentially normals and texture coordinates too. The /// format of the buffer is defined in the VertexDeclaration parameter. /// </param> /// <param name="decl"> /// VertexDeclaration describing the contents of the buffer. /// Note this declaration must _only_ draw on buffer source 0! /// </param> /// <param name="width">Specifies the width of the patch in control points.</param> /// <param name="height">Specifies the height of the patch in control points.</param> /// <param name="type">The type of surface.</param> /// <param name="uMaxSubdivisionLevel"> /// If you want to manually set the top level of subdivision, /// do it here, otherwise let the system decide. /// </param> /// <param name="vMaxSubdivisionLevel"> /// If you want to manually set the top level of subdivision, /// do it here, otherwise let the system decide. /// </param> /// <param name="side">Determines which side of the patch (or both) triangles are generated for.</param> public unsafe void DefineSurface(System.Array controlPointBuffer, VertexDeclaration declaration, int width, int height, PatchSurfaceType type, int uMaxSubdivisionLevel, int vMaxSubdivisionLevel, VisibleSide visibleSide) { if (height == 0 || width == 0) { return; // Do nothing - garbage } this.type = type; this.controlWidth = width; this.controlHeight = height; this.controlCount = width * height; this.controlPointBuffer = controlPointBuffer; this.declaration = declaration; // Copy positions into Vector3 vector controlPoints.Clear(); VertexElement elem = declaration.FindElementBySemantic(VertexElementSemantic.Position); int vertSize = declaration.GetVertexSize(0); byte * pVert = (byte *)Marshal.UnsafeAddrOfPinnedArrayElement(controlPointBuffer, 0); float * pReal = null; for (int i = 0; i < controlCount; i++) { pReal = (float *)(pVert + elem.Offset); controlPoints.Add(new Vector3(pReal[0], pReal[1], pReal[2])); pVert += vertSize; } this.side = visibleSide; // Determine max level // Initialise to 100% detail subdivisionFactor = 1.0f; if (uMaxSubdivisionLevel == AUTO_LEVEL) { uLevel = maxULevel = GetAutoULevel(); } else { uLevel = maxULevel = uMaxSubdivisionLevel; } if (vMaxSubdivisionLevel == AUTO_LEVEL) { vLevel = maxVLevel = GetAutoVLevel(); } else { vLevel = maxVLevel = vMaxSubdivisionLevel; } // Derive mesh width / height meshWidth = (LevelWidth(maxULevel) - 1) * ((controlWidth - 1) / 2) + 1; meshHeight = (LevelWidth(maxVLevel) - 1) * ((controlHeight - 1) / 2) + 1; // Calculate number of required vertices / indexes at max resolution requiredVertexCount = meshWidth * meshHeight; int iterations = (side == VisibleSide.Both)? 2 : 1; requiredIndexCount = (meshWidth - 1) * (meshHeight - 1) * 2 * iterations * 3; // Calculate bounds based on control points Vector3 min = Vector3.Zero; Vector3 max = Vector3.Zero; float maxSqRadius = 0.0f; bool first = true; for (int i = 0; i < controlPoints.Count; i++) { Vector3 vec = controlPoints[i]; if (first) { min = max = vec; maxSqRadius = vec.LengthSquared; first = false; } else { min.Floor(vec); max.Ceil(vec); maxSqRadius = MathUtil.Max(vec.LengthSquared, maxSqRadius); } } // set the bounds of the patch aabb.SetExtents(min, max); boundingSphereRadius = MathUtil.Sqrt(maxSqRadius); }
/* Test if a scene node intersected a portal during the last time delta * (from last frame time to current frame time). This function checks * if the node "crossed over" the portal also. */ public PortalIntersectResult intersects( PCZSceneNode pczsn ) { // Only check if portal is open if ( mOpen ) { if ( pczsn == mNode ) { // ignore the scene node if it is the node the portal is associated with return PortalIntersectResult.NO_INTERSECT; } // most complicated case - if the portal is a quad: if ( mType == PORTAL_TYPE.PORTAL_TYPE_QUAD ) { // the node is modeled as a line segment (prevPostion to currentPosition) // intersection test is then between the capsule and the line segment. Segment nodeSegment = new Segment(); nodeSegment.Set( pczsn.PreviousPosition, pczsn.DerivedPosition ); // we model the portal as a line swept sphere (mPrevDerivedCP to mDerivedCP). Capsule portalCapsule = new Capsule(); portalCapsule.Set( mPrevDerivedCP, mDerivedCP, mRadius ); if ( portalCapsule.Intersects( nodeSegment ) ) { // the portal intersected the node at some time from last frame to this frame. // Now check if node "crossed" the portal // a crossing occurs if the "side" of the final position of the node compared // to the final position of the portal is negative AND the initial position // of the node compared to the initial position of the portal is non-negative if ( mDerivedPlane.GetSide( pczsn.DerivedPosition ) == PlaneSide.Negative && mPrevDerivedPlane.GetSide( pczsn.DerivedPosition ) != PlaneSide.Negative ) { // safety check - make sure the node has at least one dimension which is // small enough to fit through the portal! (avoid the "elephant fitting // through a mouse hole" case) Vector3 nodeHalfVector = pczsn.WorldAABB.HalfSize; Vector3 portalBox = new Vector3( mRadius, mRadius, mRadius ); portalBox.Floor( nodeHalfVector ); if ( portalBox.x < mRadius ) { // crossing occurred! return PortalIntersectResult.INTERSECT_CROSS; } } } // there was no crossing of the portal by the node, but it might be touching // the portal. We check for this by checking the bounding box of the node vs. // the sphere of the portal if ( mDerivedSphere.Intersects( pczsn.WorldAABB ) && mDerivedPlane.GetSide( pczsn.WorldAABB ) == PlaneSide.Both ) { // intersection but no crossing // note this means that the node is CURRENTLY touching the portal. if ( mDerivedPlane.GetSide( pczsn.DerivedPosition ) != PlaneSide.Negative ) { // the node is on the positive (front) or exactly on the CP of the portal return PortalIntersectResult.INTERSECT_NO_CROSS; } else { // the node is on the negative (back) side of the portal - it might be in the wrong zone! return PortalIntersectResult.INTERSECT_BACK_NO_CROSS; } } // no intersection CURRENTLY. (there might have been an intersection // during the time between last frame and this frame, but it wasn't a portal // crossing, and it isn't touching anymore, so it doesn't matter. return PortalIntersectResult.NO_INTERSECT; } else if ( mType == PORTAL_TYPE.PORTAL_TYPE_AABB ) { // for aabb's we check if the center point went from being inside to being outside // the aabb (or vice versa) for crossing. AxisAlignedBox aabb = new AxisAlignedBox( mDerivedCorners[ 0 ], mDerivedCorners[ 1 ] ); //bool previousInside = aabb.contains(pczsn->getPrevPosition()); bool currentInside = aabb.Contains( pczsn.DerivedPosition ); if ( mDirection == Vector3.UnitZ ) { // portal norm is "outward" pointing, look for going from outside to inside //if (previousInside == false && if ( currentInside == true ) { return PortalIntersectResult.INTERSECT_CROSS; } } else { // portal norm is "inward" pointing, look for going from inside to outside //if (previousInside == true && if ( currentInside == false ) { return PortalIntersectResult.INTERSECT_CROSS; } } // doesn't cross, but might be touching. This is a little tricky because we only // care if the node aab is NOT fully contained in the portal aabb because we consider // the surface of the portal aabb the actual 'portal'. First, check to see if the // aab of the node intersects the aabb portal if ( aabb.Intersects( pczsn.WorldAABB ) ) { // now check if the intersection between the two is not the same as the // full node aabb, if so, then this means that the node is not fully "contained" // which is what we are looking for. AxisAlignedBox overlap = aabb.Intersection( pczsn.WorldAABB ); if ( overlap != pczsn.WorldAABB ) { return PortalIntersectResult.INTERSECT_NO_CROSS; } } return PortalIntersectResult.NO_INTERSECT; } else { // for spheres we check if the center point went from being inside to being outside // the sphere surface (or vice versa) for crossing. //Real previousDistance2 = mPrevDerivedCP.squaredDistance(pczsn->getPrevPosition()); Real currentDistance2 = mDerivedCP.DistanceSquared( pczsn.DerivedPosition ); Real mRadius2 = mRadius * mRadius; if ( mDirection == Vector3.UnitZ ) { // portal norm is "outward" pointing, look for going from outside to inside //if (previousDistance2 >= mRadius2 && if ( currentDistance2 < mRadius2 ) { return PortalIntersectResult.INTERSECT_CROSS; } } else { // portal norm is "inward" pointing, look for going from inside to outside //if (previousDistance2 < mRadius2 && if ( currentDistance2 >= mRadius2 ) { return PortalIntersectResult.INTERSECT_CROSS; } } // no crossing, but might be touching - check distance if ( System.Math.Sqrt( System.Math.Abs( mRadius2 - currentDistance2 ) ) <= mRadius ) { return PortalIntersectResult.INTERSECT_NO_CROSS; } return PortalIntersectResult.NO_INTERSECT; } } return PortalIntersectResult.NO_INTERSECT; }
/// <summary> /// Utility method for extruding a bounding box. /// </summary> /// <param name="box">Original bounding box, will be updated in-place.</param> /// <param name="lightPosition">4D light position in object space, when w=0.0f this /// represents a directional light</param> /// <param name="extrudeDistance">The distance to extrude.</param> protected virtual void ExtrudeBounds( AxisAlignedBox box, Vector4 lightPosition, float extrudeDistance ) { Vector3 extrusionDir = Vector3.Zero; if ( lightPosition.w == 0 ) { extrusionDir.x = -lightPosition.x; extrusionDir.y = -lightPosition.y; extrusionDir.z = -lightPosition.z; extrusionDir.Normalize(); extrusionDir *= extrudeDistance; box.SetExtents( box.Minimum + extrusionDir, box.Maximum + extrusionDir ); } else { Vector3[] corners = box.Corners; Vector3 vmin = new Vector3(); Vector3 vmax = new Vector3(); for ( int i = 0; i < 8; i++ ) { extrusionDir.x = corners[ i ].x - lightPosition.x; extrusionDir.y = corners[ i ].y - lightPosition.y; extrusionDir.z = corners[ i ].z - lightPosition.z; extrusionDir.Normalize(); extrusionDir *= extrudeDistance; Vector3 res = corners[ i ] + extrusionDir; if ( i == 0 ) { vmin = res; vmax = res; } else { vmin.Floor( res ); vmax.Ceil( res ); } } box.SetExtents( vmin, vmax ); } }
/* Test if a scene node intersected a portal during the last time delta * (from last frame time to current frame time). This function checks * if the node "crossed over" the portal also. */ public PortalIntersectResult intersects(PCZSceneNode pczsn) { // Only check if portal is open if (this.mOpen) { if (pczsn == this.mNode) { // ignore the scene node if it is the node the portal is associated with return(PortalIntersectResult.NO_INTERSECT); } // most complicated case - if the portal is a quad: if (this.mType == PORTAL_TYPE.PORTAL_TYPE_QUAD) { // the node is modeled as a line segment (prevPostion to currentPosition) // intersection test is then between the capsule and the line segment. var nodeSegment = new Segment(); nodeSegment.Set(pczsn.PreviousPosition, pczsn.DerivedPosition); // we model the portal as a line swept sphere (mPrevDerivedCP to mDerivedCP). var portalCapsule = new Capsule(); portalCapsule.Set(this.mPrevDerivedCP, this.mDerivedCP, this.mRadius); if (portalCapsule.Intersects(nodeSegment)) { // the portal intersected the node at some time from last frame to this frame. // Now check if node "crossed" the portal // a crossing occurs if the "side" of the final position of the node compared // to the final position of the portal is negative AND the initial position // of the node compared to the initial position of the portal is non-negative if (this.mDerivedPlane.GetSide(pczsn.DerivedPosition) == PlaneSide.Negative && this.mPrevDerivedPlane.GetSide(pczsn.DerivedPosition) != PlaneSide.Negative) { // safety check - make sure the node has at least one dimension which is // small enough to fit through the portal! (avoid the "elephant fitting // through a mouse hole" case) Vector3 nodeHalfVector = pczsn.WorldAABB.HalfSize; var portalBox = new Vector3(this.mRadius, this.mRadius, this.mRadius); portalBox.Floor(nodeHalfVector); if (portalBox.x < this.mRadius) { // crossing occurred! return(PortalIntersectResult.INTERSECT_CROSS); } } } // there was no crossing of the portal by the node, but it might be touching // the portal. We check for this by checking the bounding box of the node vs. // the sphere of the portal if (this.mDerivedSphere.Intersects(pczsn.WorldAABB) && this.mDerivedPlane.GetSide(pczsn.WorldAABB) == PlaneSide.Both) { // intersection but no crossing // note this means that the node is CURRENTLY touching the portal. if (this.mDerivedPlane.GetSide(pczsn.DerivedPosition) != PlaneSide.Negative) { // the node is on the positive (front) or exactly on the CP of the portal return(PortalIntersectResult.INTERSECT_NO_CROSS); } else { // the node is on the negative (back) side of the portal - it might be in the wrong zone! return(PortalIntersectResult.INTERSECT_BACK_NO_CROSS); } } // no intersection CURRENTLY. (there might have been an intersection // during the time between last frame and this frame, but it wasn't a portal // crossing, and it isn't touching anymore, so it doesn't matter. return(PortalIntersectResult.NO_INTERSECT); } else if (this.mType == PORTAL_TYPE.PORTAL_TYPE_AABB) { // for aabb's we check if the center point went from being inside to being outside // the aabb (or vice versa) for crossing. var aabb = new AxisAlignedBox(this.mDerivedCorners[0], this.mDerivedCorners[1]); //bool previousInside = aabb.contains(pczsn->getPrevPosition()); bool currentInside = aabb.Contains(pczsn.DerivedPosition); if (this.mDirection == Vector3.UnitZ) { // portal norm is "outward" pointing, look for going from outside to inside //if (previousInside == false && if (currentInside == true) { return(PortalIntersectResult.INTERSECT_CROSS); } } else { // portal norm is "inward" pointing, look for going from inside to outside //if (previousInside == true && if (currentInside == false) { return(PortalIntersectResult.INTERSECT_CROSS); } } // doesn't cross, but might be touching. This is a little tricky because we only // care if the node aab is NOT fully contained in the portal aabb because we consider // the surface of the portal aabb the actual 'portal'. First, check to see if the // aab of the node intersects the aabb portal if (aabb.Intersects(pczsn.WorldAABB)) { // now check if the intersection between the two is not the same as the // full node aabb, if so, then this means that the node is not fully "contained" // which is what we are looking for. AxisAlignedBox overlap = aabb.Intersection(pczsn.WorldAABB); if (overlap != pczsn.WorldAABB) { return(PortalIntersectResult.INTERSECT_NO_CROSS); } } return(PortalIntersectResult.NO_INTERSECT); } else { // for spheres we check if the center point went from being inside to being outside // the sphere surface (or vice versa) for crossing. //Real previousDistance2 = mPrevDerivedCP.squaredDistance(pczsn->getPrevPosition()); Real currentDistance2 = this.mDerivedCP.DistanceSquared(pczsn.DerivedPosition); Real mRadius2 = this.mRadius * this.mRadius; if (this.mDirection == Vector3.UnitZ) { // portal norm is "outward" pointing, look for going from outside to inside //if (previousDistance2 >= mRadius2 && if (currentDistance2 < mRadius2) { return(PortalIntersectResult.INTERSECT_CROSS); } } else { // portal norm is "inward" pointing, look for going from inside to outside //if (previousDistance2 < mRadius2 && if (currentDistance2 >= mRadius2) { return(PortalIntersectResult.INTERSECT_CROSS); } } // no crossing, but might be touching - check distance if (System.Math.Sqrt(System.Math.Abs(mRadius2 - currentDistance2)) <= this.mRadius) { return(PortalIntersectResult.INTERSECT_NO_CROSS); } return(PortalIntersectResult.NO_INTERSECT); } } return(PortalIntersectResult.NO_INTERSECT); }
public override void Update(IUpdateArgs args) { ChunkCoordinates oldChunkCoordinates = new ChunkCoordinates(base.KnownPosition); bool sprint = IsSprinting; bool sneak = IsSneaking; if (Controller.IsFreeCam && !CanFly) { Controller.IsFreeCam = false; } else if (CanFly) { IsFlying = Controller.IsFreeCam; } Controller.Update(args.GameTime); //KnownPosition.HeadYaw = KnownPosition.Yaw; if (IsSprinting && !sprint) { FOVModifier += 10; Network.EntityAction((int)EntityId, EntityAction.StartSprinting); } else if (!IsSprinting && sprint) { FOVModifier -= 10; Network.EntityAction((int)EntityId, EntityAction.StopSprinting); } if (IsSneaking != sneak) { if (IsSneaking) { Network.EntityAction((int)EntityId, EntityAction.StartSneaking); } else { Network.EntityAction((int)EntityId, EntityAction.StopSneaking); } } if (Controller.CheckInput) { var hitEntity = HitEntity; if (hitEntity != null && Controller.InputManager.IsPressed(InputCommand.LeftClick)) { if (_destroyingBlock) { StopBreakingBlock(forceCanceled: true); } InteractWithEntity(hitEntity, true); } else if (hitEntity != null && Controller.InputManager.IsPressed(InputCommand.RightClick)) { if (_destroyingBlock) { StopBreakingBlock(forceCanceled: true); } InteractWithEntity(hitEntity, false); } else if (hitEntity == null && !_destroyingBlock && Controller.InputManager.IsDown(InputCommand.LeftClick)) //Destroying block. { StartBreakingBlock(); } else if (_destroyingBlock && Controller.InputManager.IsUp(InputCommand.LeftClick)) { StopBreakingBlock(); } else if (_destroyingBlock && Controller.InputManager.IsDown(InputCommand.LeftClick)) { if (_destroyingTarget != new BlockCoordinates(Raytraced.Floor())) { StopBreakingBlock(true, true); if (Gamemode != Gamemode.Creative) { StartBreakingBlock(); } } } else if (Controller.InputManager.IsPressed(InputCommand.RightClick)) { bool handledClick = false; // Log.Debug($"Right click!"); if (Inventory.MainHand != null && !(Inventory.MainHand is ItemAir)) { handledClick = HandleRightClick(Inventory.MainHand, 0); } if (!handledClick && Inventory.OffHand != null && !(Inventory.OffHand is ItemAir)) { handledClick = HandleRightClick(Inventory.OffHand, 1); } if (!handledClick) { var flooredAdj = AdjacentRaytrace.Floor(); var remainder = new Vector3(AdjacentRaytrace.X - flooredAdj.X, AdjacentRaytrace.Y - flooredAdj.Y, AdjacentRaytrace.Z - flooredAdj.Z); Network?.BlockPlaced(Raytraced, GetTargetFace(), 0, remainder); handledClick = true; } } } else if (_destroyingBlock) { StopBreakingBlock(); } UpdateRayTracer(); base.Update(args); }
private void _generateCurvedPlaneVertexData( HardwareVertexBuffer vbuf, int ySegments, int xSegments, float xSpace, float halfWidth, float ySpace, float halfHeight, Matrix4 transform, bool firstTime, bool normals, Matrix4 rotation, float curvature, int numTexCoordSets, float xTexCoord, float yTexCoord, SubMesh subMesh, ref Vector3 min, ref Vector3 max, ref float maxSquaredLength ) { Vector3 vec; unsafe { // lock the vertex buffer IntPtr data = vbuf.Lock( BufferLocking.Discard ); float* pData = (float*)data.ToPointer(); for ( int y = 0; y <= ySegments; y++ ) { for ( int x = 0; x <= xSegments; x++ ) { // centered on origin vec.x = ( x * xSpace ) - halfWidth; vec.y = ( y * ySpace ) - halfHeight; // Here's where curved plane is different from standard plane. Amazing, I know. Real diff_x = ( x - ( (Real)xSegments / 2 ) ) / (Real)xSegments; Real diff_y = ( y - ( (Real)ySegments / 2 ) ) / (Real)ySegments; Real dist = Utility.Sqrt( diff_x * diff_x + diff_y * diff_y ); vec.z = ( -Utility.Sin( ( 1 - dist ) * ( Utility.PI / 2 ) ) * curvature ) + curvature; // Transform by orientation and distance Vector3 pos = transform.TransformAffine( vec ); *pData++ = pos.x; *pData++ = pos.y; *pData++ = pos.z; // Build bounds as we go if ( firstTime ) { min = vec; max = vec; maxSquaredLength = vec.LengthSquared; firstTime = false; } else { min.Floor( vec ); max.Ceil( vec ); maxSquaredLength = Utility.Max( maxSquaredLength, vec.LengthSquared ); } if ( normals ) { // This part is kinda 'wrong' for curved planes... but curved planes are // very valuable outside sky planes, which don't typically need normals // so I'm not going to mess with it for now. // Default normal is along unit Z //vec = Vector3::UNIT_Z; // Rotate vec = rotation.TransformAffine( vec ); *pData++ = vec.x; *pData++ = vec.y; *pData++ = vec.z; } for ( int i = 0; i < numTexCoordSets; i++ ) { *pData++ = x * xTexCoord; *pData++ = 1 - ( y * yTexCoord ); } // for texCoords } // for x } // for y // unlock the buffer vbuf.Unlock(); subMesh.useSharedVertices = true; } // unsafe }
private void InitDebugInfo() { _debugInfo.AddDebugLeft(() => { //FpsCounter.Update(); //World.ChunkManager.GetPendingLightingUpdates(out int lowLight, out int midLight, out int highLight); double avg = 0; if (World.ChunkManager.TotalChunkUpdates > 0) { avg = (World.ChunkManager.ChunkUpdateTime / World.ChunkManager.TotalChunkUpdates).TotalMilliseconds; } return ($"Alex {Alex.Version} ({Alex.FpsMonitor.Value:##} FPS, Chunk Updates: {World.EnqueuedChunkUpdates} queued, {World.ConcurrentChunkUpdates} active, Avg: {avg:F2}ms, Max: {World.ChunkManager.MaxUpdateTime.TotalMilliseconds:F2}ms, Min: {World.ChunkManager.MinUpdateTIme.TotalMilliseconds:F2})" /*, H: {highLight} M: {midLight} L: {lowLight} lighting updates)"*/ ); }); _debugInfo.AddDebugLeft(() => { var pos = World.Player.KnownPosition; var blockPos = pos.GetCoordinates3D(); return($"RenderPosition: (X={pos.X:F2}, Y={pos.Y:F2}, Z={pos.Z:F2}) / Block: ({blockPos.X:D}, {blockPos.Y:D}, {blockPos.Z:D})"); }); _debugInfo.AddDebugLeft(() => { var pos = World.Player.KnownPosition; return($"Facing: {GetCardinalDirection(pos)} (HeadYaw={pos.HeadYaw:F2}, Yaw={pos.Yaw:F2}, Pitch={pos.Pitch:F2})"); }); _debugInfo.AddDebugLeft(() => { var pos = World.Player.Velocity; return($"Velocity: (X={pos.X:F2}, Y={pos.Y:F2}, Z={pos.Z:F2}) / Target Speed: {World.Player.Controller.LastSpeedFactor:F2} M/s"); }); _debugInfo.AddDebugLeft(() => $"Vertices: {World.Vertices:N0} ({GetBytesReadable((long)(World.Vertices * BlockShaderVertex.VertexDeclaration.VertexStride))})"); // _debugInfo.AddDebugLeft(() => $"IndexBuffer Elements: {World.IndexBufferSize:N0} ({GetBytesReadable(World.IndexBufferSize * 4)})"); _debugInfo.AddDebugLeft(() => $"Chunks: {World.ChunkCount}, {World.ChunkManager.RenderedChunks}"); _debugInfo.AddDebugLeft(() => $"Entities: {World.EntityManager.EntityCount}, {World.EntityManager.EntitiesRendered}"); _debugInfo.AddDebugLeft(() => { return($"Biome: {_currentBiome.Name} ({_currentBiomeId})"); }); _debugInfo.AddDebugLeft(() => { return($"Do DaylightCycle: {World.DoDaylightcycle}"); }); _debugInfo.AddDebugRight(() => Alex.OperatingSystem); _debugInfo.AddDebugRight(() => Alex.Gpu); _debugInfo.AddDebugRight(() => $"{Alex.DotnetRuntime}\n"); //_debugInfo.AddDebugRight(() => MemoryUsageDisplay); _debugInfo.AddDebugRight(() => $"RAM: {GetBytesReadable(_ramUsage, 2)}"); _debugInfo.AddDebugRight(() => $"GPU: {GetBytesReadable(GpuResourceManager.GetMemoryUsage, 2)}"); _debugInfo.AddDebugRight(() => { return ($"Threads: {(_threadsUsed):00}/{_maxThreads}"); }); _debugInfo.AddDebugRight(() => { if (_raytracedBlock.Y > 0 && _raytracedBlock.Y < 256) { var adj = Vector3.Floor(_adjacentBlock) - Vector3.Floor(_raytracedBlock); adj.Normalize(); var face = adj.GetBlockFace(); StringBuilder sb = new StringBuilder(); sb.AppendLine($"Target: {_raytracedBlock} Face: {face}"); sb.AppendLine( $"Skylight: {World.GetSkyLight(_raytracedBlock)} Face Skylight: {World.GetSkyLight(_adjacentBlock)}"); sb.AppendLine( $"Blocklight: {World.GetBlockLight(_raytracedBlock)} Face Blocklight: {World.GetBlockLight(_adjacentBlock)}"); //sb.AppendLine($"Skylight scheduled: {World.IsScheduled((int) _raytracedBlock.X, (int) _raytracedBlock.Y, (int) _raytracedBlock.Z)}"); foreach (var bs in World .GetBlockStates((int)_raytracedBlock.X, (int)_raytracedBlock.Y, (int)_raytracedBlock.Z)) { var blockstate = bs.State; if (blockstate != null && blockstate.Block.Renderable) { sb.AppendLine($"{blockstate.Name} (S: {bs.Storage})"); if (blockstate.IsMultiPart) { sb.AppendLine($"MultiPart=true"); sb.AppendLine(); sb.AppendLine("Models:"); foreach (var model in blockstate.AppliedModels) { sb.AppendLine(model); } } var dict = blockstate.ToDictionary(); if (dict.Count > 0) { sb.AppendLine(); sb.AppendLine("Blockstate:"); foreach (var kv in dict) { sb.AppendLine($"{kv.Key}={kv.Value}"); } } } } return(sb.ToString()); } else { return(string.Empty); } }); _debugInfo.AddDebugRight(() => { var player = World.Player; if (player == null || player.HitEntity == null) { return(string.Empty); } var entity = player.HitEntity; return($"Hit entity: {entity.EntityId} / {entity.ToString()}"); }); }
/// <summary> /// Update the bounds of the BillboardSet. /// </summary> public virtual void UpdateBounds() { if ( this.activeBillboards.Count == 0 ) { // no billboards, so the bounding box is null this.aab.IsNull = true; this.boundingRadius = 0.0f; } else { float maxSqLen = -1.0f; Vector3 min = new Vector3( float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity ); Vector3 max = new Vector3( float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity ); foreach ( Billboard billboard in this.activeBillboards ) { Vector3 pos = billboard.Position; min.Floor( pos ); max.Ceil( pos ); maxSqLen = Utility.Max( maxSqLen, pos.LengthSquared ); } // adjust for billboard size float adjust = Utility.Max( this.defaultParticleWidth, this.defaultParticleHeight ); Vector3 vecAdjust = new Vector3( adjust, adjust, adjust ); min -= vecAdjust; max += vecAdjust; // update our local aabb this.aab.SetExtents( min, max ); this.boundingRadius = Utility.Sqrt( maxSqLen ); } // if we have a parent node, ask it to update us if ( this.parentNode != null ) { this.parentNode.NeedUpdate(); } }
private static void GeneratePlaneVertexData(HardwareVertexBuffer vbuf, int ySegments, int xSegments, float xSpace, float halfWidth, float ySpace, float halfHeight, Matrix4 transform, bool firstTime, bool normals, Matrix4 rotation, int numTexCoordSets, float xTexCoord, float yTexCoord, SubMesh subMesh, ref Vector3 min, ref Vector3 max, ref float maxSquaredLength) { Vector3 vec; unsafe { // lock the vertex buffer IntPtr data = vbuf.Lock(BufferLocking.Discard); float *pData = (float *)data.ToPointer(); for (int y = 0; y <= ySegments; y++) { for (int x = 0; x <= xSegments; x++) { // centered on origin vec.x = (x * xSpace) - halfWidth; vec.y = (y * ySpace) - halfHeight; vec.z = 0.0f; vec = transform * vec; *pData++ = vec.x; *pData++ = vec.y; *pData++ = vec.z; // Build bounds as we go if (firstTime) { min = vec; max = vec; maxSquaredLength = vec.LengthSquared; firstTime = false; } else { min.Floor(vec); max.Ceil(vec); maxSquaredLength = MathUtil.Max(maxSquaredLength, vec.LengthSquared); } if (normals) { vec = Vector3.UnitZ; vec = rotation * vec; *pData++ = vec.x; *pData++ = vec.y; *pData++ = vec.z; } for (int i = 0; i < numTexCoordSets; i++) { *pData++ = x * xTexCoord; *pData++ = 1 - (y * yTexCoord); } // for texCoords } // for x } // for y // unlock the buffer vbuf.Unlock(); subMesh.useSharedVertices = true; } // unsafe }