public static float[] CreateCubeNormals() { List <float> normals = new List <float>(); void AppendVertexes(TextureType side) { var normal = FaceSides.Parse(side); for (int i = 0; i < 4; i++) { normals.Add(normal.x); normals.Add(normal.y); normals.Add(normal.z); } } AppendVertexes(TextureType.up); AppendVertexes(TextureType.down); AppendVertexes(TextureType.north); AppendVertexes(TextureType.south); AppendVertexes(TextureType.east); AppendVertexes(TextureType.west); return(normals.ToArray()); }
public static void AppendFace(TextureType side, float[] from, float[] to, Vector3 rotation, Vector3 rotationOrigin, ref float[] vertexes, ref float[] normals, int startIndex) { FaceSides faceSide = FaceSides.Parse(side); //TextureType parsed to FaceSides, also a normal of this face Vector3 normal = faceSide.ToVec(); float[] unitFace = _cube[faceSide]; //one side of the cube in unit size float x = from[0] / 16f; float y = from[1] / 16f; float z = from[2] / 16f; float sx = to[0] / 16f - x; //the size of the cube part float sy = to[1] / 16f - y; float sz = to[2] / 16f - z; for (var i = 0; i < unitFace.Length; i += 3) { var vertex = RotateVertex(new Vector3( x + unitFace[i] * sx, y + unitFace[i + 1] * sy, z + unitFace[i + 2] * sz), rotation, rotationOrigin); vertexes[startIndex + i] = vertex.X; vertexes[startIndex + i + 1] = vertex.Y; vertexes[startIndex + i + 2] = vertex.Z; var nrm = RotateVertex(normal, rotation, rotationOrigin); normals[startIndex + i] = nrm.X; normals[startIndex + i + 1] = nrm.Y; normals[startIndex + i + 2] = nrm.Z; } }
//unused for now public void AppendVertexesForSide(FaceSides side, List <float> vertexes, BlockPos offset) { /* * top = 0 * bottom = 1 * north = 2 * south = 3 * west = 4 * east = 5 * --> these are used as indexes of the faces, since the model vertex data is added in the same exact order of the TextureType enum values */ if (!FaceSides.Parse(side, out var parsed)) //FaceSides is a struct containing Vector2 values (normals) { return; } int faceIndex = (int)parsed * 12; for (int i = 0; i < 12; i += 3) { vertexes.Add(_vertexes[faceIndex + i] + offset.X); vertexes.Add(_vertexes[faceIndex + i + 1] + offset.Y); vertexes.Add(_vertexes[faceIndex + i + 2] + offset.Z); } }
//TODO - only use these when the block model is one 1x1x1 big cube public void AppendVertexDataForSide(FaceSides side, List <float> vertexes, List <float> normals, List <float> uvs, BlockPos offset) { if (!FaceSides.Parse(side, out var parsed)) //FaceSides is a struct containing Vector2 values (normals) { return; } int faceIndex = (int)parsed * 12; for (int i = 0; i < 12; i += 3) { vertexes.Add(_vertexes[faceIndex + i] + offset.X); vertexes.Add(_vertexes[faceIndex + i + 1] + offset.Y); vertexes.Add(_vertexes[faceIndex + i + 2] + offset.Z); normals.Add(_normals[faceIndex + i]); normals.Add(_normals[faceIndex + i + 1]); normals.Add(_normals[faceIndex + i + 2]); } faceIndex = (int)parsed * 8; for (int i = 0; i < 8; i += 2) { uvs.Add(_uvs[faceIndex + i]); uvs.Add(_uvs[faceIndex + i + 1]); } }
public static void AppendFace(Facing side, float[] from, float[] to, Vector3 rotation, Vector3 rotationOrigin, ref List <float> vertexes, ref List <float> normals) { FaceSides faceSide = FaceSides.Parse(side); //TextureType parsed to FaceSides, also a normal of this face Vector3 normal = faceSide.ToVec(); float[] unitFace = _cubeTriangles[faceSide]; //one side of the cube in unit size float x = from[0] / 16f; float y = from[1] / 16f; float z = from[2] / 16f; float sx = to[0] / 16f - x; //the size of the cube part float sy = to[1] / 16f - y; float sz = to[2] / 16f - z; for (var i = 0; i < unitFace.Length; i += 3) { var vertex = RotateVertex(new Vector3( x + unitFace[i] * sx, y + unitFace[i + 1] * sy, z + unitFace[i + 2] * sz), rotation, rotationOrigin); vertexes.Add(vertex.X); vertexes.Add(vertex.Y); vertexes.Add(vertex.Z); var nrm = RotateVertex(normal, rotation, rotationOrigin); normals.Add(nrm.X); normals.Add(nrm.Y); normals.Add(nrm.Z); } }
public void AppendUvsForSide(FaceSides side, List <float> uvs) { if (!FaceSides.Parse(side, out var parsed)) { return; } int faceIndex = (int)parsed * 8; for (int i = 0; i < 8; i += 2) { uvs.Add(_uvs[faceIndex + i]); uvs.Add(_uvs[faceIndex + i + 1]); } }
//unused for now public void AppendNormalsForSide(FaceSides side, List <float> normals) { if (!FaceSides.Parse(side, out var parsed)) { return; } int faceIndex = (int)parsed * 12; for (int i = 0; i < 12; i += 3) { normals.Add(_normals[faceIndex + i]); normals.Add(_normals[faceIndex + i + 1]); normals.Add(_normals[faceIndex + i + 2]); } }
public static float[] CreateCubeVertexes(bool centered = false) { List <float> vertexes = new List <float>(); void AppendVertexes(TextureType side) { var face = _cube[FaceSides.Parse(side)]; for (var index = 0; index < face.Length; index += 3) { var x = face[index]; var y = face[index + 1]; var z = face[index + 2]; if (centered) { x -= 0.5f; y -= 0.5f; z -= 0.5f; } vertexes.Add(x); vertexes.Add(y); vertexes.Add(z); } } AppendVertexes(TextureType.up); AppendVertexes(TextureType.down); AppendVertexes(TextureType.north); AppendVertexes(TextureType.south); AppendVertexes(TextureType.east); AppendVertexes(TextureType.west); return(vertexes.ToArray()); }
public override void Update() { _ticksLast = _ticks; if (OnGround) { _ticks = (_ticks + 1) % 90; if (_ticksLast > _ticks) { _ticksLast = _ticks - 1; } } LastPos = Pos; Motion.Y -= 0.04f * Gravity; Move(); Motion.Xz *= 0.8664021f; List <AxisAlignedBb> bbs = SharpCraft.Instance.World.GetBlockCollisionBoxes(BoundingBox); if (bbs.Count > 0) { BlockPos bp = new BlockPos(Pos); FaceSides lastFace = FaceSides.Up; bool blocksAround = FaceSides.YPlane.All(face => World.IsAir(bp.Offset(lastFace = face))) && World.IsAir(bp.Offset(lastFace = FaceSides.Up)) && World.IsAir(bp.Offset(lastFace = FaceSides.Down)); //has to be in this order if (!blocksAround) { Motion += lastFace.ToVec() * 0.1f; } } if (OnGround) { Motion.Xz *= 0.6676801f; } if (++_entityAge >= 20 * 50 * 60 + 10) //stay on ground for a minute, 20 ticks as a pick up delay { SetDead(); return; } if (_entityAge < 5) { return; } List <EntityItem> inAttractionArea = World.Entities.OfType <EntityItem>().Where(e => e != this && e.IsAlive && e._stack.ItemSame(_stack)).OrderByDescending(e => e._stack.Count).ToList(); float attractionRange = 1.8F; float mergeRange = 0.15F; foreach (EntityItem entity in inAttractionArea) { if (_stack.IsEmpty || entity._stack.IsEmpty || entity._stack.Count == entity._stack.Item.GetMaxStackSize()) { continue; } Vector3 distanceVector = entity.Pos - Pos; float distance = distanceVector.Length; if (distance >= attractionRange) { continue; } int ammountToTake = Math.Min(_stack.Item.GetMaxStackSize() - _stack.Count, entity._stack.Count); if (ammountToTake == 0) { continue; } if (distance <= mergeRange) { //Motion -= entity.Motion * MathUtil.Remap(entity.stack.Count / (float)stack.Count, 1, 64, 1, 3); //entity.Motion -= Motion * MathUtil.Remap(stack.Count / (float)entity.stack.Count, 1, 64, 1, 3); entity._stack.Count -= ammountToTake; if (entity._stack.IsEmpty) { entity.SetDead(); } _stack.Count += ammountToTake; _entityAge = 3; entity._entityAge = 1; continue; } distanceVector.Normalize(); float distanceMul = (float)Math.Sqrt(1 - distance / attractionRange); if (distanceMul > 0.8) { distanceMul = ((1 - distanceMul) / 0.2F) * 0.6F + 0.2F; } Vector3 baseForce = distanceVector * 0.02f * distanceMul * MathUtil.Remap(_stack.Count / (float)entity._stack.Count, 1, entity._stack.Item.GetMaxStackSize(), 2, 5); Motion += baseForce * entity._stack.Count / Math.Max(entity._stack.Count, _stack.Count); entity.Motion -= baseForce * _stack.Count / Math.Max(entity._stack.Count, _stack.Count); } if (_entityAge < 15 || !IsAlive) { return; } //TODO change this for multiplayer IEnumerable <EntityPlayerSp> players = World.Entities.OfType <EntityPlayerSp>() .OrderBy(entity => Vector3.Distance(entity.Pos, Pos)) .Where(e => Vector3.Distance(e.Pos, Pos) <= attractionRange); foreach (EntityPlayerSp player in players) { if (!player.CanPickUpStack(_stack)) { continue; } Vector3 attrTarget = player.Pos; attrTarget.Y += player.GetCollisionBoundingBox().Size.Y / 2; Vector3 distanceVector = attrTarget - Pos; if (distanceVector.Length <= 0.35f) { if (player.OnPickup(_stack)) { SetDead(); } Motion *= -1f; } Motion = distanceVector.Normalized() * 0.45f; } if (_stack.IsEmpty) { SetDead(); } }
public ParticleDigging(World world, Vector3 pos, Vector3 motion, float particleScale, BlockState state, FaceSides side) : base(world, pos, motion, particleScale, JsonModelLoader.TEXTURE_BLOCKS) { State = state; ModelBlock model = JsonModelLoader.GetModelForBlock(state.Block.UnlocalizedName); if (model.RawModel is ModelBlockRaw mbr) { Vector2 start; Vector2 end; if (state.Block.IsFullCube) { List <float> uvs = new List <float>(8); mbr.AppendUvsForSide(side, uvs); start = new Vector2(uvs[0], uvs[1]); end = new Vector2(uvs[4], uvs[5]); //4,5 because that's the 3. vertex and the local UV there is 1,1 } else { var tex = model.GetParticleTexture(); start = tex.UVMin; end = tex.UVMax; } Vector2 size = end - start; Vector2 pixel = size / 16; UVmin = start + pixel * new Vector2(MathUtil.NextFloat(0, 12), MathUtil.NextFloat(0, 12)); UVmax = UVmin + pixel * 4; } if (side == FaceSides.Up) { Motion.Xz = SharpCraft.Instance.Camera.GetLookVec().Xz * 0.15f; } Vector3 vec = new Vector3(MathUtil.NextFloat(-1), MathUtil.NextFloat(-1), MathUtil.NextFloat(-1)); _rotStep = vec.Normalized() * MathUtil.NextFloat(40, 75); }
public void GetMouseOverObject() { if (World == null) { return; } float radius = 5.5f; MouseOverObject final = new MouseOverObject(); float dist = float.MaxValue; Vector3 camPos = Vector3.One * 0.5f + Camera.Pos; var air = BlockRegistry.GetBlock <BlockAir>(); for (float z = -radius; z <= radius; z++) { for (float y = -radius; y <= radius; y++) { for (float x = -radius; x <= radius; x++) { Vector3 vec = camPos; vec.X += x; vec.Y += y; vec.Z += z; float f = (vec - Camera.Pos).LengthFast; if (f <= radius + 0.5f) { BlockPos pos = new BlockPos(vec); BlockState state = World.GetBlockState(pos); if (state.Block != air) { AxisAlignedBb bb = state.Block.BoundingBox.Offset(pos.ToVec()); bool hitSomething = RayHelper.RayIntersectsBB(Camera.Pos, Camera.GetLookVec(), bb, out Vector3 hitPos, out Vector3 normal); if (hitSomething) { FaceSides sideHit = FaceSides.Null; if (normal.X < 0) { sideHit = FaceSides.West; } else if (normal.X > 0) { sideHit = FaceSides.East; } if (normal.Y < 0) { sideHit = FaceSides.Down; } else if (normal.Y > 0) { sideHit = FaceSides.Up; } if (normal.Z < 0) { sideHit = FaceSides.North; } else if (normal.Z > 0) { sideHit = FaceSides.South; } BlockPos p = new BlockPos(hitPos - normal * bb.Size / 2); if (sideHit == FaceSides.Null) { continue; } float l = Math.Abs((Camera.Pos - (p.ToVec() + bb.Size / 2)).Length); if (l < dist) { dist = l; final.hit = HitType.Block; final.hitVec = hitPos; final.blockPos = p; final.normal = normal; final.sideHit = sideHit; final.boundingBox = bb; } } } } } } } MouseOverObject = final; }
public void BuildChunkModelNow() { if (ModelBuilding || !QueuedForModelBuild) { return; } ModelBuilding = true; //ConcurrentDictionary<Shader<ModelBlock>, List<RawQuad>> modelRaw = new ConcurrentDictionary<Shader<ModelBlock>, List<RawQuad>>(); //List<RawQuad> quads; Stopwatch sw = Stopwatch.StartNew(); //this is just a debug thing.... var air = BlockRegistry.GetBlock <BlockAir>(); var vertexes = new List <float>(); var normals = new List <float>(); var uvs = new List <float>(); object locker = new object(); //generate the model - fill MODEL_RAW Enumerable.Range(0, ChunkHeight).AsParallel().ForAll(y => { for (int x = 0; x < ChunkSize; x++) { for (int z = 0; z < ChunkSize; z++) { BlockPos worldPos = new BlockPos(x + Pos.WorldSpaceX(), y, z + Pos.WorldSpaceZ()); BlockState state = World.GetBlockState(worldPos); if (state.Block == air) { continue; } BlockPos localPos = new BlockPos(x, y, z); ModelBlockRaw mbr = (ModelBlockRaw)state.Model?.RawModel; if (mbr == null) { continue; } if (!state.Block.IsFullCube) { lock (locker) mbr.AppendAllVertexData(vertexes, normals, uvs, localPos); continue; } for (var index = 0; index < FaceSides.AllSides.Count; index++) { FaceSides dir = FaceSides.AllSides[index]; BlockPos worldPosO = worldPos.Offset(dir); BlockState stateO = World.GetBlockState(worldPosO); if (!(stateO.Block == air || stateO.Block.HasTransparency && !state.Block.HasTransparency) && stateO.Block.IsFullCube) { continue; } lock (locker) { mbr.AppendVertexDataForSide(dir, vertexes, normals, uvs, localPos); //mbr.AppendNormalsForSide(dir, normals); //mbr.AppendUvsForSide(dir, uvs); } } } } }); sw.Stop(); Console.WriteLine($"DEBUG: built chunk model [{sw.Elapsed.TotalMilliseconds:F}ms]"); float[] vtx = vertexes.ToArray(); //this is here because this takes time and I don't want it to slow down the main thread by running it in GlContext float[] nrm = normals.ToArray(); float[] uv = uvs.ToArray(); SharpCraft.Instance.RunGlContext(() => { if (_model == null) { _model = new ModelChunk(vtx, nrm, uv, Block.DefaultShader); } else { _model.OverrideData(vtx, nrm, uv); } ModelBuilding = false; }); QueuedForModelBuild = false; }
public ParticleDigging(World world, Vector3 pos, Vector3 motion, float particleScale, BlockState state, FaceSides side) : base(world, pos, motion, particleScale, JsonModelLoader.TextureBlocks) { State = state; if (state.Model.RawModel is ModelBlockRaw) { var tex = state.Model.ParticleTexture; Vector2 start = tex.UVMin; Vector2 end = tex.UVMax; Vector2 size = end - start; Vector2 pixel = size / 16; UVmin = start + pixel * new Vector2(MathUtil.NextFloat(0, 12), MathUtil.NextFloat(0, 12)); UVmax = UVmin + pixel * 4; } if (side == FaceSides.Up) { Motion.Xz = SharpCraft.Instance.Camera.GetLookVec().Xz * 0.15f; } Vector3 vec = new Vector3(MathUtil.NextFloat(-1), MathUtil.NextFloat(-1), MathUtil.NextFloat(-1)); _rotStep = vec.Normalized() * MathUtil.NextFloat(40, 75); }