using System; using System.Collections; using GlitchyEngine.Content; using GlitchyEngine.Renderer; using Bon; using GlitchyEngine.Math; using System.IO; using Bon.Integrated; using GlitchyEngine; namespace GlitchyEditor.Assets.Importers; [BonTarget] class MaterialVariable { public ShaderVariableType ElementType; public int MatrixColumns; public int MatrixRows; public int ArrayElements; public uint8[] RawData ~ delete _; public this() { } public this(ShaderVariableType elementType, int matrixColumns, int matrixRows, int arrayElements) { ElementType = elementType; MatrixColumns = matrixColumns; MatrixRows = matrixRows; ArrayElements = arrayElements; RawData = new uint8[elementType.ElementSizeInBytes() * matrixColumns * matrixRows * arrayElements]; } static this() { gBonEnv.typeHandlers.Add(typeof(Self), ((.)new => VariableValueSerialize, (.)new => VariableValueDeserialize)); } static void VariableValueSerialize(BonWriter writer, ValueView value, BonEnvironment env, SerializeValueState state) { /*Log.EngineLogger.Assert(value.type == typeof(Self)); let variableValue = value.Get(); writer.Type(variableValue) using (writer.ObjectBlock()) { Serialize.Value(writer, nameof(MaterialFile.Effect), materialFile.Effect, env); Serialize.Value(writer, nameof(MaterialFile.Textures), materialFile.Textures, env); }*/ } static Result VariableValueDeserialize(BonReader reader, ValueView val, BonEnvironment env, DeserializeValueState state) { MaterialVariable output = val.Get(); StringView typeName = Try!(reader.EnumName()); // If we don't find a digit, we assume entire type name is element type and rows string ends up being an empty string. int firstDigitIndex = typeName.Length; for (char8 c in typeName) { if (c.IsDigit) { firstDigitIndex = @c.Index; } } Result elementTypeResult = Enum.Parse(typeName.Substring(0, firstDigitIndex), true); if (elementTypeResult case .Err) { Deserialize.Error!("Unknown element type.", reader); } int xIndex = typeName.LastIndexOf('x'); StringView rowsString = null; StringView columnsString = null; if (xIndex != -1) { rowsString = typeName.Substring(firstDigitIndex ..< xIndex); columnsString = typeName.Substring(xIndex + 1); } else { rowsString = typeName.Substring(firstDigitIndex); } Result rowsResult = int.Parse(rowsString); if (rowsResult case .Err(var error)) { switch (error) { case .NoValue: rowsResult = 1; case .Overflow: Deserialize.Error!("Integer overflow in row count.", reader); case .InvalidChar: Deserialize.Error!("Invalid character in row count.", reader); default: return .Err; } } Result columnsResult = int.Parse(columnsString); if (columnsResult case .Err(out error)) { switch (error) { case .NoValue: columnsResult = 1; case .Overflow: Deserialize.Error!("Integer overflow in column count.", reader); case .InvalidChar: Deserialize.Error!("Invalid character in column count.", reader); default: return .Err; } } // TODO: Array /*if (reader.[Friend]Check('[')) { }*/ output.ElementType = elementTypeResult.Get(); output.MatrixRows = rowsResult.Get(); output.MatrixColumns = columnsResult.Get(); output.ArrayElements = 1; int elementSize = output.ElementType.ElementSizeInBytes(); int elementCount = output.MatrixColumns * output.MatrixRows; output.RawData = new uint8[elementSize * elementCount * output.ArrayElements]; Try!(reader.ObjectBlock()); for (int currentElementIndex < elementCount) { switch (output.ElementType) { case .Float: StringView valueString = Try!(reader.Floating()); float* rawFloats = (float*)output.RawData.Ptr; rawFloats[currentElementIndex] = Try!(float.Parse(valueString)); case .Bool: // TODO: I'm pretty sure this is wrong, bools in c buffers are usually 32 bit bool value = Try!(reader.Bool()); ((bool*)&output.RawData)[currentElementIndex] = value; case .Int: StringView valueString = Try!(reader.Integer()); ((int32*)&output.RawData)[currentElementIndex] = Try!(int32.Parse(valueString)); case .UInt: StringView valueString = Try!(reader.Integer()); ((uint32*)&output.RawData)[currentElementIndex] = Try!(uint32.Parse(valueString)); } if (reader.ObjectHasMore()) { Try!(reader.EntryEnd()); } else { Log.EngineLogger.Warning("Vector/Matrix doesn't contain enough elements."); break; } } Try!(reader.ObjectBlockEnd()); return .Ok; } } [BonTarget] class NewMaterialFile : ImportedResource { public AssetHandle Effect; public Dictionary> Textures = new .() ~ DeleteDictionaryAndKeys!(_); public Dictionary Constants = new .() ~ DeleteDictionaryAndKeysAndValues!(_); public this(AssetIdentifier ownAssetIdentifier) : base(ownAssetIdentifier) { } } class MaterialImporter: IAssetImporter { private static readonly List _fileExtensions = new .(){".mat"} ~ delete _; public static List FileExtensions => _fileExtensions; public static Type ProcessedAssetType => typeof(NewMaterialFile); public AssetImporterConfig CreateDefaultConfig() { return new AssetImporterConfig(); } public Result Import(StringView fullFileName, AssetIdentifier assetIdentifier, AssetConfig config) { NewMaterialFile material = new .(new AssetIdentifier(assetIdentifier.FullIdentifier)); defer { if (@return case .Err) { delete material; } } String fullText = scope .(); Try!(File.ReadAllText(fullFileName, fullText, true)); Try!(Bon.Deserialize(ref material, fullText)); return material; } }