/// <summary> /// Create a DGRPMesh from a .OBJ file. /// </summary> public DGRP3DMesh(DGRP dgrp, OBJ source, GraphicsDevice gd) { Bounds = source.Vertices.Count > 0?BoundingBox.CreateFromPoints(source.Vertices):new BoundingBox(); Geoms = new List <Dictionary <Texture2D, DGRP3DGeometry> >(); if (dgrp == null) { return; } Name = dgrp.ChunkParent.Filename.Replace('.', '_').Replace("spf", "iff") + "_" + dgrp.ChunkID; foreach (var obj in source.FacesByObjgroup.OrderBy(x => x.Key)) { if (obj.Key == "_default") { continue; } var split = obj.Key.Split('_'); //0: dynsprite id, 1: SPR or custom, 2: rotation, 3: index var id = int.Parse(split[0]); while (Geoms.Count <= id) { Geoms.Add(new Dictionary <Texture2D, DGRP3DGeometry>()); } var dict = Geoms[id]; var geom = new DGRP3DGeometry(split, source, obj.Value, dgrp, gd); dict[geom.Pixel] = geom; } }
public DGRP3DMesh(DGRP dgrp, Stream source, GraphicsDevice gd) { using (var cstream = new GZipStream(source, CompressionMode.Decompress)) { using (var io = IoBuffer.FromStream(cstream, ByteOrder.LITTLE_ENDIAN)) { var fsom = io.ReadCString(4); Version = io.ReadInt32(); ReconstructVersion = io.ReadInt32(); Name = io.ReadPascalString(); var geomCount = io.ReadInt32(); Geoms = new List <Dictionary <Texture2D, DGRP3DGeometry> >(); for (int i = 0; i < geomCount; i++) { var d = new Dictionary <Texture2D, DGRP3DGeometry>(); var subCount = io.ReadInt32(); for (int j = 0; j < subCount; j++) { var geom = new DGRP3DGeometry(io, dgrp, gd); d.Add(geom.Pixel, geom); } Geoms.Add(d); } var x = io.ReadFloat(); var y = io.ReadFloat(); var z = io.ReadFloat(); var x2 = io.ReadFloat(); var y2 = io.ReadFloat(); var z2 = io.ReadFloat(); Bounds = new BoundingBox(new Vector3(x, y, z), new Vector3(x2, y2, z2)); } } }
/// <summary> /// Create a DGRPMesh from a .OBJ file. /// </summary> public DGRP3DMesh(DGRP dgrp, OBJ source, GraphicsDevice gd) { Bounds = source.Vertices.Count > 0?BoundingBox.CreateFromPoints(source.Vertices):new BoundingBox(); Geoms = new List <Dictionary <Texture2D, DGRP3DGeometry> >(); if (dgrp == null) { return; } Name = dgrp.ChunkParent.Filename.Replace('.', '_').Replace("spf", "iff") + "_" + dgrp.ChunkID; foreach (var obj in source.FacesByObjgroup.OrderBy(x => x.Key)) { if (obj.Key == "_default") { continue; } var split = obj.Key.Split('_'); if (split[0] == "DEPTH") { DepthMask = new DGRP3DGeometry(split, source, obj.Value, dgrp, gd); if (split.Length > 2 && split[2] == "PORTAL") { MaskType = DGRP3DMaskType.Portal; var verts = new List <Vector3>(); var objs = source.FacesByObjgroup.Where(x => !x.Key.StartsWith("DEPTH_MASK_PORTAL")).Select(x => x.Value); foreach (var obj2 in objs) { foreach (var tri in obj2) { verts.Add(source.Vertices[tri[0] - 1]); } } Bounds = BoundingBox.CreateFromPoints(verts); } else { MaskType = DGRP3DMaskType.Normal; } } else { //0: dynsprite id, 1: SPR or custom, 2: rotation, 3: index var id = int.Parse(split[0]); while (Geoms.Count <= id) { Geoms.Add(new Dictionary <Texture2D, DGRP3DGeometry>()); } var dict = Geoms[id]; var geom = new DGRP3DGeometry(split, source, obj.Value, dgrp, gd); dict[geom.Pixel] = geom; } } }
public DGRP3DMesh(DGRP dgrp, Stream source, GraphicsDevice gd) { using (var cstream = new GZipStream(source, CompressionMode.Decompress)) { using (var io = IoBuffer.FromStream(cstream, ByteOrder.LITTLE_ENDIAN)) { var fsom = io.ReadCString(4); Version = io.ReadInt32(); ReconstructVersion = io.ReadInt32(); if (ReconstructVersion != 0 && ReconstructVersion < CURRENT_RECONSTRUCT) { throw new Exception("Reconstruction outdated, must be rerun!"); } Name = io.ReadPascalString(); var geomCount = io.ReadInt32(); Geoms = new List <Dictionary <Texture2D, DGRP3DGeometry> >(); for (int i = 0; i < geomCount; i++) { var d = new Dictionary <Texture2D, DGRP3DGeometry>(); var subCount = io.ReadInt32(); for (int j = 0; j < subCount; j++) { var geom = new DGRP3DGeometry(io, dgrp, gd, Version); if (geom.Pixel == null && geom.PrimCount > 0) { throw new Exception("Invalid Mesh! (old format)"); } d.Add(geom.Pixel, geom); } Geoms.Add(d); } if (Version > 2) { MaskType = (DGRP3DMaskType)io.ReadInt32(); if (MaskType > DGRP3DMaskType.None) { DepthMask = new DGRP3DGeometry(io, dgrp, gd, Version); } } var x = io.ReadFloat(); var y = io.ReadFloat(); var z = io.ReadFloat(); var x2 = io.ReadFloat(); var y2 = io.ReadFloat(); var z2 = io.ReadFloat(); Bounds = new BoundingBox(new Vector3(x, y, z), new Vector3(x2, y2, z2)); } } }
public DGRP3DMesh(DGRP dgrp, OBJD obj, GraphicsDevice gd, string saveDirectory) { ReconstructVersion = CURRENT_RECONSTRUCT; SaveDirectory = saveDirectory; Geoms = new List <Dictionary <Texture2D, DGRP3DGeometry> >(); if (dgrp == null) { return; } Name = obj.ChunkParent.Filename.Replace('.', '_') + "_" + dgrp.ChunkID; var lower = obj.ChunkParent.Filename.ToLowerInvariant(); var config = obj.ChunkParent.List <FSOR>()?.FirstOrDefault()?.Params; if (config == null) { if (!ParamsByIff.TryGetValue(lower, out config)) { config = DefaultParams; } } if (!config.InRange(dgrp.ChunkID)) { config = DefaultParams; } int totalSpr = 0; for (uint rotation = 0; rotation < 4; rotation++) { if (config.DoorFix) { if ((obj.SubIndex & 0xFF) == 1) { if ((rotation + 1) % 4 > 1) { continue; } } else { if ((rotation + 1) % 4 < 2) { continue; } } } else if (!config.Rotations[rotation]) { continue; } var img = dgrp.GetImage(1, 3, rotation); var zOff = (config.BlenderTweak) ? -57.5f : -55f; var mat = Matrix.CreateTranslation(new Vector3(-72, -344, zOff)); mat *= Matrix.CreateScale((1f / (128)) * 1.43f);//1.4142135623730f); mat *= Matrix.CreateScale(1, -1, 1); mat *= Matrix.CreateRotationX((float)Math.PI / -6); mat *= Matrix.CreateRotationY(((float)Math.PI / 4) * (1 + rotation * 2)); var factor = (config.BlenderTweak) ? 0.40f : 0.39f; int curSpr = 0; foreach (var sprite in img.Sprites) { var sprMat = mat * Matrix.CreateTranslation(new Vector3(sprite.ObjectOffset.X, sprite.ObjectOffset.Z, sprite.ObjectOffset.Y) * new Vector3(1f / 16f, 1f / 5f, 1f / 16f)); var inv = Matrix.Invert(sprMat); var tex = sprite.GetTexture(gd); if (tex == null) { curSpr++; continue; } var isDynamic = sprite.SpriteID >= obj.DynamicSpriteBaseId && sprite.SpriteID < (obj.DynamicSpriteBaseId + obj.NumDynamicSprites); var dynid = (isDynamic) ? (int)(1 + sprite.SpriteID - obj.DynamicSpriteBaseId) : 0; while (Geoms.Count <= dynid) { Geoms.Add(new Dictionary <Texture2D, DGRP3DGeometry>()); } DGRP3DGeometry geom = null; if (!Geoms[dynid].TryGetValue(tex, out geom)) { geom = new DGRP3DGeometry() { Pixel = tex }; Geoms[dynid][geom.Pixel] = geom; } geom.PixelDir = (ushort)rotation; geom.PixelSPR = (ushort)(curSpr++); totalSpr++; var depthB = sprite.GetDepth(); var useDequantize = false; float[] depth = null; int iterations = 125; int triDivisor = 100; float aggressiveness = 3.5f; if (useDequantize) { var dtex = new Texture2D(gd, ((TextureInfo)tex.Tag).Size.X, ((TextureInfo)tex.Tag).Size.Y, false, SurfaceFormat.Color); dtex.SetData(depthB.Select(x => new Color(x, x, x, x)).ToArray()); depth = DepthTreatment.DequantizeDepth(gd, dtex); dtex.Dispose(); iterations = 500; aggressiveness = 2.5f; MaxAllowedSq = 0.05f * 0.05f; } else if (depthB != null) { depth = depthB.Select(x => x / 255f).ToArray(); iterations = 125; aggressiveness = 3.5f; } if (depth == null) { continue; } QueueWork(() => { var boundPts = new List <Vector3>(); //begin async part var w = ((TextureInfo)tex.Tag).Size.X; var h = ((TextureInfo)tex.Tag).Size.Y; var pos = sprite.SpriteOffset + new Vector2(72, 348 - h); var tl = Vector3.Transform(new Vector3(pos, 0), sprMat); var tr = Vector3.Transform(new Vector3(pos + new Vector2(w, 0), 0), sprMat); var bl = Vector3.Transform(new Vector3(pos + new Vector2(0, h), 0), sprMat); var tlFront = Vector3.Transform(new Vector3(pos, 110.851251f), sprMat); var xInc = (tr - tl) / w; var yInc = (bl - tl) / h; var dFactor = (tlFront - tl) / (factor); if (sprite.Flip) { tl = tr; xInc *= -1; } var dict = new Dictionary <int, int>(); var verts = new List <VertexPositionTexture>(); var indices = new List <int>(); var lastPt = new Vector3(); var i = 0; var verti = 0; for (int y = 0; y < h; y++) { if (y > 0) { boundPts.Add(lastPt); } bool first = true; var vpos = tl; for (int x = 0; x < w; x++) { var d = depth[i++]; if (d < 0.999f) { lastPt = vpos + (1f - d) * dFactor; if (first) { boundPts.Add(lastPt); first = false; } var vert = new VertexPositionTexture(lastPt, new Vector2((float)x / w, (float)y / h)); verts.Add(vert); dict.Add(y * w + x, verti++); } vpos += xInc; } tl += yInc; } for (int y = 0; y < h - 1; y++) { for (int x = 0; x < w - 1; x++) { //try make a triangle or two var quad = new int?[] { QuickTryGet(dict, x + y * w), QuickTryGet(dict, x + 1 + y * w), QuickTryGet(dict, x + 1 + (y + 1) * w), QuickTryGet(dict, x + (y + 1) * w) }; var total = quad.Sum(v => (v == null) ? 0 : 1); if (total == 4) { var d1 = Vector3.DistanceSquared(verts[quad[0].Value].Position, verts[quad[2].Value].Position); var d2 = Vector3.DistanceSquared(verts[quad[1].Value].Position, verts[quad[3].Value].Position); if (d1 > MaxAllowedSq || d2 > MaxAllowedSq) { continue; } indices.Add(quad[0].Value); indices.Add(quad[1].Value); indices.Add(quad[2].Value); indices.Add(quad[0].Value); indices.Add(quad[2].Value); indices.Add(quad[3].Value); } else if (total == 3) { //clockwise anyways. we can only make one int?last = null; int?first = null; bool exit = false; foreach (var v in quad) { if (v != null) { if (last != null && Vector3.DistanceSquared(verts[last.Value].Position, verts[v.Value].Position) > MaxAllowedSq) { exit = true; break; } last = v.Value; if (first == null) { first = last; } } } if (!exit && Vector3.DistanceSquared(verts[last.Value].Position, verts[first.Value].Position) > MaxAllowedSq) { exit = true; } if (exit) { continue; } foreach (var v in quad) { if (v != null) { indices.Add(v.Value); } } } } } if (config.CounterFix) { //x axis extrapolation //clip: -0.4 to 0.4 //identify vertices very close to clipping range(border) //! for each vertex outwith clipping range //- idendify closest border pixel bp in image space //- result.zy = bp.zy //- result.x = (resultIMAGE.x - bpIMAGE.x) / 64; //- clip x to -0.5, 0.5f. var clip = 0.4; var bWidth = 0.02; var border1 = new List <Tuple <Vector2, Vector3> >(); var invalid1 = new List <KeyValuePair <int, int> >(); var border2 = new List <Tuple <Vector2, Vector3> >(); var invalid2 = new List <KeyValuePair <int, int> >(); foreach (var vert in dict) { var vpos = verts[vert.Value].Position; var dist = Math.Abs(vpos.X); if (dist > clip) { if (vpos.X > 0) { invalid1.Add(vert); } else { invalid2.Add(vert); } } else if (dist > (clip - bWidth)) { if (vpos.X > 0) { border1.Add(new Tuple <Vector2, Vector3>(new Vector2(vert.Key % w, vert.Key / w), vpos)); } else { border2.Add(new Tuple <Vector2, Vector3>(new Vector2(vert.Key % w, vert.Key / w), vpos)); } } } var edge = 0.498f + 0.001f * (rotation % 2); if (border1.Count > 0) { foreach (var vert in invalid1) { var vstr = verts[vert.Value]; var pos2d = new Vector2(vert.Key % w, vert.Key / w); var vpos = vstr.Position; var closest = border1.OrderBy(x => Vector2.DistanceSquared(x.Item1, pos2d)).First(); vpos.X = closest.Item2.X + Vector2.Distance(closest.Item1, pos2d) / 71.55f; if (vpos.X > 0.5f) { vpos.X = edge; } else { vpos.Y = closest.Item2.Y; vpos.Z = closest.Item2.Z; } vstr.Position = vpos; verts[vert.Value] = vstr; } } if (border2.Count > 0) { foreach (var vert in invalid2) { var vstr = verts[vert.Value]; var pos2d = new Vector2(vert.Key % w, vert.Key / w); var vpos = vstr.Position; var closest = border2.OrderBy(x => Vector2.DistanceSquared(x.Item1, pos2d)).First(); vpos.X = closest.Item2.X - Vector2.Distance(closest.Item1, pos2d) / 71.55f; if (vpos.X < -0.5f) { vpos.X = -edge; } else { vpos.Y = closest.Item2.Y; vpos.Z = closest.Item2.Z; } vstr.Position = vpos; verts[vert.Value] = vstr; } } } lock (BoundPts) BoundPts.AddRange(boundPts); var useSimplification = config.Simplify; if (useSimplification) { var simple = new Simplify(); simple.vertices = verts.Select(x => new MSVertex() { p = x.Position, t = x.TextureCoordinate }).ToList(); for (int t = 0; t < indices.Count; t += 3) { simple.triangles.Add(new MSTriangle() { v = new int[] { indices[t], indices[t + 1], indices[t + 2] } }); } simple.simplify_mesh(simple.triangles.Count / triDivisor, agressiveness: aggressiveness, iterations: iterations); verts = simple.vertices.Select(x => { var iv = Vector3.Transform(x.p, inv); //DGRP3DVert return(new VertexPositionTexture(x.p, new Vector2( (sprite.Flip) ? (1 - ((iv.X - pos.X + 0.5f) / w)) : ((iv.X - pos.X + 0.5f) / w), (iv.Y - pos.Y + 0.5f) / h))); } ).ToList(); indices.Clear(); foreach (var t in simple.triangles) { indices.Add(t.v[0]); indices.Add(t.v[1]); indices.Add(t.v[2]); } GameThread.NextUpdate(x => { if (geom.SVerts == null) { geom.SVerts = new List <DGRP3DVert>(); geom.SIndices = new List <int>(); } var bID = geom.SVerts.Count; foreach (var id in indices) { geom.SIndices.Add(id + bID); } var verts2 = verts.Select(v => new DGRP3DVert(v.Position, Vector3.Zero, v.TextureCoordinate)).ToList(); DGRP3DVert.GenerateNormals(!sprite.Flip, verts2, indices); geom.SVerts.AddRange(verts2); lock (this) { if (++CompletedCount == TotalSprites) { Complete(gd); } } }); } else { GameThread.NextUpdate(x => { if (geom.SVerts == null) { geom.SVerts = new List <DGRP3DVert>(); geom.SIndices = new List <int>(); } var baseID = geom.SVerts.Count; foreach (var id in indices) { geom.SIndices.Add(id + baseID); } var verts2 = verts.Select(v => new DGRP3DVert(v.Position, Vector3.Zero, v.TextureCoordinate)).ToList(); DGRP3DVert.GenerateNormals(!sprite.Flip, verts2, indices); geom.SVerts.AddRange(verts2); lock (this) { if (++CompletedCount == TotalSprites) { Complete(gd); } } }); } }); } } TotalSprites = totalSpr; }