/// <summary> /// Updates all children of this object. Override this to change default behavior. /// </summary> /// <param name="updateState">The current update state.</param> /// <param name="children">The full list of children that should be updated.</param> protected override void UpdateChildrenInternal(SceneRelatedUpdateState updateState, List <SceneObject> children) { bool prevForceState = updateState.ForceTransformUpdatesOnChilds; updateState.ForceTransformUpdatesOnChilds = prevForceState || m_forceTransformUpdateOnChilds; m_forceTransformUpdateOnChilds = false; try { int childCount = children.Count; for (int loop = 0; loop < childCount; loop++) { // Forward current transform matrix to child objects Matrix4Stack currentWorld = updateState.World; currentWorld.Push(m_transform); try { children[loop].Update(updateState); } finally { currentWorld.Pop(); } } } finally { updateState.ForceTransformUpdatesOnChilds = prevForceState; } }
/// <summary> /// Fills the given geometry 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="geometry">The Geometry to be filled.</param> /// <param name="transformStack">Current matrix stack (for stacked objects).</param> private static void FillGeometry(Geometry geometry, List <ACMaterialInfo> acMaterials, ACObjectInfo objInfo, Matrix4Stack transformStack) { var 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 geometry material by material for (var actMaterialIndex = 0; actMaterialIndex < acMaterials.Count; actMaterialIndex++) { var actGeometrySurface = geometry.Surfaces[actMaterialIndex]; // Initialize local index table (needed for vertex reuse) var oneSideVertexCount = objInfo.Vertices.Count; var localIndices = new int[oneSideVertexCount * 2]; for (var loop = 0; loop < localIndices.Length; loop++) { localIndices[loop] = int.MaxValue; } // Process all surfaces foreach (var actSurface in objInfo.Surfaces) { // Get the vertex index on which to start var startVertexIndex = geometry.CountVertices; var startTriangleIndex = actGeometrySurface.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 var oneSideSurfaceVertexCount = actSurface.VertexReferences.Count; var countSurfaceSides = actSurface.IsTwoSided ? 2 : 1; var onGeometryReferencedVertices = new int[oneSideSurfaceVertexCount * countSurfaceSides]; var surfaceVertexReferences = actSurface.VertexReferences; for (var loop = 0; loop < surfaceVertexReferences.Count; loop++) { var actTexCoord = actSurface.TextureCoordinates[loop]; if (!actSurface.IsFlatShaded) { // Try to reuse vertices on standard shading if (localIndices[surfaceVertexReferences[loop]] == int.MaxValue) { var position = Vector3.Transform( objInfo.Vertices[surfaceVertexReferences[loop]].Position, transformStack.Top); localIndices[surfaceVertexReferences[loop]] = geometry.AddVertex(new VertexBasic( position, Color4.White, actTexCoord, Vector3.Zero)); if (actSurface.IsTwoSided) { localIndices[surfaceVertexReferences[loop] + oneSideVertexCount] = geometry.AddVertex(new VertexBasic( position, Color4.White, actTexCoord, Vector3.Zero)); } } // Store vertex reference for this surface's index onGeometryReferencedVertices[loop] = localIndices[surfaceVertexReferences[loop]]; if (actSurface.IsTwoSided) { onGeometryReferencedVertices[loop + oneSideSurfaceVertexCount] = localIndices[surfaceVertexReferences[loop] + oneSideVertexCount]; } } else { // Create one vertex for one reference for flat shading var position = Vector3.Transform( objInfo.Vertices[surfaceVertexReferences[loop]].Position, transformStack.Top); onGeometryReferencedVertices[loop] = geometry.AddVertex(new VertexBasic( position, Color4.White, actTexCoord, Vector3.Zero)); if (actSurface.IsTwoSided) { onGeometryReferencedVertices[loop + oneSideSurfaceVertexCount] = geometry.AddVertex(new VertexBasic( position, Color4.White, actTexCoord, Vector3.Zero)); } } } // Build object geometry switch (actSurface.VertexReferences.Count) { case 3: // Front side actGeometrySurface.AddTriangle( onGeometryReferencedVertices[0], onGeometryReferencedVertices[1], onGeometryReferencedVertices[2]); // Back side if (actSurface.IsTwoSided) { actGeometrySurface.AddTriangle( onGeometryReferencedVertices[5], onGeometryReferencedVertices[4], onGeometryReferencedVertices[3]); } break; case 4: // Front side actGeometrySurface.AddTriangle( onGeometryReferencedVertices[0], onGeometryReferencedVertices[1], onGeometryReferencedVertices[2]); actGeometrySurface.AddTriangle( onGeometryReferencedVertices[2], onGeometryReferencedVertices[3], onGeometryReferencedVertices[0]); // Back side if (actSurface.IsTwoSided) { actGeometrySurface.AddTriangle( onGeometryReferencedVertices[6], onGeometryReferencedVertices[5], onGeometryReferencedVertices[4]); actGeometrySurface.AddTriangle( onGeometryReferencedVertices[4], onGeometryReferencedVertices[7], onGeometryReferencedVertices[6]); } break; default: if (!actSurface.IsTwoSided) { // Front side actGeometrySurface.AddPolygonByCuttingEars(onGeometryReferencedVertices); } else { // Front and back side actGeometrySurface.AddPolygonByCuttingEars(onGeometryReferencedVertices.Subset(0, oneSideSurfaceVertexCount)); actGeometrySurface.AddPolygonByCuttingEars(onGeometryReferencedVertices.Subset(oneSideSurfaceVertexCount, oneSideSurfaceVertexCount)); } break; } // Perform shading if (actSurface.IsFlatShaded) { actGeometrySurface.CalculateNormalsFlat( startTriangleIndex, actGeometrySurface.CountTriangles - startTriangleIndex); } else { // Nothing to be done for now.. var vertexCount = geometry.CountVertices - startVertexIndex; if (vertexCount > 0) { standardShadedVertices.Add( Tuple.Create(startVertexIndex, vertexCount)); } } } // Calculate default shading finally (if any) foreach (var actStandardShadedPair in standardShadedVertices) { geometry.CalculateNormals( actStandardShadedPair.Item1, actStandardShadedPair.Item2); } standardShadedVertices.Clear(); } // Fill in all child object data foreach (var actObjInfo in objInfo.Children) { FillGeometry(geometry, acMaterials, actObjInfo, transformStack); } } finally { transformStack.Pop(); } }
/// <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(); } }