Basic triangle structure.
        /// <summary>
        ///
        /// </summary>
        protected void ConnectEdges()
        {
            int triIndex = 0;

            for (int i = 0; i < edgeData.triangles.Count; i++, triIndex++)
            {
                EdgeData.Triangle tri = (EdgeData.Triangle)edgeData.triangles[i];
                EdgeData.Edge     e   = null;

                if (tri.sharedVertIndex[0] > tri.sharedVertIndex[1])
                {
                    e = FindEdge(tri.sharedVertIndex[1], tri.sharedVertIndex[0]);

                    if (e != null)
                    {
                        e.triIndex[1]  = triIndex;
                        e.isDegenerate = false;
                    }
                }
                if (tri.sharedVertIndex[1] > tri.sharedVertIndex[2])
                {
                    // Find the existing edge (should be reversed order)
                    e = FindEdge(tri.sharedVertIndex[2], tri.sharedVertIndex[1]);

                    if (e != null)
                    {
                        e.triIndex[1]  = triIndex;
                        e.isDegenerate = false;
                    }
                }
                if (tri.sharedVertIndex[2] > tri.sharedVertIndex[0])
                {
                    e = FindEdge(tri.sharedVertIndex[0], tri.sharedVertIndex[2]);

                    if (e != null)
                    {
                        e.triIndex[1]  = triIndex;
                        e.isDegenerate = false;
                    }
                }
            }
        }
		protected override void ReadEdgeList( BinaryReader reader )
		{
			if ( !IsEOF( reader ) )
			{
				var chunkID = ReadChunk( reader );

				while ( !IsEOF( reader ) && chunkID == MeshChunkID.EdgeListLOD )
				{
					// process single LOD
					var lodIndex = ReadShort( reader );

					// If manual, no edge data here, loaded from manual mesh
					var isManual = ReadBool( reader );

					// Only load in non-manual levels; others will be connected up by Mesh on demand
					if ( !isManual )
					{
						var usage = mesh.GetLodLevel( lodIndex );

						usage.EdgeData = new EdgeData();

						var triCount = ReadInt( reader );
						var edgeGroupCount = ReadInt( reader );

						// TODO: Resize triangle list
						// TODO: Resize edge groups

						for ( var i = 0; i < triCount; i++ )
						{
							var tri = new EdgeData.Triangle();

							tri.indexSet = ReadInt( reader );
							tri.vertexSet = ReadInt( reader );

							tri.vertIndex[ 0 ] = ReadInt( reader );
							tri.vertIndex[ 1 ] = ReadInt( reader );
							tri.vertIndex[ 2 ] = ReadInt( reader );

							tri.sharedVertIndex[ 0 ] = ReadInt( reader );
							tri.sharedVertIndex[ 1 ] = ReadInt( reader );
							tri.sharedVertIndex[ 2 ] = ReadInt( reader );

							tri.normal = ReadVector4( reader );

							usage.EdgeData.triangles.Add( tri );
						}

						for ( var eg = 0; eg < edgeGroupCount; eg++ )
						{
							chunkID = ReadChunk( reader );

							if ( chunkID != MeshChunkID.EdgeListGroup )
							{
								throw new AxiomException( "Missing EdgeListGroup chunk." );
							}

							var edgeGroup = new EdgeData.EdgeGroup();

							edgeGroup.vertexSet = ReadInt( reader );

							var edgeCount = ReadInt( reader );

							// TODO: Resize the edge group list

							for ( var e = 0; e < edgeCount; e++ )
							{
								var edge = new EdgeData.Edge();

								edge.triIndex[ 0 ] = ReadInt( reader );
								edge.triIndex[ 1 ] = ReadInt( reader );

								edge.vertIndex[ 0 ] = ReadInt( reader );
								edge.vertIndex[ 1 ] = ReadInt( reader );

								edge.sharedVertIndex[ 0 ] = ReadInt( reader );
								edge.sharedVertIndex[ 1 ] = ReadInt( reader );

								edge.isDegenerate = ReadBool( reader );

								// add the edge to the list
								edgeGroup.edges.Add( edge );
							}

							// Populate edgeGroup.vertexData references
							// If there is shared vertex data, vertexSet 0 is that, 
							// otherwise 0 is first dedicated
							if ( mesh.SharedVertexData != null )
							{
								if ( edgeGroup.vertexSet == 0 )
								{
									edgeGroup.vertexData = mesh.SharedVertexData;
								}
								else
								{
									edgeGroup.vertexData = mesh.GetSubMesh( edgeGroup.vertexSet - 1 ).vertexData;
								}
							}
							else
							{
								edgeGroup.vertexData = mesh.GetSubMesh( edgeGroup.vertexSet ).vertexData;
							}

							// add the edge group to the list
							usage.EdgeData.edgeGroups.Add( edgeGroup );
						}
					}

					// grab the next chunk
					if ( !IsEOF( reader ) )
					{
						chunkID = ReadChunk( reader );
					}
				}

				// grab the next chunk
				if ( !IsEOF( reader ) )
				{
					// backpedal to the start of chunk
					Seek( reader, -ChunkOverheadSize );
				}
			}

			mesh.IsEdgeListBuilt = true;
		}
        /// <summary>
        ///		Generates the indexes required to render a shadow volume into the
        ///		index buffer which is passed in, and updates shadow renderables to use it.
        /// </summary>
        /// <param name="edgeData">The edge information to use.</param>
        /// <param name="indexBuffer">The buffer into which to write data into; current
        ///	contents are assumed to be discardable.</param>
        /// <param name="light">The light, mainly for type info as silhouette calculations
        /// should already have been done in <see cref="UpdateEdgeListLightFacing"/></param>
        /// <param name="shadowRenderables">A list of shadow renderables which has
        /// already been constructed but will need populating with details of
        /// the index ranges to be used.</param>
        /// <param name="flags">Additional controller flags, see <see cref="ShadowRenderableFlags"/>.</param>
        protected virtual void GenerateShadowVolume(EdgeData edgeData, HardwareIndexBuffer indexBuffer, Light light,
                                                    ShadowRenderableList shadowRenderables, int flags)
        {
            // Edge groups should be 1:1 with shadow renderables
            Debug.Assert(edgeData.edgeGroups.Count == shadowRenderables.Count);

            LightType lightType = light.Type;

            bool extrudeToInfinity = (flags & (int)ShadowRenderableFlags.ExtrudeToInfinity) > 0;

            // Lock index buffer for writing
            IntPtr idxPtr = indexBuffer.Lock(BufferLocking.Discard);

            int indexStart = 0;

            unsafe {
                // TODO: Will currently cause an overflow for 32 bit indices, revisit
                short *pIdx  = (short *)idxPtr.ToPointer();
                int    count = 0;

                // Iterate over the groups and form renderables for each based on their
                // lightFacing
                for (int groupCount = 0; groupCount < edgeData.edgeGroups.Count; groupCount++)
                {
                    EdgeData.EdgeGroup eg = (EdgeData.EdgeGroup)edgeData.edgeGroups[groupCount];
                    ShadowRenderable   si = (ShadowRenderable)shadowRenderables[groupCount];

                    RenderOperation lightShadOp = null;

                    // Initialise the index bounds for this shadow renderable
                    RenderOperation shadOp = si.GetRenderOperationForUpdate();
                    shadOp.indexData.indexCount = 0;
                    shadOp.indexData.indexStart = indexStart;

                    // original number of verts (without extruded copy)
                    int  originalVertexCount = eg.vertexData.vertexCount;
                    bool firstDarkCapTri     = true;
                    int  darkCapStart        = 0;

                    for (int edgeCount = 0; edgeCount < eg.edges.Count; edgeCount++)
                    {
                        EdgeData.Edge edge = (EdgeData.Edge)eg.edges[edgeCount];

                        EdgeData.Triangle t1 = (EdgeData.Triangle)edgeData.triangles[edge.triIndex[0]];
                        EdgeData.Triangle t2 =
                            edge.isDegenerate ? (EdgeData.Triangle)edgeData.triangles[edge.triIndex[0]] : (EdgeData.Triangle)edgeData.triangles[edge.triIndex[1]];

                        if (t1.lightFacing && (edge.isDegenerate || !t2.lightFacing))
                        {
                            /* Silhouette edge, first tri facing the light
                             * Also covers degenerate tris where only tri 1 is valid
                             * Remember verts run anticlockwise along the edge from
                             * tri 0 so to point shadow volume tris outward, light cap
                             * indexes have to be backwards
                             *
                             * We emit 2 tris if light is a point light, 1 if light
                             * is directional, because directional lights cause all
                             * points to converge to a single point at infinity.
                             *
                             * First side tri = near1, near0, far0
                             * Second tri = far0, far1, near1
                             *
                             * 'far' indexes are 'near' index + originalVertexCount
                             * because 'far' verts are in the second half of the
                             * buffer
                             */
                            pIdx[count++] = (short)edge.vertIndex[1];
                            pIdx[count++] = (short)edge.vertIndex[0];
                            pIdx[count++] = (short)(edge.vertIndex[0] + originalVertexCount);
                            shadOp.indexData.indexCount += 3;

                            if (!(lightType == LightType.Directional && extrudeToInfinity))
                            {
                                // additional tri to make quad
                                pIdx[count++] = (short)(edge.vertIndex[0] + originalVertexCount);
                                pIdx[count++] = (short)(edge.vertIndex[1] + originalVertexCount);
                                pIdx[count++] = (short)edge.vertIndex[1];
                                shadOp.indexData.indexCount += 3;
                            }

                            // Do dark cap tri
                            // Use McGuire et al method, a triangle fan covering all silhouette
                            // edges and one point (taken from the initial tri)
                            if ((flags & (int)ShadowRenderableFlags.IncludeDarkCap) > 0)
                            {
                                if (firstDarkCapTri)
                                {
                                    darkCapStart    = edge.vertIndex[0] + originalVertexCount;
                                    firstDarkCapTri = false;
                                }
                                else
                                {
                                    pIdx[count++] = (short)darkCapStart;
                                    pIdx[count++] = (short)(edge.vertIndex[1] + originalVertexCount);
                                    pIdx[count++] = (short)(edge.vertIndex[0] + originalVertexCount);
                                    shadOp.indexData.indexCount += 3;
                                }
                            }
                        }
                        else if (!t1.lightFacing && (edge.isDegenerate || t2.lightFacing))
                        {
                            // Silhouette edge, second tri facing the light
                            // Note edge indexes inverse of when t1 is light facing
                            pIdx[count++] = (short)edge.vertIndex[0];
                            pIdx[count++] = (short)edge.vertIndex[1];
                            pIdx[count++] = (short)(edge.vertIndex[1] + originalVertexCount);
                            shadOp.indexData.indexCount += 3;

                            if (!(lightType == LightType.Directional && extrudeToInfinity))
                            {
                                // additional tri to make quad
                                pIdx[count++] = (short)(edge.vertIndex[1] + originalVertexCount);
                                pIdx[count++] = (short)(edge.vertIndex[0] + originalVertexCount);
                                pIdx[count++] = (short)edge.vertIndex[0];
                                shadOp.indexData.indexCount += 3;
                            }

                            // Do dark cap tri
                            // Use McGuire et al method, a triangle fan covering all silhouette
                            // edges and one point (taken from the initial tri)
                            if ((flags & (int)ShadowRenderableFlags.IncludeDarkCap) > 0)
                            {
                                if (firstDarkCapTri)
                                {
                                    darkCapStart    = edge.vertIndex[1] + originalVertexCount;
                                    firstDarkCapTri = false;
                                }
                                else
                                {
                                    pIdx[count++] = (short)darkCapStart;
                                    pIdx[count++] = (short)(edge.vertIndex[0] + originalVertexCount);
                                    pIdx[count++] = (short)(edge.vertIndex[1] + originalVertexCount);
                                    shadOp.indexData.indexCount += 3;
                                }
                            }
                        }
                    }

                    // Do light cap
                    if ((flags & (int)ShadowRenderableFlags.IncludeLightCap) > 0)
                    {
                        ShadowRenderable lightCapRend = null;

                        if (si.IsLightCapSeperate)
                        {
                            // separate light cap
                            lightCapRend = si.LightCapRenderable;
                            lightShadOp  = lightCapRend.GetRenderOperationForUpdate();
                            lightShadOp.indexData.indexCount = 0;
                            // start indexes after the current total
                            // NB we don't update the total here since that's done below
                            lightShadOp.indexData.indexStart =
                                indexStart + shadOp.indexData.indexCount;
                        }

                        for (int triCount = 0; triCount < edgeData.triangles.Count; triCount++)
                        {
                            EdgeData.Triangle t = (EdgeData.Triangle)edgeData.triangles[triCount];

                            // Light facing, and vertex set matches
                            if (t.lightFacing && t.vertexSet == eg.vertexSet)
                            {
                                pIdx[count++] = (short)t.vertIndex[0];
                                pIdx[count++] = (short)t.vertIndex[1];
                                pIdx[count++] = (short)t.vertIndex[2];

                                if (lightShadOp != null)
                                {
                                    lightShadOp.indexData.indexCount += 3;
                                }
                                else
                                {
                                    shadOp.indexData.indexCount += 3;
                                }
                            }
                        }
                    }

                    // update next indexStart (all renderables sharing the buffer)
                    indexStart += shadOp.indexData.indexCount;

                    // add on the light cap too
                    if (lightShadOp != null)
                    {
                        indexStart += lightShadOp.indexData.indexCount;
                    }
                }
            }

            // Unlock index buffer
            indexBuffer.Unlock();

            Debug.Assert(indexStart <= indexBuffer.IndexCount, "Index buffer overrun while generating shadow volume!");
        }
