Skip to content

Instantly share code, notes, and snippets.

@occar421
Created March 4, 2014 06:23
Show Gist options
  • Save occar421/9341260 to your computer and use it in GitHub Desktop.
Save occar421/9341260 to your computer and use it in GitHub Desktop.
Discussion of .srf file linq parser 2
public void Parse(IEnumerable<string> data)
{
DateTime start = DateTime.Now;
var stream = data.Where(x => !string.IsNullOrEmpty(x));
if (stream.First().StartsWith("surf", false, null))
{
throw new FileFormatException("SURF Header");
}
var splitedByZ = stream.Skip(1).GroupBy(x => x.First() == 'Z');
var normalLines = splitedByZ.Single(x => !x.Key);
var zBuf = splitedByZ.SingleOrDefault(x => x.Key);
IDictionary<int, int> alphaData;
IEnumerable<int> zData;
IEnumerable<int> lightData;
if (zBuf == null)
{
alphaData = new Dictionary<int, int>();
zData = new int[0];
lightData = new int[0];
}
else
{
var zLines = zBuf.GroupBy(x => x.Skip(1).First()).Select(x => new KeyValuePair<char, IEnumerable<int>>(x.Key, x.SelectMany(y => y.Split(' ').Skip(1)).Select(y => int.Parse(y))));
//Alpha
var alphaLines = zLines.SingleOrDefault(x => x.Key == 'A').Value;
if (alphaLines == null)
{
alphaData = new Dictionary<int, int>();
}
else
{
var alphaGroup = alphaLines.Select((x, i) => new { Index = i, Value = x }).GroupBy(x => x.Index % 2 == 0);
alphaData = alphaGroup.Single(x => x.Key).Zip(alphaGroup.Single(x => !x.Key), (key, value) => new { Key = key.Value, Value = value.Value })
.ToDictionary(x => x.Key, x => x.Value);
}
//Z
zData = zLines.SingleOrDefault(x => x.Key == 'Z').Value ?? new int[0];
//Light
lightData = zLines.SingleOrDefault(x => x.Key == 'L').Value ?? new int[0];
}
//Vertex
var vertexLines = normalLines.TakeWhile(x => x.First() == 'V');
Vertices = vertexLines.Select(x => Vertex.Create(x));
//Face
var faceLines = normalLines.SkipWhile(x => x.First() == 'V');
Faces = Face.CreateFaces(faceLines, alphaData, zData, lightData);
RequiredTime = DateTime.Now - start;
}
struct Face
{
public IEnumerable<int> VertexIndices { get; set; }
public Color4 Color { get; set; }
public bool IsEmit { get; set; }
public Vector3 Normal { get; set; }
public Vector3 Centroid { get; set; }
public bool IsCpuRenderIgnore { get; set; }
public bool IsLight { get; set; }
static public IEnumerable<Face> CreateFaces(IEnumerable<string> data, IDictionary<int, int> alpha, IEnumerable<int> z, IEnumerable<int> light)
{
var e = data.GetEnumerator();
bool isFace = false;
Face f = new Face();
for (var i = 0; e.MoveNext(); i++)
{
switch (e.Current.First())
{
case 'F':
isFace = true;
break;
case 'B':
if (!isFace)
{
throw new FileFormatException("F行とE行の外にB行があります。");
}
f.IsEmit = true;
break;
case 'C':
if (!isFace)
{
throw new FileFormatException("F行とE行の外にC行があります。");
}
var color = e.Current.Split(' ');
if (color.Length == 4)
{
f.Color = new Color4()
{
R = float.Parse(color[1]) / 255f,
G = float.Parse(color[2]) / 255f,
B = float.Parse(color[3]) / 255f,
A = alpha.ContainsKey(i) ? alpha[i] : 0f
};
}
else if (color.Length == 2)
{
f.Color = new Color4()
{
R = (float)Math.Floor(((int.Parse(color[1]) & 992) >> 5) * 255.0f / 31.0f),
G = (float)Math.Floor(((int.Parse(color[1]) & 31744) >> 10) * 255.0f / 31.0f),
B = (float)Math.Floor(((int.Parse(color[1]) & 31)) * 255.0f / 31.0f),
A = alpha.ContainsKey(i) ? alpha[i] : 0f
};
}
else
{
throw new FileFormatException("色のフォーマットが異常です。" + string.Concat(color));
}
break;
case 'N':
if (!isFace)
{
throw new FileFormatException("F行とE行の外にN行があります。");
}
var normal = e.Current.Split(' ');
f.Normal = new Vector3()
{
X = -float.Parse(normal[1]),
Y = float.Parse(normal[2]),
Z = float.Parse(normal[3])
};
f.Centroid = new Vector3()
{
X = -float.Parse(normal[4]),
Y = float.Parse(normal[5]),
Z = float.Parse(normal[6])
};
break;
case 'V':
if (!isFace)
{
throw new FileFormatException("F行とE行の外に面定義と思われるV行があります。");
}
f.VertexIndices = e.Current.Split(' ').Skip(1).Select(x => int.Parse(x));
break;
case 'E':
if (isFace)
{
f.IsCpuRenderIgnore = z.Contains(i);
f.IsLight = light.Contains(i);
yield return f;
}
else
{
yield break;
}
isFace = false;
break;
default:
break;
}
}
}
}
struct Vertex
{
public Vector3 Position { get; set; }
public bool IsRound { get; set; }
public Vector3 Normal { get; set; }
static public Vertex Create(string data)
{
var e = data.Split(' ');
return new Vertex()
{
Position = new Vector3()
{
X = -float.Parse(e[1]),
Y = float.Parse(e[2]),
Z = float.Parse(e[3])
},
IsRound = (e.Length > 5 && "R".Equals(e[4]))
};
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment