Пример #1
0
        public void Dispose()
        {
            if (ObjWriter == null)
            {
                return;
            }

            DoorWriter.Flush();
            DoorWriter.Dispose();
            GeomSetWriter.Flush();
            GeomSetWriter.Dispose();
            ObjWriter.Save();
            if (ObjWriter.Empty)
            {
                File.Delete(ObjWriter.File);
            }
            ObjWriter = null;
        }
Пример #2
0
        public Zone2Obj(Zone2 zone)
        {
            Zone = zone;
            if (!Directory.Exists("zones"))
            {
                Directory.CreateDirectory("zones");
            }
            string filename = Path.Combine("zones", string.Format("zone{0:D3}", zone.ID));

            DoorWriter    = new DoorWriter(filename + ".doors");
            GeomSetWriter = new GeomSetWriter(filename + ".geomset");
            ObjWriter     = new WavefrontObjFile(filename + ".obj")
            {
                Scale = MESH_SCALE
            };
            GeomSetWriter.WriteLoadMesh(filename + ".obj");
            FirstPass = !NavmeshMgr.IsPathingEnabled(zone);
        }
Пример #3
0
        private void ExtractDoor(NiFile model, Matrix4 worldMatrix, int fixtureid)
        {
            // take everything that is under a doorX node and use it for the hull...
            if (model == null)
            {
                return;
            }

            var doorVertices = new Dictionary <string, List <Vector3> >();

            // find all trimeshs and tristrips
            foreach (var obj in model.ObjectsByRef.Values)
            {
                var avNode = obj as NiAVObject;
                if (avNode == null)
                {
                    continue;
                }

                if (!IsMatched(avNode, new[] { "visible", "collidee", "collide" }))
                {
                    continue;
                }

                var doorName = FindMatchRegex(avNode, new[] { DoorRegex });

                if (doorName == string.Empty)
                {
                    continue;
                }

                Vector3[]  vertices  = null;
                Triangle[] triangles = null;

                TryExtractTriShape(obj, worldMatrix, false, false, ref vertices, ref triangles);

                if (vertices == null)
                {
                    TryExtractTriStrips(obj, worldMatrix, false, false, ref vertices, ref triangles);
                }

                if (vertices == null)
                {
                    continue;
                }

                if (!doorVertices.ContainsKey(doorName))
                {
                    doorVertices.Add(doorName, new List <Vector3>());
                }
                doorVertices[doorName].AddRange(vertices);
            }


            foreach (var key in doorVertices.Keys)
            {
                float hullMinZ = float.MaxValue;
                float hullMaxZ = float.MinValue;

                var verts = doorVertices[key].ToArray();

                var pts = new List <PointF>();
                foreach (Vector3 vert in verts)
                {
                    hullMinZ = Math.Min(vert.Z, hullMinZ);
                    hullMaxZ = Math.Max(vert.Z, hullMaxZ);
                    pts.Add(new PointF(vert.X, vert.Y));
                }

                MCvBox2D box = PointCollection.MinAreaRect(pts.ToArray());

                float maxSize = box.size.Width;
                maxSize = Math.Max(maxSize, box.size.Height);
                maxSize = Math.Max(maxSize, hullMaxZ - hullMinZ);

                // There are some weird door ids in e.g. Jordheim (z120): "door01:0" e.g. -- how do they translate to IDs?
                var doorID  = Regex.Match(key.Replace(":", ""), "([0-9]+)").Groups[1].Value;
                var heading = ((box.angle + (box.size.Width < box.size.Height ? 0.0 : 90.0 + 90.0)) * DEGREES_TO_HEADING) % 0x1000;
                if (heading < 0)
                {
                    heading += 0x1000;
                }
                DoorWriter.WriteDoor(Zone.ID * 1000000 + fixtureid * 100 + int.Parse(doorID), model.FileName, (int)box.center.X, (int)box.center.Y, (int)hullMinZ, (int)heading, (int)maxSize);


                // Make sure we have a min of 20f for doors on width/height
                box.size.Width  = Math.Max(20f, box.size.Width);
                box.size.Height = Math.Max(20f, box.size.Height);

                // Make sure the door touches the ground...
                hullMinZ -= 16.0f;

                var boxVertices = box.GetVertices();
                GeomSetWriter.WriteConvexVolume(boxVertices.Length, hullMinZ, hullMaxZ, CEM.GeomSetWriter.eAreas.Door);

                foreach (var vert in boxVertices)
                {
                    GeomSetWriter.WriteConvexVolumeVertex(new Vector3(vert.X, vert.Y, hullMinZ)); // debug
                }
            }
        }
