/// <summary> /// /// </summary> /// <returns></returns> private GX_Attribute[] GetAttributes(GXAttribName[] names) { var attrs = new GX_Attribute[names.Length + 1]; for (int i = 0; i < names.Length; i++) { if (!nameToAttr.ContainsKey(names[i])) { var attr = new GX_Attribute() { AttributeName = names[i], AttributeType = GXAttribType.GX_DIRECT, CompType = GXCompType.RGB8, Stride = 4, CompCount = GXCompCnt.ClrRGB }; if (UseVertexAlpha && (names[i].Equals(GXAttribName.GX_VA_CLR0) || names[i].Equals(GXAttribName.GX_VA_CLR1))) { attr.CompType = GXCompType.RGBA8; } Console.WriteLine(names[i] + " " + attr.CompType); nameToAttr.Add(names[i], attr); } attrs[i] = nameToAttr[names[i]]; } // null buffer to indicate end attrs[attrs.Length - 1] = new GX_Attribute(); attrs[attrs.Length - 1].AttributeName = GXAttribName.GX_VA_NULL; return(attrs); }
/// <summary> /// Gets the index of a value in the buffer /// </summary> /// <param name="v"></param> /// <param name="o"></param> /// <returns></returns> private ushort GetIndex(GXAttribName attributeName, float[] o) { if (!nameToAttr.ContainsKey(attributeName)) { GX_Attribute a = new GX_Attribute(); a.AttributeName = attributeName; nameToIndexHash.Add(attributeName, new Dictionary <int, int>()); nameToAttr.Add(attributeName, a); attrToNewData.Add(a, new List <float[]>()); } var hashToIndex = nameToIndexHash[attributeName]; var index = 0; var hash = string.Join("", o).GetHashCode();// ((IStructuralEquatable)o).GetHashCode(EqualityComparer<float>.Default); if (hashToIndex.ContainsKey(hash)) { index = hashToIndex[hash]; } else { var vals = attrToNewData[nameToAttr[attributeName]]; index = vals.Count; vals.Add(o); hashToIndex.Add(hash, index); } return((ushort)index); }
/// <summary> /// /// </summary> /// <returns></returns> private GX_Attribute[] GetAttributes(GXAttribName[] names) { var attrs = new GX_Attribute[names.Length + 1]; for (int i = 0; i < names.Length; i++) { if (!nameToAttr.ContainsKey(names[i])) { nameToAttr.Add(names[i], new GX_Attribute() { AttributeName = names[i], AttributeType = GXAttribType.GX_DIRECT, CompType = GXCompType.RGB8, Stride = 4, CompCount = GXCompCnt.ClrRGB }); } attrs[i] = nameToAttr[names[i]]; } // null buffer to indicate end attrs[attrs.Length - 1] = new GX_Attribute(); attrs[attrs.Length - 1].AttributeName = GXAttribName.GX_VA_NULL; return(attrs); }
/// <summary> /// /// </summary> /// <param name="Attribute"></param> /// <param name="Values"></param> public static void GenerateBuffer(GX_Attribute Attribute, List <float[]> Values) { switch (Attribute.AttributeName) { case GXAttribName.GX_VA_PNMTXIDX: case GXAttribName.GX_VA_TEX0MTXIDX: case GXAttribName.GX_VA_TEX1MTXIDX: case GXAttribName.GX_VA_TEX2MTXIDX: case GXAttribName.GX_VA_TEX3MTXIDX: case GXAttribName.GX_VA_TEX4MTXIDX: case GXAttribName.GX_VA_TEX5MTXIDX: case GXAttribName.GX_VA_TEX6MTXIDX: case GXAttribName.GX_VA_TEX7MTXIDX: case GXAttribName.GX_VA_CLR0: case GXAttribName.GX_VA_CLR1: Attribute.AttributeType = GXAttribType.GX_DIRECT; break; } OptimizeCompression(Attribute, Values); MemoryStream o = new MemoryStream(); using (BinaryWriterExt Writer = new BinaryWriterExt(o)) { Writer.BigEndian = true; foreach (float[] ob in Values) { foreach (var v in ob) { WriteData(Writer, v, Attribute.CompType, Attribute.Scale); } } Writer.Align(0x20); } if (Attribute.Buffer == null) { Attribute.Buffer = new HSDAccessor(); } Attribute.Buffer._s.SetData(o.ToArray()); o.Dispose(); }
/// <summary> /// </summary> private static void OptimizeCompression(GX_Attribute attr, List <float[]> values) { // no need to optimize direct if (attr.AttributeType == GXAttribType.GX_DIRECT) { return; } switch (attr.AttributeName) { case GXAttribName.GX_VA_POS: attr.CompCount = GXCompCnt.PosXYZ; break; case GXAttribName.GX_VA_NRM: attr.CompCount = GXCompCnt.NrmXYZ; break; case GXAttribName.GX_VA_NBT: attr.CompCount = GXCompCnt.NrmNBT; break; case GXAttribName.GX_VA_TEX0: case GXAttribName.GX_VA_TEX1: case GXAttribName.GX_VA_TEX2: case GXAttribName.GX_VA_TEX3: case GXAttribName.GX_VA_TEX4: case GXAttribName.GX_VA_TEX5: case GXAttribName.GX_VA_TEX6: case GXAttribName.GX_VA_TEX7: attr.CompCount = GXCompCnt.TexST; break; case GXAttribName.GX_VA_CLR0: case GXAttribName.GX_VA_CLR1: if (attr.CompType == GXCompType.RGBA4 || attr.CompType == GXCompType.RGBA6 || attr.CompType == GXCompType.RGBA8 || attr.CompType == GXCompType.RGBX8) { attr.CompCount = GXCompCnt.ClrRGBA; } else { attr.CompCount = GXCompCnt.ClrRGB; } break; default: throw new NotSupportedException($"{attr.AttributeName} not supported for optimizing"); } // get normalized value range double max = 0; bool signed = false; foreach (float[] v in values) { foreach (var val in v) { max = Math.Max(max, Math.Abs(val)); if (val < 0) { signed = true; } } } // get best scale for 8 byte scale = 1; byte byteScale = 1; byte sbyteScale = 1; byte shortScale = 1; byte ushortScale = 1; while (max != 0 && max * Math.Pow(2, scale) < ushort.MaxValue && scale < byte.MaxValue) { var val = max * Math.Pow(2, scale); if (val < byte.MaxValue) { byteScale = scale; } if (val < sbyte.MaxValue) { sbyteScale = scale; } if (val < short.MaxValue) { shortScale = scale; } if (val < ushort.MaxValue) { ushortScale = scale; } scale++; } double error = 0; if (!signed) // byte or ushort { foreach (float[] v in values) { foreach (var val in v) { error = Math.Max(error, (byte)(val * Math.Pow(2, byteScale)) / Math.Pow(2, byteScale)); } } } else // sbyte or short { foreach (float[] v in values) { foreach (var val in v) { error = (sbyte)(val * Math.Pow(2, sbyteScale)) / Math.Pow(2, sbyteScale); } } } if (Math.Abs(max - error) < Epsilon) { if (signed) { attr.CompType = GXCompType.Int8; attr.Scale = sbyteScale; } else { attr.CompType = GXCompType.UInt8; attr.Scale = byteScale; } } else { if (signed) { attr.CompType = GXCompType.Int16; attr.Scale = shortScale; } else { attr.CompType = GXCompType.UInt16; attr.Scale = ushortScale; } } // set index type attr.AttributeType = GXAttribType.GX_INDEX8; if (values.Count > byte.MaxValue) { attr.AttributeType = GXAttribType.GX_INDEX16; } // calculate stride attr.Stride = AttributeStride(attr); }
/// <summary> /// /// </summary> /// <param name="attribute"></param> /// <returns></returns> private static short AttributeStride(GX_Attribute attribute) { return((short)(CompTypeToInt(attribute.AttributeName, attribute.CompType) * CompCountToInt(attribute.AttributeName, attribute.CompCount))); }