public static void ReadUVData(byte[] data, VRTF.ElementLayout layout, ref float[] output, float scale) { byte[] element = new byte[VRTF.ByteSizeFromFormat(layout.Format)]; Array.Copy(data, layout.Offset, element, 0, element.Length); switch (layout.Format) { case VRTF.ElementFormat.Short2: for (int i = 0; i < output.Length; i++) { output[i] += (float)BitConverter.ToInt16(element, i * sizeof(short)) * scale; } break; case VRTF.ElementFormat.Short4: for (int i = 0; i < output.Length; i++) { output[i] += (float)BitConverter.ToInt16(element, i * sizeof(short)) / short.MaxValue; } break; case VRTF.ElementFormat.Short4_DropShadow: for (int i = 0; i < output.Length - 1; i++) { output[i] += (float)BitConverter.ToInt16(element, i * sizeof(short)) / short.MaxValue; } output[output.Length - 1] += (float)BitConverter.ToInt16(element, (output.Length - 1) * sizeof(short)) / 511; break; default: ReadFloatData(data, layout, ref output); break; } }
private static void PositionMinMax(VRTF vrtf, IEnumerable <Vertex> vertices) { positionMin = 0f; positionMax = 0f; VRTF.ElementLayout layout = vrtf.Layouts.FirstOrDefault(x => x.Format == VRTF.ElementFormat.UShort4N && x.Usage == VRTF.ElementUsage.Position); if (layout == null) { return; } List <float> positionFloats = new List <float>(); foreach (float[] fs in vertices.Select(x => x.Position)) { if (fs != null) { positionFloats.AddRange(fs); } } if (positionFloats.Count > 0) { positionMax = positionMin = Math.Abs(positionFloats[0]); foreach (float f in positionFloats) { float x = Math.Abs(f); if (positionMin > x) { positionMin = x; } if (positionMax < x) { positionMax = x; } } } //positionMin = positionFloats.Count > 0 ? positionFloats.Min(x => Math.Abs(x)) : 0; //positionMax = positionFloats.Count > 0 ? positionFloats.Max(x => Math.Abs(x)) : 0; }
private static bool WriteUVData(float[] input, VRTF.ElementLayout layout, byte[] output, float scale) { bool okay = true; switch (layout.Format) { case VRTF.ElementFormat.Short2: for (int i = 0; i < input.Length; i++) { if ((short)Math.Round(input[i] / scale) != (long)Math.Round(input[i] / scale)) { okay = false; } Array.Copy(BitConverter.GetBytes((short)Math.Round(input[i] / scale)), 0, output, layout.Offset + i * sizeof(short), sizeof(short)); } break; case VRTF.ElementFormat.Short4: for (int i = 0; i < input.Length; i++) { Array.Copy(BitConverter.GetBytes((short)Math.Round(input[i] * short.MaxValue)), 0, output, layout.Offset + i * sizeof(short), sizeof(short)); } break; case VRTF.ElementFormat.Short4_DropShadow: for (int i = 0; i < input.Length - 1; i++) { Array.Copy(BitConverter.GetBytes((short)Math.Round(input[i] * short.MaxValue)), 0, output, layout.Offset + i * sizeof(short), sizeof(short)); } Array.Copy(BitConverter.GetBytes((short)Math.Round(input[input.Length - 1] * 511)), 0, output, layout.Offset + (input.Length - 1) * sizeof(short), sizeof(short)); break; default: WriteFloatData(input, layout, output); break; } return(okay); }
private static void WritePositionData(float[] input, VRTF.ElementLayout layout, byte[] output, float max) { switch (layout.Format) { case VRTF.ElementFormat.UShort4N: //scalar = (max >= 1) ? 511 : (ulong)short.MaxValue; //-- could try "max < 1.0 / 512.0"? //ulong scalar = (ulong)(max < 1 ? short.MaxValue : 511); //scalar++; //2011-08-30 changed to fixed 512 as LoveseatDanishModern had problems ulong scalar = 512; for (int i = 0; i < input.Length; i++) { Array.Copy(BitConverter.GetBytes((short)Math.Round(input[i] * scalar)), 0, output, layout.Offset + i * sizeof(short), sizeof(short)); } Array.Copy(BitConverter.GetBytes((short)(scalar == 512 ? 0 : scalar - 1)), 0, output, layout.Offset + 3 * sizeof(short), sizeof(short)); break; default: WriteFloatData(input, layout, output); break; } }
private static void WriteFloatData(float[] input, VRTF.ElementLayout layout, byte[] output) { ulong scalar; double max; switch (layout.Format) { case VRTF.ElementFormat.Float1: case VRTF.ElementFormat.Float2: case VRTF.ElementFormat.Float3: case VRTF.ElementFormat.Float4: for (int i = 0; i < input.Length; i++) { Array.Copy(BitConverter.GetBytes(input[i]), 0, output, layout.Offset + i * sizeof(float), sizeof(float)); } break; case VRTF.ElementFormat.ColorUByte4: switch (layout.Usage) { case VRTF.ElementUsage.Colour: for (int i = 0; i < input.Length; i++) { output[layout.Offset + i] = (byte)Math.Round(input[i] * byte.MaxValue); } break; case VRTF.ElementUsage.BlendWeight: for (int i = 0; i < input.Length; i++) { output[layout.Offset + kColorUByte4Map[i]] = (byte)Math.Round(input[i] * byte.MaxValue); } break; case VRTF.ElementUsage.Normal: case VRTF.ElementUsage.Tangent: // -0.98828125 == (((0.5 + 1) / 128f) - 1) for (int i = 0; i < input.Length - 1; i++) { output[layout.Offset + 2 - i] = (byte)(input[i] < -0.98828125 ? 0 : (Math.Round((input[i] + 1) * 128) - 1)); } //-- // Wes: (signed char) bytes[0]=vert[2+vrtfp.offset[j]]; // (float) norms[0]=(float)bytes[0]; // norms[0]=(norms[0]<(float)0.0)?(norms[0]+(float)128.0):(norms[0]-(float)128.0); //?? //-- // input: +1 > 0 > -1 // map step1: +2 > +1 > 0 // map step2: 255 > 127.5 > 0 //for (int i = 0; i < input.Length - 1; i++) // output[layout.Offset + 2 - i] = (byte)Math.Round((input[i] + 1) * 127.5); if (input[input.Length - 1] == -1) { output[layout.Offset + 3] = 0; } else if (input[input.Length - 1] == 0) { output[layout.Offset + 3] = 127; } else if (input[input.Length - 1] == 1) { output[layout.Offset + 3] = 255; } else { System.Diagnostics.Debug.WriteLine(String.Format("Unexpected handedness {0}.", input[input.Length - 1])); } break; } break; case VRTF.ElementFormat.Short2: for (int i = 0; i < input.Length; i++) { Array.Copy(BitConverter.GetBytes((short)Math.Round(input[i] * short.MaxValue)), 0, output, layout.Offset + i * sizeof(short), sizeof(short)); } break; case VRTF.ElementFormat.Short4: max = Math.Ceiling(input.Max(x => Math.Abs(x))); scalar = (ulong)(max < 1 ? short.MaxValue : short.MaxValue / max); //scalar++; for (int i = 0; i < input.Length; i++) { Array.Copy(BitConverter.GetBytes((short)Math.Round(input[i] * scalar)), 0, output, layout.Offset + i * sizeof(short), sizeof(short)); } Array.Copy(BitConverter.GetBytes((short)(scalar /*- 1/**/)), 0, output, layout.Offset + 3 * sizeof(short), sizeof(short)); break; case VRTF.ElementFormat.UShort4N: max = Math.Ceiling(input.Max(x => Math.Abs(x))); scalar = (ulong)(max < 1.0 ? short.MaxValue : 512); //scalar++; for (int i = 0; i < input.Length; i++) { Array.Copy(BitConverter.GetBytes((short)Math.Round(input[i] * scalar)), 0, output, layout.Offset + i * sizeof(short), sizeof(short)); } Array.Copy(BitConverter.GetBytes((short)(scalar == 512 ? 0 : scalar /*- 1/**/)), 0, output, layout.Offset + 3 * sizeof(short), sizeof(short)); break; } }
private static bool SetVertices(MemoryStream s, VRTF vrtf, IEnumerable <Vertex> vertices, float[] uvscales) { bool okay = true; PositionMinMax(vrtf, vertices); byte[] output = new byte[vrtf.Stride]; VRTF.ElementLayout position = vrtf.Layouts .FirstOrDefault(x => x.Usage == VRTF.ElementUsage.Position); VRTF.ElementLayout normal = vrtf.Layouts .FirstOrDefault(x => x.Usage == VRTF.ElementUsage.Normal); VRTF.ElementLayout[] uv = vrtf.Layouts .Where(x => x.Usage == VRTF.ElementUsage.UV) .ToArray(); VRTF.ElementLayout blendIndices = vrtf.Layouts .FirstOrDefault(x => x.Usage == VRTF.ElementUsage.BlendIndex); VRTF.ElementLayout blendWeights = vrtf.Layouts .FirstOrDefault(x => x.Usage == VRTF.ElementUsage.BlendWeight); VRTF.ElementLayout tangents = vrtf.Layouts .FirstOrDefault(x => x.Usage == VRTF.ElementUsage.Tangent); VRTF.ElementLayout color = vrtf.Layouts .FirstOrDefault(x => x.Usage == VRTF.ElementUsage.Colour); if (uvscales == null) { uvscales = defaultUVScales; } foreach (Vertex v in vertices) { if (v.Position != null) { WritePositionData(v.Position, position, output, positionMax); } if (v.Normal != null) { WriteFloatData(v.Normal, normal, output); } for (int u = 0; u < uv.Length; u++) { float scale = u < uvscales.Length && uvscales[u] != 0 ? uvscales[u] : uvscales[0]; if (v.UV[u] != null) { if (!WriteUVData(v.UV[u], uv[u], output, scale)) { okay = false; } } } if (v.BlendIndices != null) { Array.Copy(v.BlendIndices, 0, output, blendIndices.Offset, VRTF.ByteSizeFromFormat(blendIndices.Format)); } if (v.BlendWeights != null) { WriteFloatData(v.BlendWeights, blendWeights, output); } if (v.Tangents != null) { WriteFloatData(v.Tangents, tangents, output); } if (v.Color != null) { WriteFloatData(v.Color, color, output); } s.Write(output, 0, output.Length); } s.Flush(); return(okay); }
//Currently not supported: //UByte4N, //Short2N, Short4N, UShort2N, //Dec3N, UDec3N, //Float16_2, Float16_4 public static void ReadFloatData(byte[] data, VRTF.ElementLayout layout, ref float[] output) { byte[] element = new byte[VRTF.ByteSizeFromFormat(layout.Format)]; Array.Copy(data, layout.Offset, element, 0, element.Length); float scalar; switch (layout.Format) { case VRTF.ElementFormat.Float1: case VRTF.ElementFormat.Float2: case VRTF.ElementFormat.Float3: case VRTF.ElementFormat.Float4: for (int i = 0; i < output.Length; i++) { output[i] += BitConverter.ToSingle(element, i * sizeof(float)); } break; case VRTF.ElementFormat.ColorUByte4: switch (layout.Usage) { case VRTF.ElementUsage.Colour: for (int i = 0; i < output.Length; i++) { output[i] += element[i] / (float)byte.MaxValue; } break; case VRTF.ElementUsage.BlendWeight: for (int i = 0; i < output.Length; i++) { output[i] += element[kColorUByte4Map[i]] / (float)byte.MaxValue; } break; case VRTF.ElementUsage.Normal: case VRTF.ElementUsage.Tangent: for (int i = 0; i < output.Length - 1; i++) { output[i] += element[2 - i] == 0 ? -1 : (((element[2 - i] + 1) / 128f) - 1); } //-- // Wes: (signed char) bytes[0]=vert[2+vrtfp.offset[j]]; // (float) norms[0]=(float)bytes[0]; // norms[0]=(norms[0]<(float)0.0)?(norms[0]+(float)128.0):(norms[0]-(float)128.0); //??? //-- // input: 255 > 128 > 127 > 0 // map step1: +2 > 0 // map step2: +1 > -1 //for (int i = 0; i < output.Length - 1; i++) // output[i] += (element[2 - i] / 127.5f) - 1f; switch (element[3]) { case 0: output[output.Length - 1] = -1f; break; // -1 determinant case 127: output[output.Length - 1] = 0f; break; // There is no determinant case 255: output[output.Length - 1] = +1f; break; // +1 determinant default: System.Diagnostics.Debug.WriteLine(String.Format("Unexpected handedness {0}.", element[3])); break; } break; } break; case VRTF.ElementFormat.Short2: for (int i = 0; i < output.Length; i++) { output[i] += BitConverter.ToInt16(element, i * sizeof(short)) / (float)short.MaxValue; } break; case VRTF.ElementFormat.Short4: scalar = BitConverter.ToUInt16(element, 3 * sizeof(short)); if (scalar == 0) { scalar = short.MaxValue; } //scalar++; for (int i = 0; i < output.Length; i++) { output[i] += BitConverter.ToInt16(element, i * sizeof(short)) / scalar; } break; case VRTF.ElementFormat.UShort4N: scalar = BitConverter.ToUInt16(element, 3 * sizeof(ushort)); if (scalar == 0) { scalar = 511; } //scalar++; for (int i = 0; i < output.Length; i++) { output[i] += BitConverter.ToInt16(element, i * sizeof(short)) / scalar; } break; } }
public Vertex[] GetVertices(VRTF vrtf, long offset, int count, float[] uvscales) { long streamOffset = offset; Stream s = new MemoryStream(mBuffer); s.Seek(streamOffset, SeekOrigin.Begin); VRTF.ElementLayout position = vrtf.Layouts .FirstOrDefault(x => x.Usage == VRTF.ElementUsage.Position); VRTF.ElementLayout normal = vrtf.Layouts .FirstOrDefault(x => x.Usage == VRTF.ElementUsage.Normal); VRTF.ElementLayout[] uv = vrtf.Layouts .Where(x => x.Usage == VRTF.ElementUsage.UV) .ToArray(); VRTF.ElementLayout blendIndices = vrtf.Layouts .FirstOrDefault(x => x.Usage == VRTF.ElementUsage.BlendIndex); VRTF.ElementLayout blendWeights = vrtf.Layouts .FirstOrDefault(x => x.Usage == VRTF.ElementUsage.BlendWeight); VRTF.ElementLayout tangents = vrtf.Layouts .FirstOrDefault(x => x.Usage == VRTF.ElementUsage.Tangent); VRTF.ElementLayout color = vrtf.Layouts .FirstOrDefault(x => x.Usage == VRTF.ElementUsage.Colour); Vertex[] verts = new Vertex[count]; if (uvscales == null) { uvscales = new float[3]; } for (int i = 0; i < count; i++) { Vertex v = new Vertex(); byte[] data = new byte[vrtf.Stride]; s.Read(data, 0, vrtf.Stride); if (position != null) { float[] posPoints = new float[VRTF.FloatCountFromFormat(position.Format)]; ReadFloatData(data, position, ref posPoints); v.Position = posPoints; } if (normal != null) { float[] normPoints = new float[VRTF.FloatCountFromFormat(normal.Format)]; ReadFloatData(data, normal, ref normPoints); v.Normal = normPoints; } v.UV = new float[uv.Length][]; for (int j = 0; j < uv.Length; j++) { VRTF.ElementLayout u = uv[j]; float[] uvPoints = new float[VRTF.FloatCountFromFormat(u.Format)]; float scale = j < uvscales.Length && uvscales[j] != 0 ? uvscales[j] : uvscales[0]; ReadUVData(data, u, ref uvPoints, scale); v.UV[j] = uvPoints; } if (blendIndices != null) { byte[] blendIPoints = new byte[VRTF.ByteSizeFromFormat(blendIndices.Format)]; Array.Copy(data, blendIndices.Offset, blendIPoints, 0, blendIPoints.Length); v.BlendIndices = blendIPoints; } if (blendWeights != null) { float[] blendWPoints = new float[VRTF.FloatCountFromFormat(blendWeights.Format)]; ReadFloatData(data, blendWeights, ref blendWPoints); v.BlendWeights = blendWPoints; } if (tangents != null) { float[] tangentPoints = new float[VRTF.FloatCountFromFormat(tangents.Format)]; ReadFloatData(data, tangents, ref tangentPoints); v.Tangents = tangentPoints; } if (color != null) { float[] colorPoints = new float[VRTF.FloatCountFromFormat(color.Format)]; ReadFloatData(data, color, ref colorPoints); v.Color = colorPoints; } verts[i] = v; } return(verts); }