Base files

This commit is contained in:
Samuele Lorefice
2025-01-22 00:43:53 +01:00
commit 2a051cf098
10 changed files with 874 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
bin/
obj/
/packages/
riderModule.iml
/_ReSharper.Caches/

13
.idea/.idea.BlenderSharp/.idea/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,13 @@
# Default ignored files
/shelf/
/workspace.xml
# Rider ignored files
/.idea.BlenderSharp.iml
/contentModel.xml
/modules.xml
/projectSettingsUpdater.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="UserContentModel">
<attachedFolders />
<explicitIncludes />
<explicitExcludes />
</component>
</project>

6
.idea/.idea.BlenderSharp/.idea/vcs.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

View File

@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

22
BlenderSharp.sln Normal file
View File

@@ -0,0 +1,22 @@

Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeGenerator", "CodeGenerator\CodeGenerator.csproj", "{F7A0CD58-F691-4EFC-AC04-D63DB372DA31}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BlendTypes", "BlendTypes\BlendTypes.csproj", "{E2D22AE2-A31A-453C-8A3F-1D4066F0C55D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{F7A0CD58-F691-4EFC-AC04-D63DB372DA31}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F7A0CD58-F691-4EFC-AC04-D63DB372DA31}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F7A0CD58-F691-4EFC-AC04-D63DB372DA31}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F7A0CD58-F691-4EFC-AC04-D63DB372DA31}.Release|Any CPU.Build.0 = Release|Any CPU
{E2D22AE2-A31A-453C-8A3F-1D4066F0C55D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E2D22AE2-A31A-453C-8A3F-1D4066F0C55D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E2D22AE2-A31A-453C-8A3F-1D4066F0C55D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E2D22AE2-A31A-453C-8A3F-1D4066F0C55D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,575 @@
// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild
using System.Collections.Generic;
// ReSharper disable once CheckNamespace
namespace Kaitai {
/// <summary>
/// Blender is an open source suite for 3D modelling, sculpting,
/// animation, compositing, rendering, preparation of assets for its own
/// game engine and exporting to others, etc. `.blend` is its own binary
/// format that saves whole state of suite: current scene, animations,
/// all software settings, extensions, etc.
///
/// Internally, .blend format is a hybrid semi-self-descriptive
/// format. On top level, it contains a simple header and a sequence of
/// file blocks, which more or less follow typical [TLV
/// pattern](https://en.wikipedia.org/wiki/Type-length-value). Pre-last
/// block would be a structure with code `DNA1`, which is a essentially
/// a machine-readable schema of all other structures used in this file.
/// </summary>
public partial class BlenderBlend : KaitaiStruct {
public static BlenderBlend FromFile(string fileName) {
return new BlenderBlend(new KaitaiStream(fileName));
}
public enum PtrSize {
Bits64 = 45,
Bits32 = 95,
}
public enum Endian {
Be = 86,
Le = 118,
}
public BlenderBlend(KaitaiStream p__io, KaitaiStruct p__parent = null, BlenderBlend p__root = null) : base(p__io) {
m_parent = p__parent;
m_root = p__root ?? this;
f_sdnaStructs = false;
_read();
}
private void _read() {
_hdr = new Header(m_io, this, m_root);
_blocks = new List<FileBlock>();
{
var i = 0;
while (!m_io.IsEof) {
_blocks.Add(new FileBlock(m_io, this, m_root));
i++;
}
}
}
/// <summary>
/// DNA struct contains a `type` (type name), which is specified as
/// an index in types table, and sequence of fields.
/// </summary>
public partial class DnaStruct : KaitaiStruct {
public static DnaStruct FromFile(string fileName) {
return new DnaStruct(new KaitaiStream(fileName));
}
public DnaStruct(KaitaiStream p__io, BlenderBlend.Dna1Body p__parent = null, BlenderBlend p__root = null) :
base(p__io) {
m_parent = p__parent;
m_root = p__root;
f_type = false;
_read();
}
private void _read() {
_idxType = m_io.ReadU2le();
_numFields = m_io.ReadU2le();
_fields = new List<DnaField>();
for (var i = 0; i < NumFields; i++) {
_fields.Add(new DnaField(m_io, this, m_root));
}
}
private bool f_type;
private string _type;
public string Type {
get {
if (f_type)
return _type;
_type = (string)(M_Parent.Types[IdxType]);
f_type = true;
return _type;
}
}
private ushort _idxType;
private ushort _numFields;
private List<DnaField> _fields;
private BlenderBlend m_root;
private BlenderBlend.Dna1Body m_parent;
public ushort IdxType {
get { return _idxType; }
}
public ushort NumFields {
get { return _numFields; }
}
public List<DnaField> Fields {
get { return _fields; }
}
public BlenderBlend M_Root {
get { return m_root; }
}
public BlenderBlend.Dna1Body M_Parent {
get { return m_parent; }
}
}
public partial class FileBlock : KaitaiStruct {
public static FileBlock FromFile(string fileName) {
return new FileBlock(new KaitaiStream(fileName));
}
public FileBlock(KaitaiStream p__io, BlenderBlend p__parent = null, BlenderBlend p__root = null) : base(p__io) {
m_parent = p__parent;
m_root = p__root;
f_sdnaStruct = false;
_read();
}
private void _read() {
_code = System.Text.Encoding.GetEncoding("ASCII").GetString(m_io.ReadBytes(4));
_lenBody = m_io.ReadU4le();
_memAddr = m_io.ReadBytes(M_Root.Hdr.Psize);
_sdnaIndex = m_io.ReadU4le();
_count = m_io.ReadU4le();
switch (Code) {
case "DNA1":
{
__raw_body = m_io.ReadBytes(LenBody);
var io___raw_body = new KaitaiStream(__raw_body);
_body = new Dna1Body(io___raw_body, this, m_root);
break;
}
default:
{
_body = m_io.ReadBytes(LenBody);
break;
}
}
}
private bool f_sdnaStruct;
private DnaStruct _sdnaStruct;
public DnaStruct SdnaStruct {
get {
if (f_sdnaStruct)
return _sdnaStruct;
if (SdnaIndex != 0) {
_sdnaStruct = (DnaStruct)(M_Root.SdnaStructs[(int)SdnaIndex]);
}
f_sdnaStruct = true;
return _sdnaStruct;
}
}
private string _code;
private uint _lenBody;
private byte[] _memAddr;
private uint _sdnaIndex;
private uint _count;
private object _body;
private BlenderBlend m_root;
private BlenderBlend m_parent;
private byte[] __raw_body;
/// <summary>
/// Identifier of the file block
/// </summary>
public string Code {
get { return _code; }
}
/// <summary>
/// Total length of the data after the header of file block
/// </summary>
public uint LenBody {
get { return _lenBody; }
}
/// <summary>
/// Memory address the structure was located when written to disk
/// </summary>
public byte[] MemAddr {
get { return _memAddr; }
}
/// <summary>
/// Index of the SDNA structure
/// </summary>
public uint SdnaIndex {
get { return _sdnaIndex; }
}
/// <summary>
/// Number of structure located in this file-block
/// </summary>
public uint Count {
get { return _count; }
}
public object Body {
get { return _body; }
}
public BlenderBlend M_Root {
get { return m_root; }
}
public BlenderBlend M_Parent {
get { return m_parent; }
}
public byte[] M_RawBody {
get { return __raw_body; }
}
}
/// <summary>
/// DNA1, also known as &quot;Structure DNA&quot;, is a special block in
/// .blend file, which contains machine-readable specifications of
/// all other structures used in this .blend file.
///
/// Effectively, this block contains:
///
/// * a sequence of &quot;names&quot; (strings which represent field names)
/// * a sequence of &quot;types&quot; (strings which represent type name)
/// * a sequence of &quot;type lengths&quot;
/// * a sequence of &quot;structs&quot; (which describe contents of every
/// structure, referring to types and names by index)
/// </summary>
/// <remarks>
/// Reference: <a href="https://archive.blender.org/wiki/index.php/Dev:Source/Architecture/File_Format/#Structure_DNA">Source</a>
/// </remarks>
public partial class Dna1Body : KaitaiStruct {
public static Dna1Body FromFile(string fileName) {
return new Dna1Body(new KaitaiStream(fileName));
}
public Dna1Body(KaitaiStream p__io, BlenderBlend.FileBlock p__parent = null, BlenderBlend p__root = null) :
base(p__io) {
m_parent = p__parent;
m_root = p__root;
_read();
}
private void _read() {
_id = m_io.ReadBytes(4);
if (!((KaitaiStream.ByteArrayCompare(Id, new byte[] { 83, 68, 78, 65 }) == 0))) {
throw new ValidationNotEqualError(new byte[] { 83, 68, 78, 65 }, Id, M_Io, "/types/dna1_body/seq/0");
}
_nameMagic = m_io.ReadBytes(4);
if (!((KaitaiStream.ByteArrayCompare(NameMagic, new byte[] { 78, 65, 77, 69 }) == 0))) {
throw new ValidationNotEqualError(new byte[] { 78, 65, 77, 69 }, NameMagic, M_Io, "/types/dna1_body/seq/1");
}
_numNames = m_io.ReadU4le();
_names = new List<string>();
for (var i = 0; i < NumNames; i++) {
_names.Add(System.Text.Encoding.GetEncoding("UTF-8").GetString(m_io.ReadBytesTerm(0, false, true, true)));
}
_padding1 = m_io.ReadBytes(KaitaiStream.Mod((4 - M_Io.Pos), 4));
_typeMagic = m_io.ReadBytes(4);
if (!((KaitaiStream.ByteArrayCompare(TypeMagic, new byte[] { 84, 89, 80, 69 }) == 0))) {
throw new ValidationNotEqualError(new byte[] { 84, 89, 80, 69 }, TypeMagic, M_Io, "/types/dna1_body/seq/5");
}
_numTypes = m_io.ReadU4le();
_types = new List<string>();
for (var i = 0; i < NumTypes; i++) {
_types.Add(System.Text.Encoding.GetEncoding("UTF-8").GetString(m_io.ReadBytesTerm(0, false, true, true)));
}
_padding2 = m_io.ReadBytes(KaitaiStream.Mod((4 - M_Io.Pos), 4));
_tlenMagic = m_io.ReadBytes(4);
if (!((KaitaiStream.ByteArrayCompare(TlenMagic, new byte[] { 84, 76, 69, 78 }) == 0))) {
throw new ValidationNotEqualError(new byte[] { 84, 76, 69, 78 }, TlenMagic, M_Io, "/types/dna1_body/seq/9");
}
_lengths = new List<ushort>();
for (var i = 0; i < NumTypes; i++) {
_lengths.Add(m_io.ReadU2le());
}
_padding3 = m_io.ReadBytes(KaitaiStream.Mod((4 - M_Io.Pos), 4));
_strcMagic = m_io.ReadBytes(4);
if (!((KaitaiStream.ByteArrayCompare(StrcMagic, new byte[] { 83, 84, 82, 67 }) == 0))) {
throw new ValidationNotEqualError(new byte[] { 83, 84, 82, 67 }, StrcMagic, M_Io,
"/types/dna1_body/seq/12");
}
_numStructs = m_io.ReadU4le();
_structs = new List<DnaStruct>();
for (var i = 0; i < NumStructs; i++) {
_structs.Add(new DnaStruct(m_io, this, m_root));
}
}
private byte[] _id;
private byte[] _nameMagic;
private uint _numNames;
private List<string> _names;
private byte[] _padding1;
private byte[] _typeMagic;
private uint _numTypes;
private List<string> _types;
private byte[] _padding2;
private byte[] _tlenMagic;
private List<ushort> _lengths;
private byte[] _padding3;
private byte[] _strcMagic;
private uint _numStructs;
private List<DnaStruct> _structs;
private BlenderBlend m_root;
private BlenderBlend.FileBlock m_parent;
public byte[] Id {
get { return _id; }
}
public byte[] NameMagic {
get { return _nameMagic; }
}
public uint NumNames {
get { return _numNames; }
}
public List<string> Names {
get { return _names; }
}
public byte[] Padding1 {
get { return _padding1; }
}
public byte[] TypeMagic {
get { return _typeMagic; }
}
public uint NumTypes {
get { return _numTypes; }
}
public List<string> Types {
get { return _types; }
}
public byte[] Padding2 {
get { return _padding2; }
}
public byte[] TlenMagic {
get { return _tlenMagic; }
}
public List<ushort> Lengths {
get { return _lengths; }
}
public byte[] Padding3 {
get { return _padding3; }
}
public byte[] StrcMagic {
get { return _strcMagic; }
}
public uint NumStructs {
get { return _numStructs; }
}
public List<DnaStruct> Structs {
get { return _structs; }
}
public BlenderBlend M_Root {
get { return m_root; }
}
public BlenderBlend.FileBlock M_Parent {
get { return m_parent; }
}
}
public partial class Header : KaitaiStruct {
public static Header FromFile(string fileName) {
return new Header(new KaitaiStream(fileName));
}
public Header(KaitaiStream p__io, BlenderBlend p__parent = null, BlenderBlend p__root = null) : base(p__io) {
m_parent = p__parent;
m_root = p__root;
f_psize = false;
_read();
}
private void _read() {
_magic = m_io.ReadBytes(7);
if (!((KaitaiStream.ByteArrayCompare(Magic, new byte[] { 66, 76, 69, 78, 68, 69, 82 }) == 0))) {
throw new ValidationNotEqualError(new byte[] { 66, 76, 69, 78, 68, 69, 82 }, Magic, M_Io,
"/types/header/seq/0");
}
_ptrSizeId = ((BlenderBlend.PtrSize)m_io.ReadU1());
_endian = ((BlenderBlend.Endian)m_io.ReadU1());
_version = System.Text.Encoding.GetEncoding("ASCII").GetString(m_io.ReadBytes(3));
}
private bool f_psize;
private sbyte _psize;
/// <summary>
/// Number of bytes that a pointer occupies
/// </summary>
public sbyte Psize {
get {
if (f_psize)
return _psize;
_psize = (sbyte)((PtrSizeId == BlenderBlend.PtrSize.Bits64 ? 8 : 4));
f_psize = true;
return _psize;
}
}
private byte[] _magic;
private PtrSize _ptrSizeId;
private Endian _endian;
private string _version;
private BlenderBlend m_root;
private BlenderBlend m_parent;
public byte[] Magic {
get { return _magic; }
}
/// <summary>
/// Size of a pointer; all pointers in the file are stored in this format
/// </summary>
public PtrSize PtrSizeId {
get { return _ptrSizeId; }
}
/// <summary>
/// Type of byte ordering used
/// </summary>
public Endian Endian {
get { return _endian; }
}
/// <summary>
/// Blender version used to save this file
/// </summary>
public string Version {
get { return _version; }
}
public BlenderBlend M_Root {
get { return m_root; }
}
public BlenderBlend M_Parent {
get { return m_parent; }
}
}
public partial class DnaField : KaitaiStruct {
public static DnaField FromFile(string fileName) {
return new DnaField(new KaitaiStream(fileName));
}
public DnaField(KaitaiStream p__io, BlenderBlend.DnaStruct p__parent = null, BlenderBlend p__root = null) :
base(p__io) {
m_parent = p__parent;
m_root = p__root;
f_type = false;
f_name = false;
_read();
}
private void _read() {
_idxType = m_io.ReadU2le();
_idxName = m_io.ReadU2le();
}
private bool f_type;
private string _type;
public string Type {
get {
if (f_type)
return _type;
_type = (string)(M_Parent.M_Parent.Types[IdxType]);
f_type = true;
return _type;
}
}
private bool f_name;
private string _name;
public string Name {
get {
if (f_name)
return _name;
_name = (string)(M_Parent.M_Parent.Names[IdxName]);
f_name = true;
return _name;
}
}
private ushort _idxType;
private ushort _idxName;
private BlenderBlend m_root;
private BlenderBlend.DnaStruct m_parent;
public ushort IdxType {
get { return _idxType; }
}
public ushort IdxName {
get { return _idxName; }
}
public BlenderBlend M_Root {
get { return m_root; }
}
public BlenderBlend.DnaStruct M_Parent {
get { return m_parent; }
}
}
private bool f_sdnaStructs;
private List<DnaStruct> _sdnaStructs;
public List<DnaStruct> SdnaStructs {
get {
if (f_sdnaStructs)
return _sdnaStructs;
_sdnaStructs = (List<DnaStruct>)(((BlenderBlend.Dna1Body)(Blocks[(Blocks.Count - 2)].Body)).Structs);
f_sdnaStructs = true;
return _sdnaStructs;
}
}
private Header _hdr;
private List<FileBlock> _blocks;
private BlenderBlend m_root;
private KaitaiStruct m_parent;
public Header Hdr {
get { return _hdr; }
}
public List<FileBlock> Blocks {
get { return _blocks; }
}
public BlenderBlend M_Root {
get { return m_root; }
}
public KaitaiStruct M_Parent {
get { return m_parent; }
}
}
}

View File

@@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<Nullable>disable</Nullable>
<RootNamespace>CodeGenerator</RootNamespace>
<OutputType>Exe</OutputType>
<LangVersion>9</LangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="KaitaiStruct.Runtime.CSharp" Version="0.10.0" />
<PackageReference Include="Microsoft.CodeAnalysis.Common" Version="4.12.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.12.0" />
<PackageReference Include="System.CodeDom" Version="9.0.1" />
</ItemGroup>
<ItemGroup>
<None Update="empty.blend">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

212
CodeGenerator/Program.cs Normal file
View File

@@ -0,0 +1,212 @@
using Kaitai;
using System;
using System.IO;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
using Microsoft.CSharp;
using BlendFile = Kaitai.BlenderBlend;
namespace CodeGenerator {
public static class StrExt {
public static string ParseFName(this string str) {
str = str.Replace("*", "ptr_");
return str;
}
public static string ParseFType(this string str) {
return str switch {
"char" => typeof(char).AssemblyQualifiedName,
"short" => typeof(short).AssemblyQualifiedName,
"int" => typeof(int).AssemblyQualifiedName,
"float" => typeof(float).AssemblyQualifiedName,
"double" => typeof(double).AssemblyQualifiedName,
"string" => typeof(string).AssemblyQualifiedName,
"void" => typeof(object).AssemblyQualifiedName,
_ => str
};
}
}
public class Program {
public static BlendFile blendfile;
private static StringBuilder sb = new StringBuilder();
public static void Log(string message) {
sb.AppendLine(message);
Console.WriteLine(message);
}
public static void Main(string[] args) {
Log("Reading empty.blend file");
blendfile = BlendFile.FromFile("empty.blend");
Log($"Header: Blender v{blendfile.Hdr.Version} {blendfile.Hdr.Endian}\n" +
$"DataBlocks: {blendfile.Blocks.Count}\n" +
$"DNA1: {blendfile.SdnaStructs.Count} structures\n");
Log("Generating C# code");
CodeGeneratorOptions codeGeneratorOptions = new CodeGeneratorOptions() {
BlankLinesBetweenMembers = false,
BracingStyle = "Block",
ElseOnClosing = false,
IndentString = " ",
VerbatimOrder = false
};
var provider = new CSharpCodeProvider();
//Create a new NameSpace
CodeNamespace ns = new CodeNamespace("Blender");
Log("Pass 1: Generating structs");
foreach (var type in blendfile.SdnaStructs) {
bool hasArrays = false;
Log($"Generating struct {type.Type}");
//Create a new structs
var ctd = new CodeTypeDeclaration(type.Type) { IsStruct = true };
//Add the class to the namespace
ns.Types.Add(ctd);
//Add the fields to the class
Log($"Fields: {type.Fields.Count}");
foreach (var field in type.Fields) {
CodeMemberField cmf;
string name = field.Name;
if (field.Name.Contains("[")) {
Log($"Generating array field {field.Name}");
hasArrays = true;
cmf = CreateArrayMemberField(field);
} else {
Log($"Generating field {field.Name}");
cmf = CreateMemberField(field);
}
cmf.Attributes = MemberAttributes.Public;
ctd.Members.Add(cmf);
}
Log("Generating constructor");
ctd.Members.Add(GenerateConstructor(type, ctd));
//If it has arrays, generate a static constructor for them
if (hasArrays) {
Log("Generating static constructor");
ctd.Members.Add(GenerateStaticConstructor(ctd));
}
Log("Finished generating struct");
}
using var sw = new StreamWriter("BlenderSharp.cs");
provider.GenerateCodeFromNamespace(ns, sw, codeGeneratorOptions);
Log("Finished generating C# code");
Log("Code saved to BlenderSharp.cs");
File.AppendAllText("Log.txt", sb.ToString());
}
private static CodeTypeConstructor GenerateStaticConstructor(CodeTypeDeclaration ctd) {
CodeTypeConstructor ctc = new CodeTypeConstructor();
ctc.Attributes = MemberAttributes.Static;
ctc.Statements.AddRange(ctd.Members
.OfType<CodeMemberField>()
.Where(f => f.Type.ArrayRank > 0)
.Select(f => {
var dims = new List<int>();
for (int i = 0; i < f.Type.ArrayRank; i++) {
dims.Add(0);
}
return new CodeAssignStatement(
new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), f.Name),
NewArray(f.Type, dims)
);
}).ToArray<CodeStatement>());
return ctc;
}
private static CodeConstructor GenerateConstructor(BlenderBlend.DnaStruct type, CodeTypeDeclaration ctd) {
//Create a normal constructor
CodeConstructor cc = new CodeConstructor {
Name = type.Type,
Attributes = MemberAttributes.Public,
ReturnType = new(type.Type)
};
//Add the parameters to the constructor
cc.Parameters.AddRange(ctd.Members
.OfType<CodeMemberField>()
.Select(f => {
var cpde = new CodeParameterDeclarationExpression(f.Type, f.Name);
cpde.Direction = FieldDirection.In;
return cpde;
}).ToArray());
//Assign the parameters to the respective fields
cc.Statements.AddRange(ctd.Members
.OfType<CodeMemberField>()
.Select(f => new CodeAssignStatement(
new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), f.Name),
new CodeArgumentReferenceExpression(f.Name))
).ToArray<CodeStatement>());
return cc;
}
private static CodeMemberField CreateMemberField(BlenderBlend.DnaField field) {
Type t = Type.GetType(field.Type.ParseFType());
CodeMemberField cmf;
//Check if the type is a built-in type or a custom type
if (t != null) cmf = new(t, field.Name.ParseFName()); //Built-in type
else cmf = new(new CodeTypeReference(field.Type), field.Name.ParseFName()); //Custom type
return cmf;
}
private static CodeMemberField CreateArrayMemberField(BlenderBlend.DnaField field) {
Type t = Type.GetType(field.Type.ParseFType());
CodeMemberField cmf;
// Parse all array dimensions
var dimensions = new List<int>();
var name = field.Name.ParseFName();
int startIndex = 0;
// Get all array dimensions
while ((startIndex = name.IndexOf('[', startIndex)) != -1) {
int endIndex = name.IndexOf(']', startIndex);
string sizeStr = name.Substring(startIndex + 1, endIndex - startIndex - 1);
if (int.TryParse(sizeStr, out int size)) {
dimensions.Add(size);
}
startIndex = endIndex + 1;
}
// Get clean field name (without array brackets)
name = field.Name.ParseFName().Substring(0, field.Name.IndexOf('['));
//Check if the type is a built-in type or a custom type
if (t != null) cmf = new(t, name); //Built-in type
else cmf = new(field.Type, name); //Custom type
//Define the array type
cmf.Type.ArrayElementType = new(field.Type.ParseFType() ?? field.Type);
cmf.Type.ArrayRank = dimensions.Count;
//Define the array initialization expression
cmf.InitExpression = NewArray(cmf.Type, dimensions);
return cmf;
}
public static CodeExpression NewArray (CodeTypeReference type, IEnumerable<int> dimensions) {
string dims = string.Concat(dimensions.Select(d => $"[{d}]"));
return new CodeSnippetExpression($"new {type.BaseType}{dims}");
}
}
}

BIN
CodeGenerator/empty.blend Normal file

Binary file not shown.