Example #1
0
        /// <summary>
        /// Attempts to fix the surface normals.  Call this after the shape has been
        /// loaded and the data validated.
        /// </summary>
        /// <param name="vw">Wireframe data.</param>
        /// <param name="offset">Initial shape offset.</param>
        private void FixNormals(VisWireframe vw, int offset)
        {
            const int minVisThresh = 0x9;

            int edgeOffset = offset + (short)(mFileData[offset + 0x03] |
                                              (mFileData[offset + 0x10] << 8));
            int faceOffset = offset + (short)(mFileData[offset + 0x04] |
                                              (mFileData[offset + 0x11] << 8));

            float[]   verticesX = vw.GetVerticesX();
            float[]   verticesY = vw.GetVerticesY();
            float[]   verticesZ = vw.GetVerticesZ();
            float[]   normalsX  = vw.GetNormalsX();
            float[]   normalsY  = vw.GetNormalsY();
            float[]   normalsZ  = vw.GetNormalsZ();
            IntPair[] edges     = vw.GetEdges();
            IntPair[] edgeFaces = vw.GetEdgeFaces();

            for (int face = 0; face < normalsX.Length; face++)
            {
                // Find the first edge that references this face.  We ignore anything whose
                // visibility threshold is too low.
                int edge = -1;
                int ef;
                for (ef = 0; ef < edgeFaces.Length; ef++)
                {
                    // pull the flags out of the edge data to get the visibility threshold
                    byte flags = mFileData[edgeOffset + edgeFaces[ef].Val0 * 4];
                    if (flags > 0x1f)
                    {
                        mAppRef.DebugLog("BAD FLAG " + flags.ToString("x2"));
                    }
                    if (flags < minVisThresh)
                    {
                        continue;
                    }
                    if (edgeFaces[ef].Val1 == face)
                    {
                        edge = edgeFaces[ef].Val0;
                        break;
                    }
                }
                if (edge < 0)
                {
                    mAppRef.DebugLog("Unable to find first edge for face " + face);
                    continue;
                }

                // Extract the two vertices.
                int v0 = edges[edge].Val0;
                int v1 = edges[edge].Val1;

                // Find another edge for this face that has a common vertex.
                edge = -1;
                for (++ef; ef < edgeFaces.Length; ef++)
                {
                    byte flags = mFileData[edgeOffset + edgeFaces[ef].Val0 * 4];
                    if (flags > 0x1f)
                    {
                        mAppRef.DebugLog("BAD FLAG " + flags.ToString("x2"));
                    }
                    if (flags < minVisThresh)
                    {
                        continue;
                    }
                    if (edgeFaces[ef].Val1 == face)
                    {
                        int chkEdge = edgeFaces[ef].Val0;
                        if (edges[chkEdge].Val0 == v0 || edges[chkEdge].Val0 == v1 ||
                            edges[chkEdge].Val1 == v0 || edges[chkEdge].Val1 == v1)
                        {
                            edge = chkEdge;
                            break;
                        }
                    }
                }
                if (edge < 0)
                {
                    mAppRef.DebugLog("Unable to find second edge for face " + face);
                    continue;
                }

                // Arrange the vertices so the edges are v0-v1 and v1-v2.  If the edges have
                // v0 in common we shuffle things around.
                int v2;
                if (edges[edge].Val0 == v0)
                {
                    v2 = v1;
                    v1 = v0;
                    v0 = edges[edge].Val1;
                }
                else if (edges[edge].Val1 == v0)
                {
                    v2 = v1;
                    v1 = v0;
                    v0 = edges[edge].Val0;
                }
                else if (edges[edge].Val0 == v1)
                {
                    v2 = edges[edge].Val1;
                }
                else if (edges[edge].Val1 == v1)
                {
                    v2 = edges[edge].Val0;
                }
                else
                {
                    mAppRef.DebugLog("BUG!");
                    continue;
                }

                //mAppRef.DebugLog("Face " + face + ": using vertices " + v0 + "," + v1 + "," + v2);

                // Create vectors for the edges.
                Vector3 vec0  = new Vector3(verticesX[v0], verticesY[v0], verticesZ[v0]);
                Vector3 vec1  = new Vector3(verticesX[v1], verticesY[v1], verticesZ[v1]);
                Vector3 vec2  = new Vector3(verticesX[v2], verticesY[v2], verticesZ[v2]);
                Vector3 evec0 = Vector3.Subtract(vec0, vec1);
                Vector3 evec1 = Vector3.Subtract(vec1, vec2);

                // Compute the cross product.
                Vector3 cross    = Vector3.Cross(evec0, evec1);
                Vector3 negCross = cross.Multiply(-1);

                //mAppRef.DebugLog("  evec0=" + evec0 + " evec1=" + evec1 + " cross=" + cross);

                // Check to see if we got the sign backward by adding the new vector to
                // one of the vertices.  If it moves us farther from the center of the
                // object, it's facing outward, and we're good.
                if (Vector3.Add(vec0, cross).Magnitude() <
                    Vector3.Add(vec0, negCross).Magnitude())
                {
                    // flip it
                    cross = negCross;
                }

                // Replace the entry.
                Vector3 orig =
                    new Vector3(normalsX[face], normalsY[face], normalsZ[face]).Normalize();
                Vector3 subst = cross.Normalize();
                vw.ReplaceFaceNormal(face, (float)subst.X, (float)subst.Y, (float)subst.Z);

                //double ang = Math.Acos(Vector3.Dot(orig, subst));
                //mAppRef.DebugLog("Face " + face.ToString("D2") + ": " + subst +
                //    " vs. orig " + orig +
                //    " (off by " + (ang * 180.0 / Math.PI).ToString("N2") + " deg)");
            }
        }