Base files
This commit is contained in:
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
bin/
|
||||
obj/
|
||||
/packages/
|
||||
riderModule.iml
|
||||
/_ReSharper.Caches/
|
||||
13
.idea/.idea.BlenderSharp/.idea/.gitignore
generated
vendored
Normal file
13
.idea/.idea.BlenderSharp/.idea/.gitignore
generated
vendored
Normal 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
|
||||
8
.idea/.idea.BlenderSharp/.idea/indexLayout.xml
generated
Normal file
8
.idea/.idea.BlenderSharp/.idea/indexLayout.xml
generated
Normal 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
6
.idea/.idea.BlenderSharp/.idea/vcs.xml
generated
Normal 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>
|
||||
9
BlendTypes/BlendTypes.csproj
Normal file
9
BlendTypes/BlendTypes.csproj
Normal 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
22
BlenderSharp.sln
Normal 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
|
||||
575
CodeGenerator/BlenderBlend.cs
Normal file
575
CodeGenerator/BlenderBlend.cs
Normal 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 "Structure DNA", 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 "names" (strings which represent field names)
|
||||
/// * a sequence of "types" (strings which represent type name)
|
||||
/// * a sequence of "type lengths"
|
||||
/// * a sequence of "structs" (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; }
|
||||
}
|
||||
}
|
||||
}
|
||||
24
CodeGenerator/CodeGenerator.csproj
Normal file
24
CodeGenerator/CodeGenerator.csproj
Normal 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
212
CodeGenerator/Program.cs
Normal 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
BIN
CodeGenerator/empty.blend
Normal file
Binary file not shown.
Reference in New Issue
Block a user