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