public Modelled3DFloorTile(OBJ model, string textureName) { TextureName = textureName; var indices = model.FacesByObjgroup.First(x => x.Value.Count > 0).Value; var outVerts = new List <TerrainParallaxVertex>(); var outInds = new List <int>(); var dict = new Dictionary <Tuple <int, int, int>, int>(); var off = new Vector3(0.5f, 0, 0.5f); foreach (var ind in indices) { var tup = new Tuple <int, int, int>(ind[0], ind[1], ind[2]); int targ; if (!dict.TryGetValue(tup, out targ)) { //add a vertex targ = outVerts.Count; var tc = model.TextureCoords[ind[1] - 1]; tc.Y = 1 - tc.Y; var vert = new TerrainParallaxVertex(model.Vertices[ind[0] - 1] + off, Vector4.One, tc, 0, model.Normals[ind[2] - 1]); outVerts.Add(vert); dict[tup] = targ; } outInds.Add(targ); } //todo: process using projector? (to cut at diagonals) Vertices = outVerts.ToArray(); Indices = outInds.ToArray(); }
public TerrainParallaxVertex[] GetVertices(GraphicsDevice gd) { if (VertexBuffer == null) { RegenTerrain(gd, Bp); } var dat = new TerrainParallaxVertex[VertexBuffer.VertexCount]; VertexBuffer.GetData <TerrainParallaxVertex>(dat); return(dat); }
public void RegenTerrain(GraphicsDevice device, Blueprint blueprint) { if (GrassState == null) { TerrainDirty = true; //yikes! try again to see if we have it next frame return; } TerrainDirty = false; if (VertexBuffer != null) { IndexBuffer.Dispose(); BladeIndexBuffer.Dispose(); VertexBuffer.Dispose(); GridIndexBuffer?.Dispose(); TGridIndexBuffer?.Dispose(); } /** Convert rectangle to world units **/ var quads = Size.Width; var quadWidth = WorldSpace.GetWorldFromTile((float)Size.Width / (float)quads); var quadHeight = WorldSpace.GetWorldFromTile((float)Size.Height / (float)quads); var numQuads = quads * quads; var archSize = quads; TerrainParallaxVertex[] Geom = new TerrainParallaxVertex[numQuads * 4]; int[] Indexes = new int[numQuads * 6]; int[] BladeIndexes = new int[numQuads * 6]; NumPrimitives = (numQuads * 2); int geomOffset = 0; int indexOffset = 0; int bindexOffset = 0; var offsetX = WorldSpace.GetWorldFromTile(Size.X); var offsetY = WorldSpace.GetWorldFromTile(Size.Y); for (var y = 0; y < quads; y++) { for (var x = 0; x < quads; x++) { var tl = new Vector3(offsetX + (x * quadWidth), 0.0f, offsetY + (y * quadHeight)); var tr = new Vector3(tl.X + quadWidth, 0.0f, tl.Z); var bl = new Vector3(tl.X, 0.0f, tl.Z + quadHeight); var br = new Vector3(tl.X + quadWidth, 0.0f, tl.Z + quadHeight); tl.Y = GetElevationPoint(x, y); tr.Y = GetElevationPoint(x + 1, y); bl.Y = GetElevationPoint(x, y + 1); br.Y = GetElevationPoint(x + 1, y + 1); Indexes[indexOffset++] = geomOffset; Indexes[indexOffset++] = (geomOffset + 1); Indexes[indexOffset++] = (geomOffset + 2); Indexes[indexOffset++] = (geomOffset + 2); Indexes[indexOffset++] = (geomOffset + 3); Indexes[indexOffset++] = geomOffset; short tx = (short)x, ty = (short)y; if (blueprint.GetFloor(tx, ty, 1).Pattern == 0 && (blueprint.GetWall(tx, ty, 1).Segments & (WallSegments.HorizontalDiag | WallSegments.VerticalDiag)) == 0) { BladeIndexes[bindexOffset++] = geomOffset; BladeIndexes[bindexOffset++] = (geomOffset + 1); BladeIndexes[bindexOffset++] = (geomOffset + 2); BladeIndexes[bindexOffset++] = (geomOffset + 2); BladeIndexes[bindexOffset++] = (geomOffset + 3); BladeIndexes[bindexOffset++] = geomOffset; } Color tlCol = Color.Lerp(LightGreen, LightBrown, GetGrassState(x, y)); Color trCol = Color.Lerp(LightGreen, LightBrown, GetGrassState(x + 1, y)); Color blCol = Color.Lerp(LightGreen, LightBrown, GetGrassState(x, y + 1)); Color brCol = Color.Lerp(LightGreen, LightBrown, GetGrassState(x + 1, y + 1)); Geom[geomOffset++] = new TerrainParallaxVertex(tl, tlCol.ToVector4(), new Vector2(((x - y) + 1) * 0.5f, (x + y) * 0.5f), GetGrassState(x, y), GetNormalAt(x, y)); Geom[geomOffset++] = new TerrainParallaxVertex(tr, trCol.ToVector4(), new Vector2(((x - y) + 2) * 0.5f, (x + 1 + y) * 0.5f), GetGrassState(x + 1, y), GetNormalAt(x + 1, y)); Geom[geomOffset++] = new TerrainParallaxVertex(br, brCol.ToVector4(), new Vector2(((x - y) + 1) * 0.5f, (x + y + 2) * 0.5f), GetGrassState(x + 1, y + 1), GetNormalAt(x + 1, y + 1)); Geom[geomOffset++] = new TerrainParallaxVertex(bl, blCol.ToVector4(), new Vector2((x - y) * 0.5f, (x + y + 1) * 0.5f), GetGrassState(x, y + 1), GetNormalAt(x, y + 1)); } } var GridIndices = (Bp.FineArea != null) ? GetGridIndicesForFine(Bp.FineArea, quads) : GetGridIndicesForArea(Bp.BuildableArea, quads); var TGridIndices = GetGridIndicesForArea(Bp.TargetBuildableArea, quads); VertexBuffer = new VertexBuffer(device, typeof(TerrainParallaxVertex), Geom.Length, BufferUsage.None); VertexBuffer.SetData(Geom); IndexBuffer = new IndexBuffer(device, IndexElementSize.ThirtyTwoBits, sizeof(int) * Indexes.Length, BufferUsage.None); IndexBuffer.SetData(Indexes); BladePrimitives = (bindexOffset / 3); BladeIndexBuffer = new IndexBuffer(device, IndexElementSize.ThirtyTwoBits, sizeof(int) * Indexes.Length, BufferUsage.None); BladeIndexBuffer.SetData(BladeIndexes); GeomLength = Geom.Length; var primLength = (GridAsTexture) ? 3 : 2; if (GridIndices.Length > 0) { GridIndexBuffer = new IndexBuffer(device, IndexElementSize.ThirtyTwoBits, sizeof(int) * GridIndices.Length, BufferUsage.None); GridIndexBuffer.SetData(GridIndices); GridPrimitives = GridIndices.Length / primLength; } if (TGridIndices.Length > 0) { TGridIndexBuffer = new IndexBuffer(device, IndexElementSize.ThirtyTwoBits, sizeof(int) * TGridIndices.Length, BufferUsage.None); TGridIndexBuffer.SetData(TGridIndices); TGridPrimitives = TGridIndices.Length / primLength; } if (GridTex == null) { using (var strm = File.Open($"Content/Textures/lot/tile_dashed.png", FileMode.Open, FileAccess.Read, FileShare.Read)) { GridTex = GenMips(device, Texture2D.FromStream(device, strm)); } } }
public RoofData MeshRectData(int level) { var rects = RoofRects[level - 2]; if (rects == null) { return(null); } var advRoof = true; var numQuads = rects.Count * 4; //4 sides for each roof rectangle TerrainParallaxVertex[] Vertices = new TerrainParallaxVertex[numQuads * 4]; int[] Indices = new int[numQuads * 6]; TerrainParallaxVertex[] AdvVertices = null; int[] AdvIndices = null; int advNumPrimitives = 0; if (advRoof) { //advanced roof: add down facing edges at each side, //and edge guards var advQuads = numQuads * (1 + 3); //1 quad for the rim, then 3 for the edge advQuads += rects.Count; //bottom AdvVertices = new TerrainParallaxVertex[advQuads * 4]; AdvIndices = new int[advQuads * 6]; advNumPrimitives = advQuads * 2; } var numPrimitives = (numQuads * 2); int geomOffset = 0; int indexOffset = 0; int advGeomOffset = 0; int advIndexOffset = 0; var mat3 = Matrix.CreateRotationZ((float)(Math.PI / -2f)); //good var mat1 = Matrix.CreateRotationZ((float)(Math.PI / -2f)); var mat4 = Matrix.CreateRotationX((float)(Math.PI / 2f)) * Matrix.CreateRotationZ((float)(Math.PI / -2f)); //good var mat2 = Matrix.CreateRotationX((float)(Math.PI / 2f)) * Matrix.CreateRotationZ((float)(Math.PI / 2f)); var edgeT = 0.7f; var edgeO = new Vector3(0, 0.005f, 0); var advCol = RoofAvgColor.ToVector4(); foreach (var rect in rects) { //determine roof height of the smallest edge. This height will be used on all edges var height = Math.Min(rect.x2 - rect.x1, rect.y2 - rect.y1) / 2; // / \ // / \ // /________\ Draw 4 segments like this. two segments will have the top middle section so short it will not appear. var heightMod = 0;// height / 400f; var pitch = RoofPitch; var tl = ToWorldPos(rect.x1, rect.y1, 0, level, pitch) + new Vector3(0, heightMod, 0); var tr = ToWorldPos(rect.x2, rect.y1, 0, level, pitch) + new Vector3(0, heightMod, 0); var bl = ToWorldPos(rect.x1, rect.y2, 0, level, pitch) + new Vector3(0, heightMod, 0); var br = ToWorldPos(rect.x2, rect.y2, 0, level, pitch) + new Vector3(0, heightMod, 0); var m_tl = ToWorldPos(rect.x1 + height, rect.y1 + height, height, level, pitch) + new Vector3(0, heightMod, 0); var m_tr = ToWorldPos(rect.x2 - height, rect.y1 + height, height, level, pitch) + new Vector3(0, heightMod, 0); var m_bl = ToWorldPos(rect.x1 + height, rect.y2 - height, height, level, pitch) + new Vector3(0, heightMod, 0); var m_br = ToWorldPos(rect.x2 - height, rect.y2 - height, height, level, pitch) + new Vector3(0, heightMod, 0); var thickness = new Vector3(0, -0.5f, 0); var b_tl = tl + thickness; var b_tr = tr + thickness; var b_bl = bl + thickness; var b_br = br + thickness; Color topCol = Color.White; //Color.Lerp(Color.White, new Color(175, 175, 175), pitch); Color rightCol = Color.White; //Color.White; Color btmCol = Color.White; //Color.Lerp(Color.White, new Color(200, 200, 200), pitch); Color leftCol = Color.White; //Color.Lerp(Color.White, new Color(150, 150, 150), pitch); Vector4 darken = new Vector4(0.8f, 0.8f, 0.8f, 1.0f); //quad as two tris for (int j = 0; j < 16; j += 4) { Indices[indexOffset++] = (geomOffset + 2) + j; Indices[indexOffset++] = (geomOffset + 1) + j; Indices[indexOffset++] = geomOffset + j; Indices[indexOffset++] = geomOffset + j; Indices[indexOffset++] = (geomOffset + 3) + j; Indices[indexOffset++] = (geomOffset + 2) + j; } var n1 = -Vector3.Normalize(Vector3.Cross(tl - tr, tr - m_tr)); Vector2 texScale = new Vector2(2 / 3f, 1f) * TexRescale; Vertices[geomOffset++] = new TerrainParallaxVertex(tl, topCol.ToVector4(), new Vector2(tl.X, tl.Z * -1) * texScale, 0, n1, mat1, true); Vertices[geomOffset++] = new TerrainParallaxVertex(tr, topCol.ToVector4(), new Vector2(tr.X, tr.Z * -1) * texScale, 0, n1, mat1, true); Vertices[geomOffset++] = new TerrainParallaxVertex(m_tr, topCol.ToVector4() * 1.25f, new Vector2(m_tr.X, m_tr.Z * -1) * texScale, 0, n1, mat1, true); Vertices[geomOffset++] = new TerrainParallaxVertex(m_tl, topCol.ToVector4() * 1.25f, new Vector2(m_tl.X, m_tl.Z * -1) * texScale, 0, n1, mat1, true); var n2 = -Vector3.Normalize(Vector3.Cross(tr - br, br - m_br)); Vertices[geomOffset++] = new TerrainParallaxVertex(tr, rightCol.ToVector4(), new Vector2(tr.Z, tr.X) * texScale, 0, n2, mat2, true); Vertices[geomOffset++] = new TerrainParallaxVertex(br, rightCol.ToVector4(), new Vector2(br.Z, br.X) * texScale, 0, n2, mat2, true); Vertices[geomOffset++] = new TerrainParallaxVertex(m_br, rightCol.ToVector4() * 1.25f, new Vector2(m_br.Z, m_br.X) * texScale, 0, n2, mat2, true); Vertices[geomOffset++] = new TerrainParallaxVertex(m_tr, rightCol.ToVector4() * 1.25f, new Vector2(m_tr.Z, m_tr.X) * texScale, 0, n2, mat2, true); var n3 = -Vector3.Normalize(Vector3.Cross(br - bl, bl - m_bl)); Vertices[geomOffset++] = new TerrainParallaxVertex(br, btmCol.ToVector4(), new Vector2(br.X, br.Z) * texScale, 0, n3, mat3, false); Vertices[geomOffset++] = new TerrainParallaxVertex(bl, btmCol.ToVector4(), new Vector2(bl.X, bl.Z) * texScale, 0, n3, mat3, false); Vertices[geomOffset++] = new TerrainParallaxVertex(m_bl, btmCol.ToVector4() * 1.25f, new Vector2(m_bl.X, m_bl.Z) * texScale, 0, n3, mat3, false); Vertices[geomOffset++] = new TerrainParallaxVertex(m_br, btmCol.ToVector4() * 1.25f, new Vector2(m_br.X, m_br.Z) * texScale, 0, n3, mat3, false); var n4 = -Vector3.Normalize(Vector3.Cross(bl - tl, tl - m_tl)); Vertices[geomOffset++] = new TerrainParallaxVertex(bl, leftCol.ToVector4(), new Vector2(bl.Z, bl.X * -1) * texScale, 0, n4, mat4, false); Vertices[geomOffset++] = new TerrainParallaxVertex(tl, leftCol.ToVector4(), new Vector2(tl.Z, tl.X * -1) * texScale, 0, n4, mat4, false); Vertices[geomOffset++] = new TerrainParallaxVertex(m_tl, leftCol.ToVector4() * 1.25f, new Vector2(m_tl.Z, m_tl.X * -1) * texScale, 0, n4, mat4, false); Vertices[geomOffset++] = new TerrainParallaxVertex(m_bl, leftCol.ToVector4() * 1.25f, new Vector2(m_bl.Z, m_bl.X * -1) * texScale, 0, n4, mat4, false); if (advRoof) { for (int j = 0; j < 20; j += 4) { AdvIndices[advIndexOffset++] = (advGeomOffset + 2) + j; AdvIndices[advIndexOffset++] = (advGeomOffset + 1) + j; AdvIndices[advIndexOffset++] = advGeomOffset + j; AdvIndices[advIndexOffset++] = advGeomOffset + j; AdvIndices[advIndexOffset++] = (advGeomOffset + 3) + j; AdvIndices[advIndexOffset++] = (advGeomOffset + 2) + j; } //thickness var n5 = Vector3.Normalize(Vector3.Cross(tl - tr, tr - b_tr)); AdvVertices[advGeomOffset++] = new TerrainParallaxVertex(b_tr, advCol, PosToTexCRim(b_tr, 0.73f), 0, n5, mat1, true); AdvVertices[advGeomOffset++] = new TerrainParallaxVertex(tr, advCol, PosToTexCRim(tr, 0.4f), 0, n5, mat1, true); AdvVertices[advGeomOffset++] = new TerrainParallaxVertex(tl, advCol, PosToTexCRim(tl, 0.4f), 0, n5, mat1, true); AdvVertices[advGeomOffset++] = new TerrainParallaxVertex(b_tl, advCol, PosToTexCRim(b_tl, 0.73f), 0, n5, mat1, true); n5 = Vector3.Normalize(Vector3.Cross(tr - br, br - b_br)); AdvVertices[advGeomOffset++] = new TerrainParallaxVertex(b_br, advCol, PosToTexCRim(b_br, 0.73f), 0, n5, mat2, true); AdvVertices[advGeomOffset++] = new TerrainParallaxVertex(br, advCol, PosToTexCRim(br, 0.4f), 0, n5, mat2, true); AdvVertices[advGeomOffset++] = new TerrainParallaxVertex(tr, advCol, PosToTexCRim(tr, 0.4f), 0, n5, mat2, true); AdvVertices[advGeomOffset++] = new TerrainParallaxVertex(b_tr, advCol, PosToTexCRim(b_tr, 0.73f), 0, n5, mat2, true); n5 = Vector3.Normalize(Vector3.Cross(br - bl, bl - b_bl)); AdvVertices[advGeomOffset++] = new TerrainParallaxVertex(b_bl, advCol, PosToTexCRim(b_bl, 0.73f), 0, n5, mat3, false); AdvVertices[advGeomOffset++] = new TerrainParallaxVertex(bl, advCol, PosToTexCRim(bl, 0.4f), 0, n5, mat3, false); AdvVertices[advGeomOffset++] = new TerrainParallaxVertex(br, advCol, PosToTexCRim(br, 0.4f), 0, n5, mat3, false); AdvVertices[advGeomOffset++] = new TerrainParallaxVertex(b_br, advCol, PosToTexCRim(b_br, 0.73f), 0, n5, mat3, false); n5 = Vector3.Normalize(Vector3.Cross(bl - tl, tl - b_tl)); AdvVertices[advGeomOffset++] = new TerrainParallaxVertex(b_tl, advCol, PosToTexCRim(b_tl, 0.73f), 0, n5, mat4, false); AdvVertices[advGeomOffset++] = new TerrainParallaxVertex(tl, advCol, PosToTexCRim(tl, 0.4f), 0, n5, mat4, false); AdvVertices[advGeomOffset++] = new TerrainParallaxVertex(bl, advCol, PosToTexCRim(bl, 0.4f), 0, n5, mat4, false); AdvVertices[advGeomOffset++] = new TerrainParallaxVertex(b_bl, advCol, PosToTexCRim(b_bl, 0.73f), 0, n5, mat4, false); //bottom (solid black) n5 = Vector3.Normalize(Vector3.Cross(b_tl - b_br, b_br - b_bl)); AdvVertices[advGeomOffset++] = new TerrainParallaxVertex(b_bl, advCol, new Vector2(0, 0.4f + 0.33f), 0, n5, mat4, false); AdvVertices[advGeomOffset++] = new TerrainParallaxVertex(b_br, advCol, new Vector2(0, 0.4f + 0.33f), 0, n5, mat4, false); AdvVertices[advGeomOffset++] = new TerrainParallaxVertex(b_tr, advCol, new Vector2(0, 0.4f + 0.33f), 0, n5, mat4, false); AdvVertices[advGeomOffset++] = new TerrainParallaxVertex(b_tl, advCol, new Vector2(0, 0.4f + 0.33f), 0, n5, mat4, false); //outer edge: 3 quads for top, left and right edges (on each side!) Action <Vector3, Vector3, Vector3, Vector3, Vector3, Matrix, bool> addEdge = (l, r, m_l, m_r, normal, mat, flip) => { var lToR = r - l; lToR.Normalize(); var lInner = l + lToR * edgeT; var rInner = r - lToR * edgeT; var mlToL = l - m_l; var diagLength = mlToL.Length(); mlToL.Normalize(); var mlInner = m_l + (mlToL + lToR) * edgeT; var innerDiagLength = (mlInner - lInner).Length(); var mrToR = r - m_r; mrToR.Normalize(); var mrInner = m_r + (mrToR - lToR) * edgeT; for (int j = 0; j < 12; j += 4) { AdvIndices[advIndexOffset++] = (advGeomOffset + 2) + j; AdvIndices[advIndexOffset++] = (advGeomOffset + 1) + j; AdvIndices[advIndexOffset++] = advGeomOffset + j; AdvIndices[advIndexOffset++] = advGeomOffset + j; AdvIndices[advIndexOffset++] = (advGeomOffset + 3) + j; AdvIndices[advIndexOffset++] = (advGeomOffset + 2) + j; } var idOff = (diagLength - innerDiagLength) * 0.1f; var hmul = 0.5f; AdvVertices[advGeomOffset++] = new TerrainParallaxVertex(mlInner + edgeO, advCol, new Vector2(-idOff * hmul, 0.33f), 0, normal, mat, flip); AdvVertices[advGeomOffset++] = new TerrainParallaxVertex(m_l + edgeO, advCol, new Vector2(0, 0), 0, normal, mat, flip); AdvVertices[advGeomOffset++] = new TerrainParallaxVertex(l + edgeO, advCol, new Vector2(diagLength * -hmul, 0), 0, normal, mat, flip); AdvVertices[advGeomOffset++] = new TerrainParallaxVertex(lInner + edgeO, advCol, new Vector2((idOff + innerDiagLength) * -hmul, 0.33f), 0, normal, mat, flip); var topLength = (m_r - m_l).Length(); var innerTopLength = (mrInner - mlInner).Length(); var itOff = (topLength - innerTopLength) / 2; AdvVertices[advGeomOffset++] = new TerrainParallaxVertex(mrInner + edgeO, advCol, new Vector2((itOff + innerTopLength) * hmul, 0.33f), 0, normal, mat, flip); AdvVertices[advGeomOffset++] = new TerrainParallaxVertex(m_r + edgeO, advCol, new Vector2(topLength * hmul, 0), 0, normal, mat, flip); AdvVertices[advGeomOffset++] = new TerrainParallaxVertex(m_l + edgeO, advCol, new Vector2(0, 0), 0, normal, mat, flip); AdvVertices[advGeomOffset++] = new TerrainParallaxVertex(mlInner + edgeO, advCol, new Vector2(itOff * hmul, 0.33f), 0, normal, mat, flip); AdvVertices[advGeomOffset++] = new TerrainParallaxVertex(mrInner + edgeO, advCol, new Vector2((topLength + idOff) * hmul, 0.33f), 0, normal, mat, flip); AdvVertices[advGeomOffset++] = new TerrainParallaxVertex(rInner + edgeO, advCol, new Vector2((topLength + idOff + innerDiagLength) * hmul, 0.33f), 0, normal, mat, flip); AdvVertices[advGeomOffset++] = new TerrainParallaxVertex(r + edgeO, advCol, new Vector2((topLength + diagLength) * hmul, 0f), 0, normal, mat, flip); AdvVertices[advGeomOffset++] = new TerrainParallaxVertex(m_r + edgeO, advCol, new Vector2(topLength * hmul, 0f), 0, normal, mat, flip); }; addEdge(tl, tr, m_tl, m_tr, n1, mat1, true); addEdge(tr, br, m_tr, m_br, n2, mat2, true); addEdge(br, bl, m_br, m_bl, n3, mat3, false); addEdge(bl, tl, m_bl, m_tl, n4, mat4, false); } } var result = new RoofData() { Vertices = Vertices, Indices = Indices, NumPrimitives = numPrimitives, AdvVertices = AdvVertices, AdvIndices = AdvIndices, AdvNumPrimitives = advNumPrimitives }; return(result); }