mirror of
https://github.com/simtactics/mysimulation.git
synced 2025-03-15 14:51:21 +00:00
316 lines
11 KiB
C#
316 lines
11 KiB
C#
|
using FSO.Files.Formats.IFF;
|
|||
|
using FSO.Files.Formats.IFF.Chunks;
|
|||
|
using FSO.Files.Utils;
|
|||
|
using Microsoft.Xna.Framework;
|
|||
|
using Microsoft.Xna.Framework.Graphics;
|
|||
|
using System;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.Globalization;
|
|||
|
using System.IO;
|
|||
|
using System.Linq;
|
|||
|
using System.Runtime.InteropServices;
|
|||
|
|
|||
|
namespace FSO.Files.RC
|
|||
|
{
|
|||
|
public class DGRP3DGeometry
|
|||
|
{
|
|||
|
public bool Rendered = false;
|
|||
|
public Texture2D Pixel;
|
|||
|
public ushort PixelSPR;
|
|||
|
public ushort PixelDir;
|
|||
|
|
|||
|
public ushort CustomTexture;
|
|||
|
public static Func<string, Texture2D> ReplTextureProvider;
|
|||
|
|
|||
|
public List<DGRP3DVert> SVerts; //simplified vertices
|
|||
|
public List<int> SIndices; //simplified indices
|
|||
|
|
|||
|
public VertexBuffer Verts;
|
|||
|
public IndexBuffer Indices;
|
|||
|
public int PrimCount;
|
|||
|
|
|||
|
public void SComplete(GraphicsDevice gd)
|
|||
|
{
|
|||
|
Rendered = true;
|
|||
|
Verts?.Dispose();
|
|||
|
Indices?.Dispose();
|
|||
|
|
|||
|
PrimCount = SIndices.Count / 3;
|
|||
|
if (PrimCount > 0)
|
|||
|
{
|
|||
|
Verts = new VertexBuffer(gd, typeof(DGRP3DVert), SVerts.Count, BufferUsage.None);
|
|||
|
Verts.SetData(SVerts.ToArray());
|
|||
|
Indices = new IndexBuffer(gd, IndexElementSize.ThirtyTwoBits, SIndices.Count, BufferUsage.None);
|
|||
|
Indices.SetData(SIndices.ToArray());
|
|||
|
}
|
|||
|
|
|||
|
if (!IffFile.RETAIN_CHUNK_DATA)
|
|||
|
{
|
|||
|
SVerts = null;
|
|||
|
SIndices = null;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public DGRP3DGeometry() { }
|
|||
|
public DGRP3DGeometry(IoBuffer io, DGRP source, GraphicsDevice gd, int Version)
|
|||
|
{
|
|||
|
PixelSPR = io.ReadUInt16();
|
|||
|
PixelDir = io.ReadUInt16();
|
|||
|
if (PixelDir == 65535)
|
|||
|
{
|
|||
|
CustomTexture = 1;
|
|||
|
if (source == null)
|
|||
|
{
|
|||
|
//temporary system for models without DGRP
|
|||
|
Pixel = ReplTextureProvider("FSO_TEX_" + PixelSPR + ".png");
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
var name = source.ChunkParent.Filename.Replace('.', '_').Replace("spf", "iff");
|
|||
|
name += "_TEX_" + PixelSPR + ".png";
|
|||
|
Pixel = ReplTextureProvider(name);
|
|||
|
if (Pixel == null)
|
|||
|
{
|
|||
|
Pixel = source.ChunkParent.Get<MTEX>(PixelSPR)?.GetTexture(gd);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Pixel = source.GetImage(1, 3, PixelDir).Sprites[PixelSPR].GetTexture(gd);
|
|||
|
}
|
|||
|
|
|||
|
var vertCount = io.ReadInt32();
|
|||
|
SVerts = new List<DGRP3DVert>();
|
|||
|
|
|||
|
if (Version > 1)
|
|||
|
{
|
|||
|
var bytes = io.ReadBytes(vertCount * Marshal.SizeOf(typeof(DGRP3DVert)));
|
|||
|
var readVerts = new DGRP3DVert[vertCount];
|
|||
|
var pinnedHandle = GCHandle.Alloc(readVerts, GCHandleType.Pinned);
|
|||
|
Marshal.Copy(bytes, 0, pinnedHandle.AddrOfPinnedObject(), bytes.Length);
|
|||
|
pinnedHandle.Free();
|
|||
|
SVerts = readVerts.ToList();
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
for (int i = 0; i < vertCount; i++)
|
|||
|
{
|
|||
|
var x = io.ReadFloat();
|
|||
|
var y = io.ReadFloat();
|
|||
|
var z = io.ReadFloat();
|
|||
|
var u = io.ReadFloat();
|
|||
|
var v = io.ReadFloat();
|
|||
|
var normal = new Vector3();
|
|||
|
SVerts.Add(new DGRP3DVert(new Vector3(x, y, z), normal, new Vector2(u, v)));
|
|||
|
}
|
|||
|
}
|
|||
|
var indexCount = io.ReadInt32();
|
|||
|
SIndices = ToTArray<int>(io.ReadBytes(indexCount * 4)).ToList();
|
|||
|
|
|||
|
// bottom up triangle ordering. useful for trees.
|
|||
|
/*
|
|||
|
var triBase = new int[SIndices.Count / 3][];
|
|||
|
for (int i = 0; i < triBase.Length; i++) triBase[i] = new int[] { SIndices[i * 3], SIndices[i*3 + 1], SIndices[i * 3 + 2] };
|
|||
|
|
|||
|
var ordered = triBase.OrderBy(x => SVerts[x[0]].Position.Y);
|
|||
|
SIndices.Clear();
|
|||
|
foreach (var item in ordered) SIndices.AddRange(item);
|
|||
|
*/
|
|||
|
|
|||
|
|
|||
|
if (Version < 2) GenerateNormals(false);
|
|||
|
|
|||
|
SComplete(gd);
|
|||
|
}
|
|||
|
|
|||
|
public DGRP3DGeometry(string[] splitName, OBJ obj, List<int[]> indices, DGRP source, GraphicsDevice gd)
|
|||
|
{
|
|||
|
if (splitName[1] == "SPR")
|
|||
|
{
|
|||
|
PixelSPR = ushort.Parse(splitName[3]);
|
|||
|
PixelDir = ushort.Parse(splitName[2].Substring(3));
|
|||
|
Pixel = source.GetImage(1, 3, PixelDir).Sprites[PixelSPR].GetTexture(gd);
|
|||
|
}
|
|||
|
else if (splitName[1] != "MASK")
|
|||
|
{
|
|||
|
PixelSPR = ushort.Parse(splitName[2]);
|
|||
|
CustomTexture = 1;
|
|||
|
PixelDir = 65535;
|
|||
|
|
|||
|
var name = source.ChunkParent.Filename.Replace('.', '_').Replace("spf", "iff");
|
|||
|
name += "_TEX_" + PixelSPR + ".png";
|
|||
|
Pixel = ReplTextureProvider(name);
|
|||
|
if (Pixel == null)
|
|||
|
{
|
|||
|
Pixel = source.ChunkParent.Get<MTEX>(PixelSPR)?.GetTexture(gd);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
SVerts = new List<DGRP3DVert>();
|
|||
|
SIndices = new List<int>();
|
|||
|
var dict = new Dictionary<Tuple<int, int, int>, int>();
|
|||
|
var hasNormals = false;
|
|||
|
|
|||
|
foreach (var ind in indices)
|
|||
|
{
|
|||
|
var tup = new Tuple<int, int, int>(ind[0], ind[1], (ind.Length > 2) ? ind[2] : -1);
|
|||
|
int targ;
|
|||
|
if (!dict.TryGetValue(tup, out targ))
|
|||
|
{
|
|||
|
//add a vertex
|
|||
|
targ = SVerts.Count;
|
|||
|
Vector3 normal = Vector3.Zero;
|
|||
|
if (tup.Item3 > -1)
|
|||
|
{
|
|||
|
normal = obj.Normals[tup.Item3 - 1];
|
|||
|
hasNormals = true;
|
|||
|
}
|
|||
|
var vert = new DGRP3DVert(obj.Vertices[ind[0] - 1], normal, obj.TextureCoords[ind[1] - 1]);
|
|||
|
vert.TextureCoordinate.Y = 1 - vert.TextureCoordinate.Y;
|
|||
|
SVerts.Add(vert);
|
|||
|
dict[tup] = targ;
|
|||
|
}
|
|||
|
SIndices.Add(targ);
|
|||
|
}
|
|||
|
|
|||
|
if (!hasNormals) GenerateNormals(false);
|
|||
|
|
|||
|
/*
|
|||
|
var triBase = new int[SIndices.Count / 3][];
|
|||
|
for (int i = 0; i < triBase.Length; i++) triBase[i] = new int[] { SIndices[i * 3], SIndices[i * 3 + 1], SIndices[i * 3 + 2] };
|
|||
|
|
|||
|
var ordered = triBase.OrderBy(x => SVerts[x[0]].Position.Y + SVerts[x[1]].Position.Y + SVerts[x[2]].Position.Y);
|
|||
|
SIndices.Clear();
|
|||
|
foreach (var item in ordered) SIndices.AddRange(item);
|
|||
|
*/
|
|||
|
|
|||
|
SComplete(gd);
|
|||
|
}
|
|||
|
|
|||
|
public void GenerateNormals(bool invert)
|
|||
|
{
|
|||
|
DGRP3DVert.GenerateNormals(invert, SVerts, SIndices);
|
|||
|
}
|
|||
|
|
|||
|
public void Save(IoWriter io)
|
|||
|
{
|
|||
|
io.WriteUInt16(PixelSPR);
|
|||
|
io.WriteUInt16(PixelDir);
|
|||
|
io.WriteInt32(SVerts.Count);
|
|||
|
foreach (var vert in SVerts)
|
|||
|
{
|
|||
|
io.WriteFloat(vert.Position.X);
|
|||
|
io.WriteFloat(vert.Position.Y);
|
|||
|
io.WriteFloat(vert.Position.Z);
|
|||
|
io.WriteFloat(vert.TextureCoordinate.X);
|
|||
|
io.WriteFloat(vert.TextureCoordinate.Y);
|
|||
|
io.WriteFloat(vert.Normal.X);
|
|||
|
io.WriteFloat(vert.Normal.Y);
|
|||
|
io.WriteFloat(vert.Normal.Z);
|
|||
|
}
|
|||
|
io.WriteInt32(SIndices.Count);
|
|||
|
io.WriteBytes(ToByteArray(SIndices.ToArray()));
|
|||
|
}
|
|||
|
|
|||
|
private string GetOName(int dyn)
|
|||
|
{
|
|||
|
if (CustomTexture == 0)
|
|||
|
{
|
|||
|
return dyn + "_SPR_rot" + PixelDir + "_" + PixelSPR;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
return dyn + "_TEX_" + PixelSPR;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public void SaveOBJ(StreamWriter io, int dyn, ref int baseInd)
|
|||
|
{
|
|||
|
string o_name = GetOName(dyn);
|
|||
|
|
|||
|
io.WriteLine("usemtl " + o_name);
|
|||
|
io.WriteLine("o " + o_name);
|
|||
|
foreach (var vert in SVerts)
|
|||
|
{
|
|||
|
io.WriteLine("v " + vert.Position.X.ToString(CultureInfo.InvariantCulture) + " " + vert.Position.Y.ToString(CultureInfo.InvariantCulture) + " " + vert.Position.Z.ToString(CultureInfo.InvariantCulture));
|
|||
|
}
|
|||
|
foreach (var vert in SVerts)
|
|||
|
{
|
|||
|
io.WriteLine("vt " + vert.TextureCoordinate.X.ToString(CultureInfo.InvariantCulture) + " " + (1 - vert.TextureCoordinate.Y).ToString(CultureInfo.InvariantCulture));
|
|||
|
}
|
|||
|
foreach (var vert in SVerts)
|
|||
|
{
|
|||
|
io.WriteLine("vn " + vert.Normal.X.ToString(CultureInfo.InvariantCulture) + " " + vert.Normal.Y.ToString(CultureInfo.InvariantCulture) + " " + vert.Normal.Z.ToString(CultureInfo.InvariantCulture));
|
|||
|
}
|
|||
|
|
|||
|
io.Write("f ");
|
|||
|
var ticker = 0;
|
|||
|
var j = 0;
|
|||
|
foreach (var ind in SIndices)
|
|||
|
{
|
|||
|
var i = ind + baseInd;
|
|||
|
io.Write(i + "/" + i + "/" + i + " ");
|
|||
|
if (++ticker == 3)
|
|||
|
{
|
|||
|
io.WriteLine("");
|
|||
|
if (j < SIndices.Count - 1) io.Write("f ");
|
|||
|
ticker = 0;
|
|||
|
}
|
|||
|
j++;
|
|||
|
}
|
|||
|
baseInd += SVerts.Count;
|
|||
|
}
|
|||
|
|
|||
|
public void SaveMTL(StreamWriter io, int dyn, string path)
|
|||
|
{
|
|||
|
var oname = GetOName(dyn);
|
|||
|
if (Pixel != null)
|
|||
|
{
|
|||
|
Common.Utils.GameThread.NextUpdate(x =>
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
using (var io2 = File.Open(Path.Combine(path, oname + ".png"), FileMode.Create))
|
|||
|
Pixel.SaveAsPng(io2, Pixel.Width, Pixel.Height);
|
|||
|
}
|
|||
|
catch (Exception e)
|
|||
|
{
|
|||
|
|
|||
|
}
|
|||
|
});
|
|||
|
}
|
|||
|
io.WriteLine("newmtl " + oname);
|
|||
|
io.WriteLine("Ka 1.000 1.000 1.000");
|
|||
|
io.WriteLine("Kd 1.000 1.000 1.000");
|
|||
|
io.WriteLine("Ks 0.000 0.000 0.000");
|
|||
|
|
|||
|
io.WriteLine("Ns 10.0000");
|
|||
|
io.WriteLine("illum 2");
|
|||
|
|
|||
|
io.WriteLine("map_Kd " + oname + ".png");
|
|||
|
io.WriteLine("map_d " + oname + ".png");
|
|||
|
}
|
|||
|
|
|||
|
public void Dispose()
|
|||
|
{
|
|||
|
Verts?.Dispose();
|
|||
|
Indices?.Dispose();
|
|||
|
}
|
|||
|
|
|||
|
private static T[] ToTArray<T>(byte[] input)
|
|||
|
{
|
|||
|
var result = new T[input.Length / Marshal.SizeOf(typeof(T))];
|
|||
|
Buffer.BlockCopy(input, 0, result, 0, input.Length);
|
|||
|
return result;
|
|||
|
}
|
|||
|
|
|||
|
private static byte[] ToByteArray<T>(T[] input)
|
|||
|
{
|
|||
|
var result = new byte[input.Length * Marshal.SizeOf(typeof(T))];
|
|||
|
Buffer.BlockCopy(input, 0, result, 0, result.Length);
|
|||
|
return result;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|