Skip to content

Instantly share code, notes, and snippets.

@occar421
Created March 2, 2014 11:51
Show Gist options
  • Save occar421/9305463 to your computer and use it in GitHub Desktop.
Save occar421/9305463 to your computer and use it in GitHub Desktop.
Discussion of .srf file linq parser 1
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");
}
//Alpha
var alphaLines = stream.Where(x => x.StartsWith("ZA"));
var alphaArray = alphaLines.SelectMany(x => x.Split(' ').Skip(1));
var alphaDictionary = Enumerable.Zip(alphaArray.Alternate(2), alphaArray.Skip(1).Alternate(2), (x, y) => new KeyValuePair<int, float>(int.Parse(x), float.Parse(y) / 255f)).ToDictionary(item => item.Key, item => item.Value);
//Z
var zLines = stream.Where(x => x.StartsWith("ZZ"));
var zArray = zLines.SelectMany(x => x.Split(' ').Skip(1)).Select(x => int.Parse(x));
//Light
var lightLines = stream.Where(x => x.StartsWith("ZL"));
var lightArray = lightLines.SelectMany(x => x.Split(' ').Skip(1)).Select(x => int.Parse(x));
//Vertices
var vertexLines = stream.Skip(1).TakeWhile(x => x.StartsWith("V"));
Vertices = vertexLines.AsParallel().Select(x => Vertex.Create(x));
//Faces
var faceLines = stream.Skip(1).SkipWhile(x => x.StartsWith("V")).ComparerTakeWhile((now, next) => !(now.StartsWith("E") && next.StartsWith("E")), "", "");
Faces = faceLines.HeadSeparate(x => x.StartsWith("F")).AsParallel().Select((x, i) => Face.Create(x, i, alphaDictionary, zArray, lightArray));
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 IsDoubleSide { get; set; }
public bool IsCpuRenderIgnore { get; set; }
public bool IsLight { get; set; }
static public Face Create(IEnumerable<string> data, int index, IDictionary<int, float> alpha, IEnumerable<int> z, IEnumerable<int> light)
{
var result = new Face();
result.IsEmit = data.Any(x => x.StartsWith("B"));
var color = data.Single(x => x.StartsWith("C")).Split(' ');
if (color.Length == 4)
{
result.Color = new Color4()
{
R = float.Parse(color[1]) / 255f,
G = float.Parse(color[2]) / 255f,
B = float.Parse(color[3]) / 255f,
A = alpha.ContainsKey(index) ? alpha[index] : 0f
};
}
else if (color.Length == 2)
{
result.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)
};
}
else
{
throw new FileFormatException("色のフォーマットが異常です。" + string.Concat(color));
}
var normal = data.Single(x => x.StartsWith("N")).Split(' ');
result.Normal = new Vector3()
{
X = -float.Parse(normal[1]),
Y = float.Parse(normal[2]),
Z = float.Parse(normal[3])
};
result.Centroid = new Vector3()
{
X = -float.Parse(normal[4]),
Y = float.Parse(normal[5]),
Z = float.Parse(normal[6])
};
result.IsDoubleSide = result.Normal == Vector3.Zero;
var indices = data.Single(x => x.StartsWith("V")).Split(' ');
result.VertexIndices = indices.Skip(1).Select(x => int.Parse(x)).Reverse();
result.IsCpuRenderIgnore = z.Contains(index);
result.IsLight = light.Contains(index);
return result;
}
}
static class LinqExtension
{
public static IEnumerable<T> ComparerTakeWhile<T>(this IEnumerable<T> obj, Func<T, T, bool> comparer, T firstItem, T lastItem)
{
if (obj == null)
{
yield break;
}
var e = obj.GetEnumerator();
if (!e.MoveNext())
{
yield break;
}
T now = e.Current;
if (!comparer(firstItem, now))
{
yield break;
}
while (e.MoveNext())
{
if (!comparer(now, e.Current))
{
yield return now;
yield break;
}
yield return now;
now = e.Current;
}
if (comparer(now, lastItem))
{
yield return now;
}
}
public static IEnumerable<IEnumerable<T>> HeadSeparate<T>(this IEnumerable<T> obj, Func<T, bool> head)
{
if (obj == null)
{
yield break;
}
var predicate = (Func<T, bool>)(x => !head(x));
IEnumerable<T> current, next = obj, sample;
while (next.Any())
{
sample = next.Skip(1).TakeWhile(predicate);
current = next.Take(sample.Count() + 1);
yield return current;
next = next.Skip(1).SkipWhile(predicate);
}
}
public static IEnumerable<T> Alternate<T>(this IEnumerable<T> obj, int step)
{
var e = obj.GetEnumerator();
for (int i = 0; e.MoveNext(); i++)
{
if (i % step == 0)
{
yield return e.Current;
}
}
}
}
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