Exemple #4
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="indexSet"></param>
        /// <param name="vertexSet"></param>
        protected void BuildTrianglesEdges(int indexSet, int vertexSet)
        {
            var indexData = (IndexData)indexDataList[indexSet];
            var opType    = operationTypes[indexSet];

            var iterations = 0;

            switch (opType)
            {
            case OperationType.TriangleList:
                iterations = indexData.indexCount / 3;
                break;

            case OperationType.TriangleFan:
            case OperationType.TriangleStrip:
                iterations = indexData.indexCount - 2;
                break;
            }

            // locate postion element & the buffer to go with it
            var vertexData = (VertexData)vertexDataList[vertexSet];
            var posElem    = vertexData.vertexDeclaration.FindElementBySemantic(VertexElementSemantic.Position);

            var posBuffer = vertexData.vertexBufferBinding.GetBuffer(posElem.Source);
            var posPtr    = posBuffer.Lock(BufferLocking.ReadOnly);
            var idxPtr    = indexData.indexBuffer.Lock(BufferLocking.ReadOnly);

#if !AXIOM_SAFE_ONLY
            unsafe
#endif
            {
                var pBaseVertex = posPtr;

                var p16Idx = idxPtr.ToShortPointer();
                var p32Idx = idxPtr.ToIntPointer();

                // counters used for pointer indexing
                var count16 = 0;
                var count32 = 0;

                var triStart = this.edgeData.triangles.Count;

                // iterate over all the groups of 3 indices
                this.edgeData.triangles.Capacity = triStart + iterations;

                for (var t = 0; t < iterations; t++)
                {
                    var tri = new EdgeData.Triangle();
                    tri.indexSet  = indexSet;
                    tri.vertexSet = vertexSet;

                    var index = new int[3];
                    var v     = new Vector3[3];

                    for (var i = 0; i < 3; i++)
                    {
                        // Standard 3-index read for tri list or first tri in strip / fan
                        if (opType == OperationType.TriangleList || t == 0)
                        {
                            if (indexData.indexBuffer.Type == IndexType.Size32)
                            {
                                index[i] = p32Idx[count32++];
                            }
                            else
                            {
                                index[i] = p16Idx[count16++];
                            }
                        }
                        else
                        {
                            // Strips and fans are formed from last 2 indexes plus the
                            // current one for triangles after the first
                            if (indexData.indexBuffer.Type == IndexType.Size32)
                            {
                                index[i] = p32Idx[i - 2];
                            }
                            else
                            {
                                index[i] = p16Idx[i - 2];
                            }

                            // Perform single-index increment at the last tri index
                            if (i == 2)
                            {
                                if (indexData.indexBuffer.Type == IndexType.Size32)
                                {
                                    count32++;
                                }
                                else
                                {
                                    count16++;
                                }
                            }
                        }

                        // populate tri original vertex index
                        tri.vertIndex[i] = index[i];

                        // Retrieve the vertex position
                        var pVertex = pBaseVertex + (index[i] * posBuffer.VertexSize);
                        var pReal   = (pVertex + posElem.Offset).ToFloatPointer();

                        v[i].x = pReal[0];
                        v[i].y = pReal[1];
                        v[i].z = pReal[2];
                        // find this vertex in the existing vertex map, or create it
                        tri.sharedVertIndex[i] = FindOrCreateCommonVertex(v[i], vertexSet, indexSet, index[i]);
                    }

                    // Calculate triangle normal (NB will require recalculation for
                    // skeletally animated meshes)
                    tri.normal = CalculateFaceNormal(v[0], v[1], v[2]);

                    // Add triangle to list
                    this.edgeData.triangles.Add(tri);

                    try
                    {
                        // create edges from common list
                        if (tri.sharedVertIndex[0] < tri.sharedVertIndex[1])
                        {
                            CreateEdge(vertexSet, triStart + t, tri.vertIndex[0], tri.vertIndex[1], tri.sharedVertIndex[0],
                                       tri.sharedVertIndex[1]);
                        }
                        if (tri.sharedVertIndex[1] < tri.sharedVertIndex[2])
                        {
                            CreateEdge(vertexSet, triStart + t, tri.vertIndex[1], tri.vertIndex[2], tri.sharedVertIndex[1],
                                       tri.sharedVertIndex[2]);
                        }
                        if (tri.sharedVertIndex[2] < tri.sharedVertIndex[0])
                        {
                            CreateEdge(vertexSet, triStart + t, tri.vertIndex[2], tri.vertIndex[0], tri.sharedVertIndex[2],
                                       tri.sharedVertIndex[0]);
                        }
                    }
                    catch (Exception ex)
                    {
                        //Debug.WriteLine(ex.ToString());
                        //Debug.WriteLine(ex.StackTrace);
                        // unlock those buffers!
                        indexData.indexBuffer.Unlock();
                        posBuffer.Unlock();

                        throw ex;
                    }
                } // for iterations
            }     // unsafe

            // unlock those buffers!
            indexData.indexBuffer.Unlock();
            posBuffer.Unlock();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="indexSet"></param>
        /// <param name="vertexSet"></param>
        protected void BuildTrianglesEdges(int indexSet, int vertexSet)
        {
            IndexData indexData = (IndexData)indexDataList[indexSet];
            OperationType opType = operationTypes[indexSet];

            int iterations = 0;

            switch (opType) {
                case OperationType.TriangleList:
                    iterations = indexData.indexCount / 3;
                    break;

                case OperationType.TriangleFan:
                case OperationType.TriangleStrip:
                    iterations = indexData.indexCount - 2;
                    break;
            }

            // locate postion element & the buffer to go with it
            VertexData vertexData = (VertexData)vertexDataList[vertexSet];
            VertexElement posElem =
                vertexData.vertexDeclaration.FindElementBySemantic(VertexElementSemantic.Position);

            HardwareVertexBuffer posBuffer = vertexData.vertexBufferBinding.GetBuffer(posElem.Source);
            IntPtr posPtr = posBuffer.Lock(BufferLocking.ReadOnly);
            IntPtr idxPtr = indexData.indexBuffer.Lock(BufferLocking.ReadOnly);

            unsafe {
                byte* pBaseVertex = (byte*)posPtr.ToPointer();

                short* p16Idx = null;
                int* p32Idx = null;

                // counters used for pointer indexing
                int count16 = 0;
                int count32 = 0;

                if(indexData.indexBuffer.Type == IndexType.Size16) {
                    p16Idx = (short*)idxPtr.ToPointer();
                }
                else {
                    p32Idx = (int*)idxPtr.ToPointer();
                }

                float* pReal = null;

                int triStart = edgeData.triangles.Count;

                // iterate over all the groups of 3 indices
                edgeData.triangles.Capacity = triStart + iterations;

                for(int t = 0; t < iterations; t++) {
                    EdgeData.Triangle tri = new EdgeData.Triangle();
                    tri.indexSet = indexSet;
                    tri.vertexSet = vertexSet;

                    int[] index = new int[3];
                    Vector3[] v = new Vector3[3];

                    for(int i = 0; i < 3; i++) {
                        // Standard 3-index read for tri list or first tri in strip / fan
                        if (opType == OperationType.TriangleList || t == 0) {
                            if (indexData.indexBuffer.Type == IndexType.Size32) {
                                index[i] = p32Idx[count32++];
                            }
                            else {
                                index[i] = p16Idx[count16++];
                            }
                        }
                        else {
                            // Strips and fans are formed from last 2 indexes plus the
                            // current one for triangles after the first
                            if (indexData.indexBuffer.Type == IndexType.Size32) {
                                index[i] = p32Idx[i - 2];
                            }
                            else {
                                index[i] = p16Idx[i - 2];
                            }

                            // Perform single-index increment at the last tri index
                            if (i == 2) {
                                if (indexData.indexBuffer.Type == IndexType.Size32) {
                                    count32++;
                                }
                                else {
                                    count16++;
                                }
                            }
                        }

                        // populate tri original vertex index
                        tri.vertIndex[i] = index[i];

                        // Retrieve the vertex position
                        byte* pVertex = pBaseVertex + (index[i] * posBuffer.VertexSize);
                        pReal = (float*)(pVertex + posElem.Offset);
                        v[i].x = *pReal++;
                        v[i].y = *pReal++;
                        v[i].z = *pReal++;
                        // find this vertex in the existing vertex map, or create it
                        tri.sharedVertIndex[i] = FindOrCreateCommonVertex(v[i], vertexSet, indexSet, index[i]);
                    }

                    // Calculate triangle normal (NB will require recalculation for
                    // skeletally animated meshes)
                    tri.normal = MathUtil.CalculateFaceNormal(v[0], v[1], v[2]);

                    // Add triangle to list
                    edgeData.triangles.Add(tri);

                    try {
                        // create edges from common list
                        if (tri.sharedVertIndex[0] < tri.sharedVertIndex[1]) {
                            CreateEdge(vertexSet, triStart + t,
                                tri.vertIndex[0], tri.vertIndex[1],
                                tri.sharedVertIndex[0], tri.sharedVertIndex[1]);
                        }
                        if (tri.sharedVertIndex[1] < tri.sharedVertIndex[2]) {
                            CreateEdge(vertexSet, triStart + t,
                                tri.vertIndex[1], tri.vertIndex[2],
                                tri.sharedVertIndex[1], tri.sharedVertIndex[2]);
                        }
                        if (tri.sharedVertIndex[2] < tri.sharedVertIndex[0]) {
                            CreateEdge(vertexSet, triStart + t,
                                tri.vertIndex[2], tri.vertIndex[0],
                                tri.sharedVertIndex[2], tri.sharedVertIndex[0]);
                        }
                    }
                    catch (Exception ex) {
                        //Debug.WriteLine(ex.ToString());
                        //Debug.WriteLine(ex.StackTrace);
                        // unlock those buffers!
                        indexData.indexBuffer.Unlock();
                        posBuffer.Unlock();

                        throw ex;
                    }
                } // for iterations
            } // unsafe

            // unlock those buffers!
            indexData.indexBuffer.Unlock();
            posBuffer.Unlock();
        }