/// <summary> /// Builds the structures. /// </summary> public override VertexStructure BuildStructure(StructureBuildOptions buildOptions) { VertexStructure result = new VertexStructure(); // Calculate parameters Vector3 firstCoordinate = new Vector3( -((TilesX * TileWidth) / 2f), 0f, -((TilesZ * TileWidth) / 2f)); float tileWidthX = this.TileWidth; float tileWidthZ = this.TileWidth; float fieldWidth = tileWidthX * TilesX; float fieldDepth = tileWidthZ * TilesZ; float fieldWidthHalf = fieldWidth / 2f; float fieldDepthHalf = fieldDepth / 2f; int tileMiddleX = (TilesX % 2 == 0) && (this.HighlightXZLines) ? this.TilesX / 2 : 1; int tileMiddleZ = (TilesZ % 2 == 0) && (this.HighlightXZLines) ? this.TilesZ / 2 : 1; // Define lower ground structure if (this.GenerateGround) { VertexStructureSurface lowerGround = result.CreateSurface(); lowerGround.EnableTextureTileMode(new Vector2(TileWidth, TileWidth)); lowerGround.BuildRect4V( new Vector3(-fieldWidthHalf, -0.01f, -fieldDepthHalf), new Vector3(fieldWidthHalf, -0.01f, -fieldDepthHalf), new Vector3(fieldWidthHalf, -0.01f, fieldDepthHalf), new Vector3(-fieldWidthHalf, -0.01f, fieldDepthHalf), new Vector3(0f, 1f, 0f), this.GroundColor); lowerGround.Material = this.GroundMaterial; } // Define line structures VertexStructureSurface genStructureDefaultLine = result.CreateSurface(); VertexStructureSurface genStructureGroupLine = result.CreateSurface(); for (int actTileX = 0; actTileX < TilesX + 1; actTileX++) { Vector3 localStart = firstCoordinate + new Vector3(actTileX * tileWidthX, 0f, 0f); Vector3 localEnd = localStart + new Vector3(0f, 0f, tileWidthZ * TilesZ); Color4 actLineColor = this.LineColor; float devider = actTileX % this.GroupTileCount == 0 ? this.LineSmallDevider : this.LineBigDevider; if (this.HighlightXZLines && (actTileX == tileMiddleX)) { actLineColor = this.ZLineHighlightColor; devider = this.LineSmallDevider; } VertexStructureSurface targetStruture = actTileX % this.GroupTileCount == 0 ? genStructureGroupLine : genStructureDefaultLine; targetStruture.BuildRect4V( localStart - new Vector3(tileWidthX / devider, 0f, 0f), localStart + new Vector3(tileWidthX / devider, 0f, 0f), localEnd + new Vector3(tileWidthX / devider, 0f, 0f), localEnd - new Vector3(tileWidthX / devider, 0f, 0f), actLineColor); if (this.BuildBackFaces) { targetStruture.BuildRect4V( localEnd - new Vector3(tileWidthX / devider, 0f, 0f), localEnd + new Vector3(tileWidthX / devider, 0f, 0f), localStart + new Vector3(tileWidthX / devider, 0f, 0f), localStart - new Vector3(tileWidthX / devider, 0f, 0f), actLineColor); } } for (int actTileZ = 0; actTileZ < TilesZ + 1; actTileZ++) { Vector3 localStart = firstCoordinate + new Vector3(0f, 0f, actTileZ * tileWidthZ); Vector3 localEnd = localStart + new Vector3(tileWidthX * TilesX, 0f, 0f); Color4 actLineColor = this.LineColor; float devider = actTileZ % this.GroupTileCount == 0 ? this.LineSmallDevider : this.LineBigDevider; if (this.HighlightXZLines && (actTileZ == tileMiddleZ)) { actLineColor = this.XLineHighlightColor; devider = this.LineSmallDevider; } VertexStructureSurface targetStruture = actTileZ % this.GroupTileCount == 0 ? genStructureGroupLine : genStructureDefaultLine; targetStruture.BuildRect4V( localStart + new Vector3(0f, 0f, tileWidthZ / devider), localStart - new Vector3(0f, 0f, tileWidthZ / devider), localEnd - new Vector3(0f, 0f, tileWidthZ / devider), localEnd + new Vector3(0f, 0f, tileWidthZ / devider), actLineColor); if (this.BuildBackFaces) { targetStruture.BuildRect4V( localEnd + new Vector3(0f, 0f, tileWidthZ / devider), localEnd - new Vector3(0f, 0f, tileWidthZ / devider), localStart - new Vector3(0f, 0f, tileWidthZ / devider), localStart + new Vector3(0f, 0f, tileWidthZ / devider), actLineColor); } } genStructureDefaultLine.Material = this.LineMaterial; genStructureGroupLine.Material = this.LineMaterial; if (genStructureDefaultLine.CountTriangles == 0) { result.RemoveSurface(genStructureDefaultLine); } if (genStructureGroupLine.CountTriangles == 0) { result.RemoveSurface(genStructureGroupLine); } // Return all generated structures return(result); }
/// <summary> /// Fills the given vertex structure using information from the given AC-File-Objects. /// </summary> /// <param name="objInfo">The object information from the AC file.</param> /// <param name="acMaterials">A list containing all materials from the AC file.</param> /// <param name="structure">The VertexStructure to be filled.</param> /// <param name="transformStack">Current matrix stack (for stacked objects).</param> private static void FillVertexStructure(VertexStructure structure, List <ACMaterialInfo> acMaterials, ACObjectInfo objInfo, Matrix4Stack transformStack) { List <Tuple <int, int> > standardShadedVertices = new List <Tuple <int, int> >(); transformStack.Push(); try { // Perform local transformation for the current AC object transformStack.TransformLocal(objInfo.Rotation); transformStack.TranslateLocal(objInfo.Translation); // Build structures material by material for (int actMaterialIndex = 0; actMaterialIndex < acMaterials.Count; actMaterialIndex++) { ACMaterialInfo actMaterial = acMaterials[actMaterialIndex]; VertexStructureSurface actStructSurface = structure.CreateOrGetExistingSurface(actMaterial.CreateMaterialProperties()); bool isNewSurface = actStructSurface.CountTriangles == 0; // Create and configure vertex structure actStructSurface.Material = NamedOrGenericKey.Empty; actStructSurface.TextureKey = !string.IsNullOrEmpty(objInfo.Texture) ? new NamedOrGenericKey(objInfo.Texture) : NamedOrGenericKey.Empty; actStructSurface.MaterialProperties.DiffuseColor = actMaterial.Diffuse; actStructSurface.MaterialProperties.AmbientColor = actMaterial.Ambient; actStructSurface.MaterialProperties.EmissiveColor = actMaterial.Emissive; actStructSurface.MaterialProperties.Shininess = actMaterial.Shininess; actStructSurface.MaterialProperties.SpecularColor = actMaterial.Specular; // Initialize local index table (needed for vertex reuse) int oneSideVertexCount = objInfo.Vertices.Count; int[] localIndices = new int[oneSideVertexCount * 2]; for (int loop = 0; loop < localIndices.Length; loop++) { localIndices[loop] = int.MaxValue; } // Process all surfaces foreach (ACSurface actSurface in objInfo.Surfaces) { // Get the vertex index on which to start int startVertexIndex = structure.CountVertices; int startTriangleIndex = actStructSurface.CountTriangles; // Only handle surfaces of the current material if (actSurface.Material != actMaterialIndex) { continue; } // Sort out unsupported surfaces if (actSurface.VertexReferences.Count < 3) { continue; } if (actSurface.IsLine) { continue; } if (actSurface.IsClosedLine) { continue; } // Preprocess referenced vertices int oneSideSurfaceVertexCount = actSurface.VertexReferences.Count; int countSurfaceSides = actSurface.IsTwoSided ? 2 : 1; int[] onStructureReferencedVertices = new int[oneSideSurfaceVertexCount * countSurfaceSides]; List <int> surfaceVertexReferences = actSurface.VertexReferences; for (int loop = 0; loop < surfaceVertexReferences.Count; loop++) { Vector2 actTexCoord = actSurface.TextureCoordinates[loop]; if (!actSurface.IsFlatShaded) { // Try to reuse vertices on standard shading if (localIndices[surfaceVertexReferences[loop]] == int.MaxValue) { Vector3 position = Vector3.Transform( objInfo.Vertices[surfaceVertexReferences[loop]].Position, transformStack.Top); localIndices[surfaceVertexReferences[loop]] = structure.AddVertex(new Vertex( position, Color4.White, actTexCoord, Vector3.Zero)); if (actSurface.IsTwoSided) { localIndices[surfaceVertexReferences[loop] + oneSideVertexCount] = structure.AddVertex(new Vertex( position, Color4.White, actTexCoord, Vector3.Zero)); } } // Store vertex reference for this surface's index onStructureReferencedVertices[loop] = localIndices[surfaceVertexReferences[loop]]; if (actSurface.IsTwoSided) { onStructureReferencedVertices[loop + oneSideSurfaceVertexCount] = localIndices[surfaceVertexReferences[loop] + oneSideVertexCount]; } } else { // Create one vertex for one reference for flat shading Vector3 position = Vector3.Transform( objInfo.Vertices[surfaceVertexReferences[loop]].Position, transformStack.Top); onStructureReferencedVertices[loop] = structure.AddVertex(new Vertex( position, Color4.White, actTexCoord, Vector3.Zero)); if (actSurface.IsTwoSided) { onStructureReferencedVertices[loop + oneSideSurfaceVertexCount] = structure.AddVertex(new Vertex( position, Color4.White, actTexCoord, Vector3.Zero)); } } } // Build object geometry switch (actSurface.VertexReferences.Count) { case 3: // Front side actStructSurface.AddTriangle( onStructureReferencedVertices[0], onStructureReferencedVertices[1], onStructureReferencedVertices[2]); // Back side if (actSurface.IsTwoSided) { actStructSurface.AddTriangle( onStructureReferencedVertices[5], onStructureReferencedVertices[4], onStructureReferencedVertices[3]); } break; case 4: // Front side actStructSurface.AddTriangle( onStructureReferencedVertices[0], onStructureReferencedVertices[1], onStructureReferencedVertices[2]); actStructSurface.AddTriangle( onStructureReferencedVertices[2], onStructureReferencedVertices[3], onStructureReferencedVertices[0]); // Back side if (actSurface.IsTwoSided) { actStructSurface.AddTriangle( onStructureReferencedVertices[6], onStructureReferencedVertices[5], onStructureReferencedVertices[4]); actStructSurface.AddTriangle( onStructureReferencedVertices[4], onStructureReferencedVertices[7], onStructureReferencedVertices[6]); } break; default: if (!actSurface.IsTwoSided) { // Front side actStructSurface.AddPolygonByCuttingEars(onStructureReferencedVertices); } else { // Front and back side actStructSurface.AddPolygonByCuttingEars(onStructureReferencedVertices.Subset(0, oneSideSurfaceVertexCount)); actStructSurface.AddPolygonByCuttingEars(onStructureReferencedVertices.Subset(oneSideSurfaceVertexCount, oneSideSurfaceVertexCount)); } break; } // Perform shading if (actSurface.IsFlatShaded) { actStructSurface.CalculateNormalsFlat( startTriangleIndex, actStructSurface.CountTriangles - startTriangleIndex); } else { // Nothing to be done for now.. int vertexCount = structure.CountVertices - startVertexIndex; if (vertexCount > 0) { standardShadedVertices.Add( Tuple.Create((int)startVertexIndex, vertexCount)); } } } // Calculate default shading finally (if any) foreach (var actStandardShadedPair in standardShadedVertices) { structure.CalculateNormals( actStandardShadedPair.Item1, actStandardShadedPair.Item2); } standardShadedVertices.Clear(); // Append generated VertexStructure to the output collection if ((actStructSurface.CountTriangles <= 0) && (isNewSurface)) { structure.RemoveSurface(actStructSurface); } } //Fill in all child object data foreach (ACObjectInfo actObjInfo in objInfo.Childs) { FillVertexStructure(structure, acMaterials, actObjInfo, transformStack); } } finally { transformStack.Pop(); } }