Пример #4
0
        private void ExtractLadder(NiFile model, Matrix4 worldMatrix)
        {
            // take everything that is under a climbX node and use it for the hull...
            if (model == null)
            {
                return;
            }

            var climbVertices = new Dictionary <string /* climbXXX */, List <Vector3> >();

            // Find all trimeshs and tristrips that belong to climb nodes
            foreach (var obj in model.ObjectsByRef.Values)
            {
                var avNode = obj as NiAVObject;
                if (avNode == null)
                {
                    continue;
                }

                var climbName = FindMatchRegex(avNode, new[] { LadderRegex });
                if (climbName == string.Empty)
                {
                    // No ladder in node
                    continue;
                }

                Vector3[]  vertices  = null;
                Triangle[] triangles = null;

                TryExtractTriShape(obj, worldMatrix, false, false, ref vertices, ref triangles);
                if (vertices == null)
                {
                    TryExtractTriStrips(obj, worldMatrix, false, false, ref vertices, ref triangles);
                }

                if (vertices == null)
                {
                    continue;
                }

                if (!climbVertices.ContainsKey(climbName))
                {
                    climbVertices.Add(climbName, new List <Vector3>());
                }
                climbVertices[climbName].AddRange(vertices);
            }

            // Compute each Ladder individually
            foreach (var climbNode in climbVertices.Keys)
            {
                var minZ = float.MaxValue;
                var maxZ = float.MinValue;

                var verts = climbVertices[climbNode];

                // Find min/max
                foreach (var vert in verts)
                {
                    minZ = Math.Min(vert.Z, minZ);
                    maxZ = Math.Max(vert.Z, maxZ);
                }

                // Divide points into two sets
                var minVecs = new List <Vector3>();
                var maxVecs = new List <Vector3>();

                foreach (var vert in verts)
                {
                    if (vert.Z < minZ + (maxZ - minZ) / 2)
                    {
                        minVecs.Add(vert);
                    }
                    else
                    {
                        maxVecs.Add(vert);
                    }
                }

                if (minVecs.Count == 0 || maxVecs.Count == 0)
                {
                    throw new InvalidDataException("ladder seems invalid");
                }

                var minExt = new Vector3(128, 128, 128);
                var maxExt = new Vector3(128, 128, 128);

                var minPt = GetClosestNavmeshPoint(Average(minVecs), minExt.X, minExt.Y, minExt.Z);
                var maxPt = GetClosestNavmeshPoint(Average(maxVecs), maxExt.X, maxExt.Y, maxExt.Z);

                if (minPt == Vector3.Zero || maxPt == Vector3.Zero)
                {
                    Log.Error("Could not fit ladder {0} at {2} {3} {4} to navmesh in {1}; ignoring", climbNode, Zone.Name, minVecs[0].X,
                              minVecs[0].Y, minVecs[0].Z);
                    return;
                }

                // Write the off-mesh connection from min to max that is the primary ladder. This connection has to be connected the navmesh.
                Log.Debug("Extracted Ladder: {0} with verts={1}", climbNode, verts.Count);

                // Have some visual markers that show us how well we can fit ladders to the navmesh
                if (FirstPass)
                {
                    foreach (var endPoint in new[] { new[] { minPt, minExt }, new[] { maxPt, maxExt } })
                    {
                        var pt   = endPoint[0];
                        var ext  = endPoint[1];
                        var area = (pt == minPt) ? GeomSetWriter.eAreas.Road : GeomSetWriter.eAreas.Grass;
                        GeomSetWriter.WriteConvexVolume(4, pt.Z - ext.Z, pt.Z + ext.Z, area);
                        GeomSetWriter.WriteConvexVolumeVertex(new Vector3(pt.X - ext.X, pt.Y - ext.Y, pt.Z - ext.Z));
                        GeomSetWriter.WriteConvexVolumeVertex(new Vector3(pt.X + ext.X, pt.Y - ext.Y, pt.Z - ext.Z));
                        GeomSetWriter.WriteConvexVolumeVertex(new Vector3(pt.X + ext.X, pt.Y + ext.Y, pt.Z - ext.Z));
                        GeomSetWriter.WriteConvexVolumeVertex(new Vector3(pt.X - ext.X, pt.Y + ext.Y, pt.Z - ext.Z));
                    }
                }
                else
                {
                    GeomSetWriter.WriteOffMeshConnection(minPt, maxPt, true, GeomSetWriter.eAreas.Jump, GeomSetWriter.eFlags.Jump);
                }
            }
        }
