private ABModel3D ConvertMesh(ThreeDSMesh mesh, ABMaterial[] materials)
        {
            // convert vertices
            ABModel3D model = new ABModel3D();

            model.Geometry = new ABGeometry3D();
            if (mesh.verticies != null && mesh.verticies.Length > 0)
            {
                int numVerts = mesh.verticies.Length;
                model.Geometry.Vertices = new Vector3[numVerts];
                model.Geometry.Normals  = new Vector3[numVerts];
                for (int vert = 0; vert < numVerts; vert++)
                {
                    model.Geometry.Vertices[vert] = new Vector3(mesh.verticies[vert].x,
                                                                mesh.verticies[vert].y,
                                                                mesh.verticies[vert].z);
                    model.Geometry.Normals[vert] = new Vector3(mesh.verticies[vert].nx,
                                                               mesh.verticies[vert].ny,
                                                               mesh.verticies[vert].nz);
                }
            }

            // uv map
            if (mesh.uvMap != null)
            {
                int numCoords = mesh.uvMap.Length;
                model.Geometry.TexCoords = new Vector2[numCoords];
                for (int coord = 0; coord < numCoords; coord++)
                {
                    model.Geometry.TexCoords[coord] = new Vector2(mesh.uvMap[coord].u,
                                                                  -mesh.uvMap[coord].v);
                }
            }
            model.Geometry.PrimType = Microsoft.DirectX.Direct3D.PrimitiveType.TriangleList;
            // indices
            if (mesh.groups != null)
            {
                model.Geometry.PrimIndices = new int[mesh.GetNumFaces() * 3];
                int idx = 0;
                foreach (ThreeDSMesh.FaceGroup group in mesh.groups)
                {
                    foreach (ThreeDSMesh.Face face in group.faces)
                    {
                        model.Geometry.PrimIndices[idx++] = face.p1;
                        model.Geometry.PrimIndices[idx++] = face.p2;
                        model.Geometry.PrimIndices[idx++] = face.p3;
                    }
                    if (group.mappings != null && group.mappings.Count > 0)
                    {
                        int numMatIndices = 0;
                        foreach (ThreeDSMesh.MaterialMapping mapping in group.mappings)
                        {
                            if (mapping.mappedFaces != null && mapping.mappedFaces.Length > 0)
                            {
                                numMatIndices++;
                            }
                        }
                        model.MaterialIndices = new ABMaterialIndex[numMatIndices];
                        int miIdx = 0;
                        foreach (ThreeDSMesh.MaterialMapping mapping in group.mappings)
                        {
                            if (mapping.mappedFaces != null && mapping.mappedFaces.Length > 0)
                            {
                                ABMaterialIndex matIndex = model.MaterialIndices[miIdx++] = new ABMaterialIndex();
                                matIndex.Indices = new int[mapping.mappedFaces.Length];
                                foreach (ABMaterial material in materials)
                                {
                                    if (material.Name == mapping.name)
                                    {
                                        matIndex.Material = material;
                                    }
                                }
                                for (int face = 0; face < mapping.mappedFaces.Length; face++)
                                {
                                    matIndex.Indices[face] = mapping.mappedFaces[face];
                                }
                            }
                        }
                    }
                }
            }

            return(model);
        }
        public ABModel3D[] ToAvalonBridgeModel()
        {
            ABModel3D[] models = new ABModel3D[2];
            models[0] = new ABModel3D();

            // build geometry
            double xi = startPoint.X, yi, minZ = double.PositiveInfinity, maxZ = double.NegativeInfinity;

            int numPointsX = (int)((endPoint.X - startPoint.X) / density + 1);
            int numPointsY = (int)((endPoint.Y - startPoint.Y) / density + 1);

            ABGeometry3D geometry = models[0].Geometry = new ABGeometry3D();

            geometry.PrimType = PrimitiveType.TriangleList;
            int numVerts = numPointsX * numPointsY;

            int vIdx = 0;

            Vector3[] points = new Vector3[numVerts];
            for (int x = 0; x < numPointsX; x++)
            {
                yi = startPoint.Y;
                for (int y = 0; y < numPointsY; y++)
                {
                    double zz = function(xi, yi);
                    points[vIdx++] = new Vector3((float)xi, (float)zz, (float)yi);

                    yi += density;
                    if (minZ > zz)
                    {
                        minZ = zz;
                    }
                    if (maxZ < zz)
                    {
                        maxZ = zz;
                    }
                }
                xi += density;
            }
            //e1 = verts[vIdx-2].Position - verts[vIdx-3].Position;
            //e2 = verts[vIdx-1].Position - verts[vIdx-3].Position;
            //faceNormal = Vector3::Normalize(Vector3::Cross(e1, e2));

            // tri indices
            int numTris = (numPointsX - 1) * (numPointsY - 1) * 2;

            geometry.Vertices   = new Vector3[numTris * 3];
            geometry.VertexClrs = new int[geometry.Vertices.Length];
            int tIdx = 0;

            vIdx = 0;
            float  z1, z2;
            double cc       = (maxZ - minZ) / (colorSchema.Length - 1.0);
            int    cacheIdx = 0;

            clrSchemeIcache = new int[numTris];
            for (int x = 0; x < numPointsX - 1; x++)
            {
                for (int y = 0; y < numPointsY - 1; y++)
                {
                    z1 = points[tIdx].Y;
                    z2 = points[tIdx + 1].Y;
                    int clrIdx = clrSchemeIcache[cacheIdx++] = (int)(((z1 + z2) / 2.0 - minZ) / cc);
                    int triClr = colorSchema[clrIdx].ToArgb();

                    //Vector3 e1 = points[tIdx + 1] - points[tIdx];
                    //Vector3 e2 = points[tIdx + 1 + numPointsX] - points[tIdx];
                    //Vector3 faceNormal = Vector3.Normalize(Vector3.Cross(e1, e2));

                    //geometry.Normals[vIdx] = faceNormal;
                    geometry.VertexClrs[vIdx] = triClr;
                    geometry.Vertices[vIdx++] = points[tIdx];
                    //geometry.Normals[vIdx] = faceNormal;
                    geometry.VertexClrs[vIdx] = triClr;
                    geometry.Vertices[vIdx++] = points[tIdx + 1];
                    //geometry.Normals[vIdx] = faceNormal;
                    geometry.VertexClrs[vIdx] = triClr;
                    geometry.Vertices[vIdx++] = points[tIdx + 1 + numPointsY];

                    //z1 = points[tIdx].Y;
                    //z2 = points[tIdx + 1 + numPointsX].Y;
                    //triClr = colorSchema[(int)(((z1 + z2) / 2.0 - minZ) / cc)].ToArgb();

                    //e1 = points[tIdx + 1 + numPointsX] - points[tIdx];
                    //e2 = points[tIdx + numPointsX] - points[tIdx];
                    //faceNormal = Vector3.Normalize(Vector3.Cross(e1, e2));

                    //geometry.Normals[vIdx] = faceNormal;
                    geometry.VertexClrs[vIdx] = triClr;
                    geometry.Vertices[vIdx++] = points[tIdx];
                    //geometry.Normals[vIdx] = faceNormal;
                    geometry.VertexClrs[vIdx] = triClr;
                    geometry.Vertices[vIdx++] = points[tIdx + 1 + numPointsY];
                    //geometry.Normals[vIdx] = faceNormal;
                    geometry.VertexClrs[vIdx] = triClr;
                    geometry.Vertices[vIdx++] = points[tIdx + numPointsY];

                    tIdx++;
                }
                tIdx++;
            }

            // now outlines
            models[1]         = new ABModel3D();
            geometry          = models[1].Geometry = new ABGeometry3D();
            geometry.PrimType = PrimitiveType.LineStrip;
            geometry.Vertices = new Vector3[numVerts * 2];
            geometry.Clr      = Color.Black.ToArgb();

            // TODO: Use tri strips??
            vIdx = 0;
            int pos = 0;

            // do x strips
            for (int y = 0; y < numPointsY; y++)
            {
                for (int x = 0; x < numPointsX; x++)
                {
                    geometry.Vertices[vIdx] = points[pos];
                    pos += numPointsY;
                    vIdx++;
                }
                y++;
                if (y < numPointsY)
                {
                    pos -= numPointsY;
                    pos++;
                    for (int x = 0; x < numPointsX; x++)
                    {
                        geometry.Vertices[vIdx] = points[pos];
                        pos -= numPointsY;
                        vIdx++;
                    }
                    pos = y + 1;
                }
            }
            // do y strips
            pos = 0;
            for (int x = numPointsX - 1; x >= 0; x--)
            {
                pos = ((x + 1) * numPointsY) - 1;
                for (int y = 0; y < numPointsY; y++)
                {
                    geometry.Vertices[vIdx] = points[pos--];
                    vIdx++;
                }
                x--;
                if (x >= 0)
                {
                    pos -= numPointsY - 1;
                    for (int y = 0; y < numPointsY; y++)
                    {
                        //Vector3 p = points[pos++];
                        geometry.Vertices[vIdx++] = points[pos++];
                    }
                }
            }

            return(models);
        }
        public ABScene3D LoadScene(string file)
        {
            uint     failId;
            int      failPos;
            lwObject lwobj = lwObject.GetObject5(file, out failId, out failPos);

            if (lwobj != null)
            {
                // convert to AB
                ABScene3D scene = new ABScene3D();

                ABMaterial[] materials   = null;
                int[]        clipIndices = null;
                if (lwobj.surf != null && lwobj.surf.Count > 0)
                {
                    materials   = new ABMaterial[lwobj.surf.Count];
                    clipIndices = new int[lwobj.surf.Count];
                    LinkedList <lwSurface> .Enumerator matIter = lwobj.surf.GetEnumerator();
                    int matIdx = 0;
                    while (matIter.MoveNext())
                    {
                        lwSurface  surface = matIter.Current;
                        ABMaterial mat     = materials[matIdx] = new ABMaterial();

                        mat.Name      = surface.name;
                        mat.Ambient   = new ABColorARGB();
                        mat.Ambient.A = 0xFF;
                        mat.Ambient.R = (byte)(surface.color.rgb[0] / 255f);
                        mat.Ambient.G = (byte)(surface.color.rgb[1] / 255f);
                        mat.Ambient.B = (byte)(surface.color.rgb[2] / 255f);
                        mat.Diffuse   = new ABColorARGB();
                        mat.Diffuse.A = 0xFF;
                        mat.Diffuse.R = (byte)((surface.diffuse.val * surface.color.rgb[0]) / 255f);
                        mat.Diffuse.G = (byte)((surface.diffuse.val * surface.color.rgb[1]) / 255f);
                        mat.Diffuse.B = (byte)((surface.diffuse.val * surface.color.rgb[2]) / 255f);

                        if (surface.color.tex != null)
                        {
                            // resolve texture
                            //mat.TextureName
                            clipIndices[matIdx] = surface.color.tex.First.Value.imap.cindex;
                            mat.TextureName     = surface.color.tex.First.Value.imap.vmap_name;
                        }
                        else
                        {
                            clipIndices[matIdx] = -1;
                        }

                        matIdx++;
                    }
                }

                LinkedList <lwLayer> .Enumerator layIter = lwobj.layer.GetEnumerator();
                scene.Models = new ABModel3D[lwobj.layer.Count];
                int mdlIdx = 0;
                while (layIter.MoveNext())
                {
                    lwLayer   layer = layIter.Current;
                    ABModel3D model = scene.Models[mdlIdx] = new ABModel3D();

                    model.Geometry          = new ABGeometry3D();
                    model.Geometry.Vertices = new Vector3[layer.point.count];

                    // break up polygons by surface
                    Dictionary <lwSurface, int> surfGroupCounts = new Dictionary <lwSurface, int>();
                    for (int i = 0; i < layer.polygon.pol.Length; i++)
                    {
                        lwPolygon polygon = layer.polygon.pol[i];
                        if (surfGroupCounts.ContainsKey(polygon.surf))
                        {
                            surfGroupCounts[polygon.surf]++;
                        }
                        else
                        {
                            surfGroupCounts[polygon.surf] = 1;
                        }
                    }
                    int[] groupIndices = new int[surfGroupCounts.Count];
                    model.MaterialIndices = new ABMaterialIndex[surfGroupCounts.Count];
                    for (int i = 0; i < layer.polygon.pol.Length; i++)
                    {
                        lwPolygon polygon = layer.polygon.pol[i];
                        if (surfGroupCounts.ContainsKey(polygon.surf))
                        {
                            surfGroupCounts[polygon.surf]++;
                        }
                        else
                        {
                            surfGroupCounts[polygon.surf] = 1;
                        }
                    }
                }

                // match up clips to materials
            }
            return(null);
        }