Пример #5
0
        private void ExportHeightmap()
        {
            int[,] heightmap = LoadHeightmapData();

            #region rivers
            // Export rivers
            List <List <Vector3> > riverPoints = Zone.GetRiverPoints();
            int   numWater     = riverPoints.Count;
            int[] waterHeights = Zone.GetWaterHeights();
            for (int i = 0; i < numWater; i++)
            {
                int points = riverPoints[i].Count / 2;
                int index  = 0;
                while (index < points)
                {
                    int toWrite = Math.Min(points - index, 2);
                    GeomSetWriter.WriteConvexVolume(toWrite * 2, 0, waterHeights[i], CEM.GeomSetWriter.eAreas.Water);

                    for (int j = 0; j < toWrite; j++)
                    {
                        float x = riverPoints[i][(index + j) * 2].X;
                        float y = riverPoints[i][(index + j) * 2].Y;
                        float z = waterHeights[i];
                        GeomSetWriter.WriteConvexVolumeVertex(new Vector3(x, y, z));
                    }

                    for (int j = toWrite - 1; j >= 0; j--)
                    {
                        float x = riverPoints[i][(index + j) * 2 + 1].X;
                        float y = riverPoints[i][(index + j) * 2 + 1].Y;
                        float z = waterHeights[i];

                        GeomSetWriter.WriteConvexVolumeVertex(new Vector3(x, y, z));
                    }

                    if (points - index > toWrite)
                    {
                        index += toWrite - 1;
                    }
                    else
                    {
                        index += toWrite;
                    }
                }
            }
            #endregion

            // Export Heightmap (but pay attention to water map)
            var water = Zone.LoadWaterMap();
            for (int sx = 0; sx < 8; sx++)
            {
                for (int sy = 0; sy < 8; sy++)
                {
                    Matrix4 myWorldMatrix = Matrix4.CreateTranslation(Zone.OffsetVector);
                    myWorldMatrix *= Matrix4.CreateTranslation(8192 * (sx), 8192 * (sy), 0);
                    const int xVectors = 33;
                    const int yVectors = 33;

                    var myVerticesFakeWater = new List <Vector3>(); // with water.Z
                    var myTriangles         = new List <Triangle>();

                    var myVerticesReal = new List <Vector3>(); // no water.Z

                    for (int y = 0; y < yVectors; y++)
                    {
                        for (int x = 0; x < xVectors; x++)
                        {
                            int z      = 0;
                            var waterZ = -1;
                            if (sx == 7 && x == (xVectors - 1))
                            {
                                if (sy == 7 && y == (yVectors - 1))
                                {
                                    z      = heightmap[sx * 32 + (x - 1), sy * 32 + (y - 1)];
                                    waterZ = water[sx * 32 + (x - 1), sy * 32 + (y - 1)];
                                }
                                else
                                {
                                    z      = heightmap[sx * 32 + (x - 1), sy * 32 + y];
                                    waterZ = water[sx * 32 + (x - 1), sy * 32 + y];
                                }
                            }
                            else if (sy == 7 && y == (yVectors - 1))
                            {
                                z      = heightmap[sx * 32 + x, sy * 32 + (y - 1)];
                                waterZ = water[sx * 32 + x, sy * 32 + (y - 1)];
                            }
                            else
                            {
                                z      = heightmap[sx * 32 + x, sy * 32 + y];
                                waterZ = water[sx * 32 + x, sy * 32 + y];
                            }
                            Vector3 vector = Vector3.Transform(new Vector3(x * 256, y * 256, z), myWorldMatrix);
                            myVerticesReal.Add(vector);

                            if (waterZ != 255 && waterZ < waterHeights.Length && waterHeights[waterZ] > vector.Z)
                            {
                                vector.Z = waterHeights[waterZ];
                            }
                            myVerticesFakeWater.Add(new Vector3(vector.X, vector.Y, vector.Z));

                            if (y == yVectors - 1 || x == xVectors - 1)
                            {
                                continue;
                            }

                            myTriangles.Add(new Triangle((ushort)(x + ((y + 1) * xVectors)), (ushort)(x + 1 + (y * xVectors)),
                                                         (ushort)(x + (y * xVectors))));
                            myTriangles.Add(new Triangle((ushort)(x + ((y + 1) * xVectors)), (ushort)(x + 1 + ((y + 1) * xVectors)),
                                                         (ushort)(x + 1 + (y * xVectors))));
                        }
                    }

                    //ObjWriter.AddMesh(myVerticesReal.ToArray(), myTriangles.ToArray());
                    ObjWriter.AddMesh(myVerticesFakeWater.ToArray(), myTriangles.ToArray());
                }
            }
        }