Repository: McCulloughRT/Revit2glTF
Branch: master
Commit: 564515d46e55
Files: 19
Total size: 100.4 KB
Directory structure:
gitextract_qlio5x88/
├── .gitignore
├── README.md
├── glTFRevitExport/
│ ├── App.cs
│ ├── Command.cs
│ ├── Containers.cs
│ ├── GLTFManager.cs
│ ├── GlTFExportContext.cs
│ ├── Properties/
│ │ ├── AssemblyInfo.cs
│ │ ├── Resources.Designer.cs
│ │ ├── Resources.resx
│ │ ├── Settings.Designer.cs
│ │ └── Settings.settings
│ ├── Util.cs
│ ├── WPF/
│ │ ├── MainWindow.xaml
│ │ └── MainWindow.xaml.cs
│ ├── glTF.cs
│ ├── glTFRevitExport.addin
│ └── glTFRevitExport.csproj
└── glTFRevitExport.sln
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Coverlet is a free, cross platform Code Coverage Tool
coverage*[.json, .xml, .info]
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
================================================
FILE: README.md
================================================
# Revit2glTF - A Revit glTF Exporter
This is currently a work in progress but the end goal is to create an open source implementation of an extensible exporter from Autodesk Revit to the glTF model format.
## Current To-Do's
- [x] Handle basic material export
- [ ] Handle textured material export
- [ ] Handle normals export
- [ ] Add toggle for exporting each element as a seperate .bin vs a single .glb.
- [x] Add element properties to extras on glTF nodes.
- [ ] Add element properties to a sqlite file referenced by glTF nodes.
================================================
FILE: glTFRevitExport/App.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Reflection;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Autodesk.Revit.ApplicationServices;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
namespace glTFRevitExport
{
class App : IExternalApplication
{
public Result OnStartup(UIControlledApplication a)
{
string tabName = "Andersen Tools";
try
{
a.CreateRibbonTab(tabName);
}
catch (Autodesk.Revit.Exceptions.ArgumentException)
{
// Do nothing.
}
// Add a new ribbon panel
RibbonPanel newPanel = a.CreateRibbonPanel(tabName, "glTF Export");
string thisAssemblyPath = Assembly.GetExecutingAssembly().Location;
PushButtonData button1Data = new PushButtonData("command",
"GO", thisAssemblyPath, "glTFRevitExport.Command");
PushButton pushButton1 = newPanel.AddItem(button1Data) as PushButton;
pushButton1.LargeImage = BmpImageSource(@"glTFRevitExport.Embedded_Media.large.png");
///////////////////// ADD STACKED BUTTONS ////////////////////////////////////////////
//PushButtonData tagSData = new PushButtonData("sButton1",
// "Button1", thisAssemblyPath, "glTFRevitExport.class");
//PushButtonData tagLData = new PushButtonData("sButton2",
// "Button2", thisAssemblyPath, "glTFRevitExport.class");
//newPanel.AddSeparator();
//IList<RibbonItem> stackedItems = newPanel.AddStackedItems(tagSData, tagLData);
//if(stackedItems.Count>1)
//{
// PushButton tagS = stackedItems[0] as PushButton;
// tagS.Image = BmpImageSource(@"glTFRevitExport.Embedded_Media.small.png");
// PushButton tagL = stackedItems[1] as PushButton;
// tagL.Image = BmpImageSource(@"glTFRevitExport.Embedded_Media.small.png");
//}
///////////////////////////////////////////////////////////////////////////////////////////
return Result.Succeeded;
}
public Result OnShutdown(UIControlledApplication a)
{
return Result.Succeeded;
}
private ImageSource BmpImageSource(string embeddedPath)
{
System.IO.Stream manifestResourceStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(embeddedPath);
PngBitmapDecoder pngBitmapDecoder = new PngBitmapDecoder(manifestResourceStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
return pngBitmapDecoder.Frames[0];
}
}
}
================================================
FILE: glTFRevitExport/Command.cs
================================================
using System;
using System.IO;
using Autodesk.Revit.ApplicationServices;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Microsoft.Win32;
namespace glTFRevitExport
{
[Transaction(TransactionMode.Manual)]
class Command : IExternalCommand
{
public void ExportView3D(View3D view3d, string filename, string directory)
{
Document doc = view3d.Document;
// Use our custom implementation of IExportContext as the exporter context.
glTFExportContext ctx = new glTFExportContext(doc, filename, directory);
// Create a new custom exporter with the context.
CustomExporter exporter = new CustomExporter(doc, ctx);
exporter.ShouldStopOnError = true;
exporter.Export(view3d);
}
public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
{
UIApplication uiapp = commandData.Application;
UIDocument uidoc = uiapp.ActiveUIDocument;
Application app = uiapp.Application;
Document doc = uidoc.Document;
View3D view = doc.ActiveView as View3D;
if (view == null)
{
TaskDialog.Show("glTFRevitExport", "You must be in a 3D view to export.");
return Result.Failed;
}
SaveFileDialog fileDialog = new SaveFileDialog();
fileDialog.FileName = "NewProject"; // default file name
fileDialog.DefaultExt = ".gltf"; // default file extension
bool? dialogResult = fileDialog.ShowDialog();
if (dialogResult == true)
{
string filename = fileDialog.FileName;
string directory = Path.GetDirectoryName(filename) + "\\";
ExportView3D(view, filename, directory);
}
return Result.Succeeded;
}
}
}
================================================
FILE: glTFRevitExport/Containers.cs
================================================
using System;
using System.Collections.Generic;
using Autodesk.Revit.DB;
namespace glTFRevitExport
{
/// <summary>
/// Intermediate data format for
/// converting between Revit Polymesh
/// and glTF buffers.
/// </summary>
public class GeometryData
{
public VertexLookupInt vertDictionary = new VertexLookupInt();
public List<long> vertices = new List<long>();
public List<double> normals = new List<double>();
public List<double> uvs = new List<double>();
public List<int> faces = new List<int>();
}
/// <summary>
/// Container for holding a strict set of items
/// that is also addressable by a unique ID.
/// </summary>
/// <typeparam name="T">The type of item contained.</typeparam>
public class IndexedDictionary<T>
{
private Dictionary<string, int> _dict = new Dictionary<string, int>();
public List<T> List { get; } = new List<T>();
public string CurrentKey { get; private set; }
public Dictionary<string,T> Dict
{
get
{
var output = new Dictionary<string, T>();
foreach (var kvp in _dict)
{
output.Add(kvp.Key, List[kvp.Value]);
}
return output;
}
}
/// <summary>
/// The most recently accessed item (not effected by GetElement()).
/// </summary>
public T CurrentItem
{
get { return List[_dict[CurrentKey]]; }
}
/// <summary>
/// The index of the most recently accessed item (not effected by GetElement()).
/// </summary>
public int CurrentIndex
{
get { return _dict[CurrentKey]; }
}
/// <summary>
/// Add a new item to the list, if it already exists then the
/// current item will be set to this item.
/// </summary>
/// <param name="uuid">Unique identifier for the item.</param>
/// <param name="elem">The item to add.</param>
/// <returns>true if item did not already exist.</returns>
public bool AddOrUpdateCurrent(string uuid, T elem)
{
if (!_dict.ContainsKey(uuid))
{
List.Add(elem);
_dict.Add(uuid, (List.Count - 1));
CurrentKey = uuid;
return true;
}
CurrentKey = uuid;
return false;
}
/// <summary>
/// Check if the container already has an item with this key.
/// </summary>
/// <param name="uuid">Unique identifier for the item.</param>
/// <returns></returns>
public bool Contains(string uuid)
{
return _dict.ContainsKey(uuid);
}
/// <summary>
/// Returns the index for an item given it's unique identifier.
/// </summary>
/// <param name="uuid">Unique identifier for the item.</param>
/// <returns>index of item or -1</returns>
public int GetIndexFromUUID(string uuid)
{
if (!Contains(uuid)) throw new Exception("Specified item could not be found.");
return _dict[uuid];
}
/// <summary>
/// Returns an item given it's unique identifier.
/// </summary>
/// <param name="uuid">Unique identifier for the item</param>
/// <returns>the item</returns>
public T GetElement(string uuid)
{
int index = GetIndexFromUUID(uuid);
return List[index];
}
/// <summary>
/// Returns as item given it's index location.
/// </summary>
/// <param name="index">The item's index location.</param>
/// <returns>the item</returns>
public T GetElement(int index)
{
if (index < 0 || index > List.Count - 1) throw new Exception("Specified item could not be found.");
return List[index];
}
}
/// <summary>
/// From Jeremy Tammik's RvtVa3c exporter:
/// https://github.com/va3c/RvtVa3c
/// An integer-based 3D point class.
/// </summary>
public class PointInt : IComparable<PointInt>
{
public long X { get; set; }
public long Y { get; set; }
public long Z { get; set; }
/// <summary>
/// Consider a Revit length zero
/// if is smaller than this.
/// </summary>
const double _eps = 1.0e-9;
/// <summary>
/// Conversion factor from feet to millimetres.
/// </summary>
const double _feet_to_mm = 25.4 * 12;
/// <summary>
/// Conversion a given length value
/// from feet to millimetre.
/// </summary>
public static long ConvertFeetToMillimetres(double d)
{
if (0 < d)
{
return _eps > d
? 0
: (long)(_feet_to_mm * d + 0.5);
}
else
{
return _eps > -d
? 0
: (long)(_feet_to_mm * d - 0.5);
}
}
public PointInt(XYZ p, bool switch_coordinates)
{
X = ConvertFeetToMillimetres(p.X);
Y = ConvertFeetToMillimetres(p.Y);
Z = ConvertFeetToMillimetres(p.Z);
if (switch_coordinates)
{
X = -X;
long tmp = Y;
Y = Z;
Z = tmp;
}
}
public int CompareTo(PointInt a)
{
long d = X - a.X;
if (0 == d)
{
d = Y - a.Y;
if (0 == d)
{
d = Z - a.Z;
}
}
return (0 == d) ? 0 : ((0 < d) ? 1 : -1);
}
}
/// <summary>
/// From Jeremy Tammik's RvtVa3c exporter:
/// https://github.com/va3c/RvtVa3c
/// A vertex lookup class to eliminate
/// duplicate vertex definitions.
/// </summary>
public class VertexLookupInt : Dictionary<PointInt, int>
{
/// <summary>
/// Define equality for integer-based PointInt.
/// </summary>
class PointIntEqualityComparer : IEqualityComparer<PointInt>
{
public bool Equals(PointInt p, PointInt q)
{
return 0 == p.CompareTo(q);
}
public int GetHashCode(PointInt p)
{
return (p.X.ToString()
+ "," + p.Y.ToString()
+ "," + p.Z.ToString())
.GetHashCode();
}
}
public VertexLookupInt() : base(new PointIntEqualityComparer())
{
}
/// <summary>
/// Return the index of the given vertex,
/// adding a new entry if required.
/// </summary>
public int AddVertex(PointInt p)
{
return ContainsKey(p)
? this[p]
: this[p] = Count;
}
}
}
================================================
FILE: glTFRevitExport/GLTFManager.cs
================================================
using Autodesk.Revit.DB;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Security.Cryptography;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using System.Diagnostics;
namespace glTFRevitExport
{
static class ManagerUtils
{
static public List<double> ConvertXForm(Transform xform)
{
if (xform == null || xform.IsIdentity) return null;
var BasisX = xform.BasisX;
var BasisY = xform.BasisY;
var BasisZ = xform.BasisZ;
var Origin = xform.Origin;
var OriginX = PointInt.ConvertFeetToMillimetres(Origin.X);
var OriginY = PointInt.ConvertFeetToMillimetres(Origin.Y);
var OriginZ = PointInt.ConvertFeetToMillimetres(Origin.Z);
List<double> glXform = new List<double>(16) {
BasisX.X, BasisX.Y, BasisX.Z, 0,
BasisY.X, BasisY.Y, BasisY.Z, 0,
BasisZ.X, BasisZ.Y, BasisZ.Z, 0,
OriginX, OriginY, OriginZ, 1
};
return glXform;
}
public class HashSearch
{
string _S;
public HashSearch(string s)
{
_S = s;
}
public bool EqualTo(HashedType d)
{
return d.hashcode.Equals(_S);
}
}
static public string GenerateSHA256Hash<T>(T data)
{
var binFormatter = new BinaryFormatter();
var mStream = new MemoryStream();
binFormatter.Serialize(mStream, data);
using (SHA256 hasher = SHA256.Create())
{
mStream.Position = 0;
byte[] byteHash = hasher.ComputeHash(mStream);
var sBuilder = new StringBuilder();
for (int i = 0; i < byteHash.Length; i++)
{
sBuilder.Append(byteHash[i].ToString("x2"));
}
return sBuilder.ToString();
}
}
}
class GLTFManager
{
/// <summary>
/// Flag to write coords as Z up instead of Y up (if true).
/// CAUTION: With local coordinate systems and transforms, this no longer
/// produces expected results. TODO on fixing it, however there is a larger
/// philisophical debtate to be had over whether flipping coordinates in
/// source CAD applications should EVER be the correct thing to do (as opposed to
/// flipping the camera in the viewer).
/// </summary>
private bool _flipCoords = false;
/// <summary>
/// Toggles the export of JSON properties as a glTF Extras
/// object on each node.
/// </summary>
private bool _exportProperties = true;
/// <summary>
/// Stateful, uuid indexable list of all materials in the export.
/// </summary>
private IndexedDictionary<glTFMaterial> materialDict = new IndexedDictionary<glTFMaterial>();
/// <summary>
/// Dictionary of nodes keyed to their unique id.
/// </summary>
private Dictionary<string, Node> nodeDict = new Dictionary<string, Node>();
/// <summary>
/// Hashable container for mesh data, to aid instancing.
/// </summary>
private List<MeshContainer> meshContainers = new List<MeshContainer>();
/// <summary>
/// List of root nodes defining scenes.
/// </summary>
public List<glTFScene> scenes = new List<glTFScene>();
/// <summary>
/// List of all buffers referencing the binary file data.
/// </summary>
public List<glTFBuffer> buffers = new List<glTFBuffer>();
/// <summary>
/// List of all BufferViews referencing the buffers.
/// </summary>
public List<glTFBufferView> bufferViews = new List<glTFBufferView>();
/// <summary>
/// List of all Accessors referencing the BufferViews.
/// </summary>
public List<glTFAccessor> accessors = new List<glTFAccessor>();
/// <summary>
/// Container for the vertex/face/normal information
/// that will be serialized into a binary format
/// for the final *.bin files.
/// </summary>
public List<glTFBinaryData> binaryFileData = new List<glTFBinaryData>();
/// <summary>
/// Ordered list of all nodes
/// </summary>
public List<glTFNode> nodes {
get {
var list = nodeDict.Values.ToList();
return list.OrderBy(x => x.index).Select(x => x.ToGLTFNode()).ToList();
}
}
/// <summary>
/// Returns true if the unique id is already present in the list of nodes.
/// </summary>
/// <param name="uniqueId"></param>
/// <returns></returns>
public bool containsNode(string uniqueId)
{
return nodeDict.ContainsKey(uniqueId);
}
/// <summary>
/// List of all materials referenced by meshes.
/// </summary>
public List<glTFMaterial> materials {
get {
return materialDict.List;
}
}
/// <summary>
/// List of all meshes referenced by nodes.
/// </summary>
public List<glTFMesh> meshes {
get {
return meshContainers.Select(x => x.contents).ToList();
}
}
/// <summary>
/// Stack maintaining the uniqueId's of each node down
/// the current scene graph branch.
/// </summary>
private Stack<string> parentStack = new Stack<string>();
/// <summary>
/// The uniqueId of the currently open node.
/// </summary>
private string currentNodeId {
get {
return parentStack.Peek();
}
}
/// <summary>
/// Stack maintaining the geometry containers for each
/// node down the current scene graph branch. These are popped
/// as we retreat back up the graph.
/// </summary>
private Stack<Dictionary<string, GeometryData>> geometryStack = new Stack<Dictionary<string, GeometryData>>();
/// <summary>
/// The geometry container for the currently open node.
/// </summary>
private Dictionary<string, GeometryData> currentGeom {
get {
return geometryStack.Peek();
}
}
/// <summary>
/// Returns proper tab alignment for displaying element
/// hierarchy in debug printing.
/// </summary>
public string formatDebugHeirarchy
{
get
{
string spaces = "";
for (int i = 0; i < parentStack.Count; i++)
{
spaces += " ";
}
return spaces;
}
}
public void Start(bool exportProperties = true)
{
this._exportProperties = exportProperties;
Node rootNode = new Node(0);
rootNode.children = new List<int>();
nodeDict.Add(rootNode.id, rootNode);
parentStack.Push(rootNode.id);
glTFScene defaultScene = new glTFScene();
defaultScene.nodes.Add(0);
scenes.Add(defaultScene);
}
public glTFContainer Finish()
{
glTF model = new glTF();
model.asset = new glTFVersion();
model.scenes = scenes;
model.nodes = nodes;
model.meshes = meshes;
model.materials = materials;
model.buffers = buffers;
model.bufferViews = bufferViews;
model.accessors = accessors;
glTFContainer container = new glTFContainer();
container.glTF = model;
container.binaries = binaryFileData;
return container;
}
public void OpenNode(Element elem, Transform xform = null, bool isInstance = false)
{
//// TODO: [RM] Commented out because this is likely to be very buggy and not the
//// correct solution intent is to prevent creation of new nodes when a symbol
//// is a child of an instance of the same type.
//// Witness: parking spaces and stair railings for examples of two
//// different issues with the behavior
//if (isInstance == true && elem is FamilySymbol)
//{
// FamilyInstance parentInstance = nodeDict[currentNodeId].element as FamilyInstance;
// if (
// parentInstance != null &&
// parentInstance.Symbol != null &&
// elem.Name == parentInstance.Symbol.Name
// )
// {
// nodeDict[currentNodeId].matrix = ManagerUtils.ConvertXForm(xform);
// return;
// }
// //nodeDict[currentNodeId].matrix = ManagerUtils.ConvertXForm(xform);
// //return;
//}
bool exportNodeProperties = _exportProperties;
if (isInstance == true && elem is FamilySymbol) exportNodeProperties = false;
Node node = new Node(elem, nodeDict.Count, exportNodeProperties, isInstance, formatDebugHeirarchy);
if (parentStack.Count > 0)
{
string parentId = parentStack.Peek();
Node parentNode = nodeDict[parentId];
if (parentNode.children == null) parentNode.children = new List<int>();
nodeDict[parentId].children.Add(node.index);
}
parentStack.Push(node.id);
if (xform != null)
{
node.matrix = ManagerUtils.ConvertXForm(xform);
}
nodeDict.Add(node.id, node);
OpenGeometry();
Debug.WriteLine(String.Format("{0}Node Open", formatDebugHeirarchy));
}
public void CloseNode(Element elem = null, bool isInstance = false)
{
//// TODO: [RM] Commented out because this is likely to be very buggy and not the
//// correct solution intent is to prevent creation of new nodes when a symbol
//// is a child of an instance of the same type.
//// Witness: parking spaces and stair railings for examples of two
//// different issues with the behavior
//if (isInstance && elem is FamilySymbol)
//{
// FamilyInstance parentInstance = nodeDict[currentNodeId].element as FamilyInstance;
// if (
// parentInstance != null &&
// parentInstance.Symbol != null &&
// elem.Name == parentInstance.Symbol.Name
// )
// {
// return;
// }
// //return;
//}
Debug.WriteLine(String.Format("{0}Closing Node", formatDebugHeirarchy));
if (currentGeom != null)
{
CloseGeometry();
}
Debug.WriteLine(String.Format("{0} Node Closed", formatDebugHeirarchy));
parentStack.Pop();
}
public void SwitchMaterial(MaterialNode matNode, string name = null, string id = null)
{
glTFMaterial gl_mat = new glTFMaterial();
gl_mat.name = name;
glTFPBR pbr = new glTFPBR();
pbr.baseColorFactor = new List<float>() {
matNode.Color.Red / 255f,
matNode.Color.Green / 255f,
matNode.Color.Blue / 255f,
1f - (float)matNode.Transparency
};
pbr.metallicFactor = 0f;
pbr.roughnessFactor = 1f;
gl_mat.pbrMetallicRoughness = pbr;
materialDict.AddOrUpdateCurrent(id, gl_mat);
}
public void OpenGeometry()
{
geometryStack.Push(new Dictionary<string, GeometryData>());
}
public void OnGeometry(PolymeshTopology polymesh)
{
if (currentNodeId == null) throw new Exception();
string vertex_key = currentNodeId + "_" + materialDict.CurrentKey;
if (currentGeom.ContainsKey(vertex_key) == false)
{
currentGeom.Add(vertex_key, new GeometryData());
}
// Populate normals from this polymesh
IList<XYZ> norms = polymesh.GetNormals();
foreach (XYZ norm in norms)
{
currentGeom[vertex_key].normals.Add(norm.X);
currentGeom[vertex_key].normals.Add(norm.Y);
currentGeom[vertex_key].normals.Add(norm.Z);
}
// Populate vertex and faces data
IList<XYZ> pts = polymesh.GetPoints();
foreach (PolymeshFacet facet in polymesh.GetFacets())
{
int v1 = currentGeom[vertex_key].vertDictionary.AddVertex(new PointInt(pts[facet.V1], _flipCoords));
int v2 = currentGeom[vertex_key].vertDictionary.AddVertex(new PointInt(pts[facet.V2], _flipCoords));
int v3 = currentGeom[vertex_key].vertDictionary.AddVertex(new PointInt(pts[facet.V3], _flipCoords));
currentGeom[vertex_key].faces.Add(v1);
currentGeom[vertex_key].faces.Add(v2);
currentGeom[vertex_key].faces.Add(v3);
}
}
public void CloseGeometry()
{
Debug.WriteLine(String.Format("{0} Closing Geometry", formatDebugHeirarchy));
// Create the new mesh and populate the primitives with GeometryData
glTFMesh mesh = new glTFMesh();
mesh.primitives = new List<glTFMeshPrimitive>();
// transfer ordered vertices from vertex dictionary to vertices list
foreach (KeyValuePair<string,GeometryData> key_geom in currentGeom)
{
string key = key_geom.Key;
GeometryData geom = key_geom.Value;
foreach (KeyValuePair<PointInt, int> point_index in geom.vertDictionary)
{
PointInt point = point_index.Key;
geom.vertices.Add(point.X);
geom.vertices.Add(point.Y);
geom.vertices.Add(point.Z);
}
// convert GeometryData objects into glTFMeshPrimitive
string material_key = key.Split('_')[1];
glTFBinaryData bufferMeta = processGeometry(geom, key);
if (bufferMeta.hashcode != null)
{
binaryFileData.Add(bufferMeta);
}
glTFMeshPrimitive primative = new glTFMeshPrimitive();
primative.attributes.POSITION = bufferMeta.vertexAccessorIndex;
primative.indices = bufferMeta.indexAccessorIndex;
primative.material = materialDict.GetIndexFromUUID(material_key);
// TODO: Add normal attribute accessor index here
mesh.primitives.Add(primative);
}
// glTF entity can not be empty
if (mesh.primitives.Count() > 0) {
// Prevent mesh duplication by hash checking
string meshHash = ManagerUtils.GenerateSHA256Hash(mesh);
ManagerUtils.HashSearch hs = new ManagerUtils.HashSearch(meshHash);
int idx = meshContainers.FindIndex(hs.EqualTo);
if (idx != -1) {
// set the current nodes mesh index to the already
// created mesh location.
nodeDict[currentNodeId].mesh = idx;
}
else {
// create new mesh and add it's index to the current node.
MeshContainer mc = new MeshContainer();
mc.hashcode = meshHash;
mc.contents = mesh;
meshContainers.Add(mc);
nodeDict[currentNodeId].mesh = meshContainers.Count - 1;
}
}
geometryStack.Pop();
return;
}
/// <summary>
/// Takes the intermediate geometry data and performs the calculations
/// to convert that into glTF buffers, views, and accessors.
/// </summary>
/// <param name="geomData"></param>
/// <param name="name">Unique name for the .bin file that will be produced.</param>
/// <returns></returns>
private glTFBinaryData processGeometry(GeometryData geom, string name)
{
// TODO: rename this type to glTFBufferMeta ?
glTFBinaryData bufferData = new glTFBinaryData();
glTFBinaryBufferContents bufferContents = new glTFBinaryBufferContents();
foreach (var coord in geom.vertices)
{
float vFloat = Convert.ToSingle(coord);
bufferContents.vertexBuffer.Add(vFloat);
}
foreach (var index in geom.faces)
{
bufferContents.indexBuffer.Add(index);
}
// Prevent buffer duplication by hash checking
string calculatedHash = ManagerUtils.GenerateSHA256Hash(bufferContents);
ManagerUtils.HashSearch hs = new ManagerUtils.HashSearch(calculatedHash);
var match = binaryFileData.Find(hs.EqualTo);
if (match != null)
{
// return previously created buffer metadata
bufferData.vertexAccessorIndex = match.vertexAccessorIndex;
bufferData.indexAccessorIndex = match.indexAccessorIndex;
return bufferData;
}
else
{
// add a buffer
glTFBuffer buffer = new glTFBuffer();
buffer.uri = name + ".bin";
buffers.Add(buffer);
int bufferIdx = buffers.Count - 1;
/**
* Buffer Data
**/
bufferData.name = buffer.uri;
bufferData.contents = bufferContents;
// TODO: Uncomment for normals
//foreach (var normal in geomData.normals)
//{
// bufferData.normalBuffer.Add((float)normal);
//}
// Get max and min for vertex data
float[] vertexMinMax = Util.GetVec3MinMax(bufferContents.vertexBuffer);
// Get max and min for index data
int[] faceMinMax = Util.GetScalarMinMax(bufferContents.indexBuffer);
// TODO: Uncomment for normals
// Get max and min for normal data
//float[] normalMinMax = getVec3MinMax(bufferData.normalBuffer);
/**
* BufferViews
**/
// Add a vec3 buffer view
int elementsPerVertex = 3;
int bytesPerElement = 4;
int bytesPerVertex = elementsPerVertex * bytesPerElement;
int numVec3 = (geom.vertices.Count) / elementsPerVertex;
int sizeOfVec3View = numVec3 * bytesPerVertex;
glTFBufferView vec3View = new glTFBufferView();
vec3View.buffer = bufferIdx;
vec3View.byteOffset = 0;
vec3View.byteLength = sizeOfVec3View;
vec3View.target = Targets.ARRAY_BUFFER;
bufferViews.Add(vec3View);
int vec3ViewIdx = bufferViews.Count - 1;
// TODO: Add a normals (vec3) buffer view
// Add a faces / indexes buffer view
int elementsPerIndex = 1;
int bytesPerIndexElement = 4;
int bytesPerIndex = elementsPerIndex * bytesPerIndexElement;
int numIndexes = geom.faces.Count;
int sizeOfIndexView = numIndexes * bytesPerIndex;
glTFBufferView facesView = new glTFBufferView();
facesView.buffer = bufferIdx;
facesView.byteOffset = vec3View.byteLength;
facesView.byteLength = sizeOfIndexView;
facesView.target = Targets.ELEMENT_ARRAY_BUFFER;
bufferViews.Add(facesView);
int facesViewIdx = bufferViews.Count - 1;
buffers[bufferIdx].byteLength = vec3View.byteLength + facesView.byteLength;
/**
* Accessors
**/
// add a position accessor
glTFAccessor positionAccessor = new glTFAccessor();
positionAccessor.bufferView = vec3ViewIdx;
positionAccessor.byteOffset = 0;
positionAccessor.componentType = ComponentType.FLOAT;
positionAccessor.count = geom.vertices.Count / elementsPerVertex;
positionAccessor.type = "VEC3";
positionAccessor.max = new List<float>() { vertexMinMax[1], vertexMinMax[3], vertexMinMax[5] };
positionAccessor.min = new List<float>() { vertexMinMax[0], vertexMinMax[2], vertexMinMax[4] };
accessors.Add(positionAccessor);
bufferData.vertexAccessorIndex = accessors.Count - 1;
// TODO: Uncomment for normals
// add a normals accessor
//glTFAccessor normalsAccessor = new glTFAccessor();
//normalsAccessor.bufferView = vec3ViewIdx;
//normalsAccessor.byteOffset = (positionAccessor.count) * bytesPerVertex;
//normalsAccessor.componentType = ComponentType.FLOAT;
//normalsAccessor.count = geom.data.normals.Count / elementsPerVertex;
//normalsAccessor.type = "VEC3";
//normalsAccessor.max = new List<float>() { normalMinMax[1], normalMinMax[3], normalMinMax[5] };
//normalsAccessor.min = new List<float>() { normalMinMax[0], normalMinMax[2], normalMinMax[4] };
//this.accessors.Add(normalsAccessor);
//bufferData.normalsAccessorIndex = this.accessors.Count - 1;
// add a face accessor
glTFAccessor faceAccessor = new glTFAccessor();
faceAccessor.bufferView = facesViewIdx;
faceAccessor.byteOffset = 0;
faceAccessor.componentType = ComponentType.UNSIGNED_INT;
faceAccessor.count = numIndexes;
faceAccessor.type = "SCALAR";
faceAccessor.max = new List<float>() { faceMinMax[1] };
faceAccessor.min = new List<float>() { faceMinMax[0] };
accessors.Add(faceAccessor);
bufferData.indexAccessorIndex = accessors.Count - 1;
bufferData.hashcode = calculatedHash;
return bufferData;
}
}
}
class Node : glTFNode
{
public int index;
public string id;
public bool isFinalized = false;
public Element element;
public Node(Element elem, int index, bool exportProperties = true, bool isInstance = false, string heirarchyFormat = "")
{
Debug.WriteLine(String.Format("{1} Creating new node: {0}", elem, heirarchyFormat));
this.element = elem;
this.name = Util.ElementDescription(elem);
this.id = isInstance ? elem.UniqueId + "::" + Guid.NewGuid().ToString() : elem.UniqueId;
this.index = index;
Debug.WriteLine(String.Format("{1} Name:{0}", this.name, heirarchyFormat));
if (exportProperties)
{
// get the extras for this element
glTFExtras extras = new glTFExtras();
extras.UniqueId = elem.UniqueId;
//var properties = Util.GetElementProperties(elem, true);
//if (properties != null) extras.Properties = properties;
extras.Properties = Util.GetElementProperties(elem, true);
this.extras = extras;
}
Debug.WriteLine(String.Format("{0} Exported Properties", heirarchyFormat));
}
public Node(int index)
{
this.name = "::rootNode::";
this.id = System.Guid.NewGuid().ToString();
this.index = index;
}
public glTFNode ToGLTFNode()
{
glTFNode node = new glTFNode();
node.name = this.name;
node.mesh = this.mesh;
node.matrix = this.matrix;
node.extras = this.extras;
node.children = this.children;
return node;
}
}
}
================================================
FILE: glTFRevitExport/GlTFExportContext.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using Autodesk.Revit.DB;
using Newtonsoft.Json;
using System.Diagnostics;
using System.Runtime.Serialization.Formatters.Binary;
using System.Security.Cryptography;
using System.Text;
namespace glTFRevitExport
{
public class glTFExportConfigs {
/// <summary>
/// Flag to export all buffers into a single .bin file (if true).
/// </summary>
public bool SingleBinary = true;
/// <summary>
/// Flag to export all the properties for each element.
/// </summary>
public bool ExportProperties = true;
/// <summary>
/// Flag to write coords as Z up instead of Y up (if true).
/// </summary>
public bool FlipCoords = true;
/// <summary>
/// Include non-standard elements that are not part of
/// official glTF spec. If false, non-standard elements will be excluded
/// </summary>
public bool IncludeNonStdElements = true;
}
public class glTFExportContext : IExportContext
{
private glTFExportConfigs _cfgs = new glTFExportConfigs();
/// <summary>
/// The name for the export files
/// </summary>
private string _filename;
/// <summary>
/// The directory for the export files
/// </summary>
private string _directory;
private bool _skipElementFlag = false;
private GLTFManager manager = new GLTFManager();
private Stack<Document> documentStack = new Stack<Document>();
private Document _doc
{
get
{
return documentStack.Peek();
}
}
public glTFExportContext(Document doc, string filename, string directory, glTFExportConfigs configs = null)
{
documentStack.Push(doc);
// ensure filename is really a file name and no extension
_filename = Path.GetFileNameWithoutExtension(filename);
_directory = directory;
_cfgs = configs is null ? _cfgs : configs;
}
/// <summary>
/// Runs once at beginning of export. Sets up the root node
/// and scene.
/// </summary>
/// <returns></returns>
public bool Start()
{
Debug.WriteLine("Starting...");
manager.Start(_cfgs.ExportProperties);
return true;
}
/// <summary>
/// Runs once at end of export. Serializes the gltf
/// properties and wites out the *.gltf and *.bin files.
/// </summary>
public void Finish()
{
Debug.WriteLine("Finishing...");
glTFContainer container = manager.Finish();
if (_cfgs.IncludeNonStdElements) {
// TODO: [RM] Standardize what non glTF spec elements will go into
// this "BIM glTF superset" and write a spec for it. Gridlines below
// are an example.
// Add gridlines as gltf nodes in the format:
// Origin {Vec3<double>}, Direction {Vec3<double>}, Length {double}
FilteredElementCollector col = new FilteredElementCollector(_doc)
.OfClass(typeof(Grid));
var grids = col.ToElements();
foreach (Grid g in grids) {
Line l = g.Curve as Line;
var origin = l.Origin;
var direction = l.Direction;
var length = l.Length;
var xtras = new glTFExtras();
var grid = new GridParameters();
grid.origin = new List<double>() { origin.X, origin.Y, origin.Z };
grid.direction = new List<double>() { direction.X, direction.Y, direction.Z };
grid.length = length;
xtras.GridParameters = grid;
xtras.UniqueId = g.UniqueId;
xtras.Properties = Util.GetElementProperties(g, true);
var gridNode = new glTFNode();
gridNode.name = g.Name;
gridNode.extras = xtras;
container.glTF.nodes.Add(gridNode);
container.glTF.nodes[0].children.Add(container.glTF.nodes.Count - 1);
}
}
if (_cfgs.SingleBinary)
{
int bytePosition = 0;
int currentBuffer = 0;
foreach (var view in container.glTF.bufferViews)
{
if (view.buffer == 0)
{
bytePosition += view.byteLength;
continue;
}
if (view.buffer != currentBuffer)
{
view.buffer = 0;
view.byteOffset = bytePosition;
bytePosition += view.byteLength;
}
}
glTFBuffer buffer = new glTFBuffer();
buffer.uri = _filename + ".bin";
buffer.byteLength = bytePosition;
container.glTF.buffers.Clear();
container.glTF.buffers.Add(buffer);
using (FileStream f = File.Create(Path.Combine(_directory, buffer.uri)))
{
using (BinaryWriter writer = new BinaryWriter(f))
{
foreach (var bin in container.binaries)
{
foreach (var coord in bin.contents.vertexBuffer)
{
writer.Write((float)coord);
}
// TODO: add writer for normals buffer
foreach (var index in bin.contents.indexBuffer)
{
writer.Write((int)index);
}
}
}
}
}
else
{
// Write the *.bin files
foreach (var bin in container.binaries)
{
using (FileStream f = File.Create(Path.Combine(_directory, bin.name)))
{
using (BinaryWriter writer = new BinaryWriter(f))
{
foreach (var coord in bin.contents.vertexBuffer)
{
writer.Write((float)coord);
}
// TODO: add writer for normals buffer
foreach (var index in bin.contents.indexBuffer)
{
writer.Write((int)index);
}
}
}
}
}
// Write the *.gltf file
string serializedModel = JsonConvert.SerializeObject(container.glTF, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
File.WriteAllText(Path.Combine(_directory, _filename + ".gltf"), serializedModel);
}
/// <summary>
/// Runs once for each element.
/// </summary>
/// <param name="elementId">ElementId of Element being processed</param>
/// <returns></returns>
public RenderNodeAction OnElementBegin(ElementId elementId)
{
Element e = _doc.GetElement(elementId);
Debug.WriteLine(String.Format("{2}OnElementBegin: {1}-{0}", e.Name, elementId, manager.formatDebugHeirarchy));
if (manager.containsNode(e.UniqueId))
{
// Duplicate element, skip adding.
Debug.WriteLine(String.Format("{0} Duplicate Element!", manager.formatDebugHeirarchy));
_skipElementFlag = true;
return RenderNodeAction.Skip;
}
manager.OpenNode(e);
return RenderNodeAction.Proceed;
}
/// <summary>
/// Runs every time, and immediately prior to, a mesh being processed (OnPolymesh).
/// It supplies the material for the mesh, and we use this to create a new material
/// in our material container, or switch the current material if it already exists.
/// TODO: Handle more complex materials.
/// </summary>
/// <param name="node"></param>
public void OnMaterial(MaterialNode matNode)
{
Debug.WriteLine(String.Format("{0} OnMaterial", manager.formatDebugHeirarchy));
string matName;
string uniqueId;
ElementId id = matNode.MaterialId;
if (id != ElementId.InvalidElementId)
{
Element m = _doc.GetElement(matNode.MaterialId);
matName = m.Name;
uniqueId = m.UniqueId;
}
else
{
uniqueId = string.Format("r{0}g{1}b{2}", matNode.Color.Red.ToString(), matNode.Color.Green.ToString(), matNode.Color.Blue.ToString());
matName = string.Format("MaterialNode_{0}_{1}", Util.ColorToInt(matNode.Color), Util.RealString(matNode.Transparency * 100));
}
Debug.WriteLine(String.Format("{1} Material: {0}", matName, manager.formatDebugHeirarchy));
manager.SwitchMaterial(matNode, matName, uniqueId);
}
/// <summary>
/// Runs for every polymesh being processed. Typically this is a single face
/// of an element's mesh. Vertices and faces are keyed on the element/material combination
/// (this is important because within a single element, materials can be changed and
/// repeated in unknown order).
/// </summary>
/// <param name="polymesh"></param>
public void OnPolymesh(PolymeshTopology polymesh)
{
Debug.WriteLine(String.Format("{0} OnPolymesh", manager.formatDebugHeirarchy));
manager.OnGeometry(polymesh);
}
/// <summary>
/// Runs at the end of an element being processed, after all other calls for that element.
/// </summary>
/// <param name="elementId"></param>
public void OnElementEnd(ElementId elementId)
{
Debug.WriteLine(String.Format("{0}OnElementEnd", manager.formatDebugHeirarchy.Substring(0, manager.formatDebugHeirarchy.Count() - 2)));
if (_skipElementFlag)
{
_skipElementFlag = false;
return;
}
manager.CloseNode();
}
/// <summary>
/// This is called when family instances are encountered, after OnElementBegin.
/// We're using it here to maintain the transform stack for that element's heirarchy.
/// </summary>
/// <param name="node"></param>
/// <returns></returns>
public RenderNodeAction OnInstanceBegin(InstanceNode node)
{
Debug.WriteLine(String.Format("{0}OnInstanceBegin", manager.formatDebugHeirarchy));
ElementId symId = node.GetSymbolId();
Element symElem = _doc.GetElement(symId);
Debug.WriteLine(String.Format("{2}OnInstanceBegin: {0}-{1}", symId, symElem.Name, manager.formatDebugHeirarchy));
var nodeXform = node.GetTransform();
manager.OpenNode(symElem, nodeXform.IsIdentity ? null : nodeXform, true);
return RenderNodeAction.Proceed;
}
/// <summary>
/// This is called when family instances are encountered, before OnElementEnd.
/// We're using it here to maintain the transform stack for that element's heirarchy.
/// </summary>
/// <param name="node"></param>
public void OnInstanceEnd(InstanceNode node)
{
Debug.WriteLine(String.Format("{0}OnInstanceEnd", manager.formatDebugHeirarchy.Substring(0,manager.formatDebugHeirarchy.Count() - 2)));
ElementId symId = node.GetSymbolId();
Element symElem = _doc.GetElement(symId);
manager.CloseNode(symElem, true);
}
public bool IsCanceled()
{
// This method is invoked many times during the export process.
return false;
}
public RenderNodeAction OnViewBegin(ViewNode node)
{
// TODO: we could use this to handle multiple scenes in the gltf file.
return RenderNodeAction.Proceed;
}
public void OnViewEnd(ElementId elementId)
{
// do nothing
}
public RenderNodeAction OnLinkBegin(LinkNode node)
{
ElementId symId = node.GetSymbolId();
Element symElem = _doc.GetElement(symId);
Debug.WriteLine(String.Format("{2}OnLinkBegin: {0}-{1}", symId, symElem.Name, manager.formatDebugHeirarchy));
var nodeXform = node.GetTransform();
manager.OpenNode(symElem, nodeXform.IsIdentity ? null : nodeXform, true);
documentStack.Push(node.GetDocument());
return RenderNodeAction.Proceed;
}
public void OnLinkEnd(LinkNode node)
{
Debug.WriteLine(String.Format("{0}OnLinkEnd", manager.formatDebugHeirarchy.Substring(0, manager.formatDebugHeirarchy.Count() - 2)));
manager.CloseNode();
documentStack.Pop();
}
public RenderNodeAction OnFaceBegin(FaceNode node)
{
return RenderNodeAction.Proceed;
}
public void OnFaceEnd(FaceNode node)
{
// This method is invoked only if the
// custom exporter was set to include faces.
}
public void OnRPC(RPCNode node)
{
// do nothing
}
public void OnLight(LightNode node)
{
// do nothing
}
}
}
================================================
FILE: glTFRevitExport/Properties/AssemblyInfo.cs
================================================
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("glTFRevitExport")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("glTFRevitExport")]
[assembly: AssemblyCopyright("Copyright © 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
//In order to begin building localizable applications, set
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
//inside a <PropertyGroup>. For example, if you are using US english
//in your source files, set the <UICulture> to en-US. Then uncomment
//the NeutralResourceLanguage attribute below. Update the "en-US" in
//the line below to match the UICulture setting in the project file.
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
================================================
FILE: glTFRevitExport/Properties/Resources.Designer.cs
================================================
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.34209
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace glTFRevitExport.Properties
{
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources
{
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources()
{
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager
{
get
{
if ((resourceMan == null))
{
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("glTFRevitExport.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture
{
get
{
return resourceCulture;
}
set
{
resourceCulture = value;
}
}
}
}
================================================
FILE: glTFRevitExport/Properties/Resources.resx
================================================
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
================================================
FILE: glTFRevitExport/Properties/Settings.Designer.cs
================================================
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.34209
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace glTFRevitExport.Properties
{
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
{
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default
{
get
{
return defaultInstance;
}
}
}
}
================================================
FILE: glTFRevitExport/Properties/Settings.settings
================================================
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>
================================================
FILE: glTFRevitExport/Util.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using Autodesk.Revit.DB;
namespace glTFRevitExport
{
class Util
{
public static int[] GetVec3MinMax(List<int> vec3)
{
int minVertexX = int.MaxValue;
int minVertexY = int.MaxValue;
int minVertexZ = int.MaxValue;
int maxVertexX = int.MinValue;
int maxVertexY = int.MinValue;
int maxVertexZ = int.MinValue;
for (int i = 0; i < vec3.Count; i += 3)
{
if (vec3[i] < minVertexX) minVertexX = vec3[i];
if (vec3[i] > maxVertexX) maxVertexX = vec3[i];
if (vec3[i + 1] < minVertexY) minVertexY = vec3[i + 1];
if (vec3[i + 1] > maxVertexY) maxVertexY = vec3[i + 1];
if (vec3[i + 2] < minVertexZ) minVertexZ = vec3[i + 2];
if (vec3[i + 2] > maxVertexZ) maxVertexZ = vec3[i + 2];
}
return new int[] { minVertexX, maxVertexX, minVertexY, maxVertexY, minVertexZ, maxVertexZ };
}
public static long[] GetVec3MinMax(List<long> vec3)
{
long minVertexX = long.MaxValue;
long minVertexY = long.MaxValue;
long minVertexZ = long.MaxValue;
long maxVertexX = long.MinValue;
long maxVertexY = long.MinValue;
long maxVertexZ = long.MinValue;
for (int i = 0; i < (vec3.Count / 3); i += 3)
{
if (vec3[i] < minVertexX) minVertexX = vec3[i];
if (vec3[i] > maxVertexX) maxVertexX = vec3[i];
if (vec3[i + 1] < minVertexY) minVertexY = vec3[i + 1];
if (vec3[i + 1] > maxVertexY) maxVertexY = vec3[i + 1];
if (vec3[i + 2] < minVertexZ) minVertexZ = vec3[i + 2];
if (vec3[i + 2] > maxVertexZ) maxVertexZ = vec3[i + 2];
}
return new long[] { minVertexX, maxVertexX, minVertexY, maxVertexY, minVertexZ, maxVertexZ };
}
public static float[] GetVec3MinMax(List<float> vec3)
{
List<float> xValues = new List<float>();
List<float> yValues = new List<float>();
List<float> zValues = new List<float>();
for (int i = 0; i < vec3.Count; i++)
{
if ((i % 3) == 0) xValues.Add(vec3[i]);
if ((i % 3) == 1) yValues.Add(vec3[i]);
if ((i % 3) == 2) zValues.Add(vec3[i]);
}
float maxX = xValues.Max();
float minX = xValues.Min();
float maxY = yValues.Max();
float minY = yValues.Min();
float maxZ = zValues.Max();
float minZ = zValues.Min();
return new float[] { minX, maxX, minY, maxY, minZ, maxZ };
}
public static int[] GetScalarMinMax(List<int> scalars)
{
int minFaceIndex = int.MaxValue;
int maxFaceIndex = int.MinValue;
for (int i = 0; i < scalars.Count; i++)
{
int currentMin = Math.Min(minFaceIndex, scalars[i]);
if (currentMin < minFaceIndex) minFaceIndex = currentMin;
int currentMax = Math.Max(maxFaceIndex, scalars[i]);
if (currentMax > maxFaceIndex) maxFaceIndex = currentMax;
}
return new int[] { minFaceIndex, maxFaceIndex };
}
/// <summary>
/// From Jeremy Tammik's RvtVa3c exporter:
/// https://github.com/va3c/RvtVa3c
/// Return a string for a real number
/// formatted to two decimal places.
/// </summary>
public static string RealString(double a)
{
return a.ToString("0.##");
}
/// <summary>
/// From Jeremy Tammik's RvtVa3c exporter:
/// https://github.com/va3c/RvtVa3c
/// Return a string for an XYZ point
/// or vector with its coordinates
/// formatted to two decimal places.
/// </summary>
public static string PointString(XYZ p)
{
return string.Format("({0},{1},{2})",
RealString(p.X),
RealString(p.Y),
RealString(p.Z));
}
/// <summary>
/// From Jeremy Tammik's RvtVa3c exporter:
/// https://github.com/va3c/RvtVa3c
/// Return an integer value for a Revit Color.
/// </summary>
public static int ColorToInt(Color color)
{
return ((int)color.Red) << 16
| ((int)color.Green) << 8
| (int)color.Blue;
}
/// <summary>
/// From Jeremy Tammik's RvtVa3c exporter:
/// https://github.com/va3c/RvtVa3c
/// Extract a true or false value from the given
/// string, accepting yes/no, Y/N, true/false, T/F
/// and 1/0. We are extremely tolerant, i.e., any
/// value starting with one of the characters y, n,
/// t or f is also accepted. Return false if no
/// valid Boolean value can be extracted.
/// </summary>
public static bool GetTrueOrFalse(string s, out bool val)
{
val = false;
if (s.Equals(Boolean.TrueString,
StringComparison.OrdinalIgnoreCase))
{
val = true;
return true;
}
if (s.Equals(Boolean.FalseString,
StringComparison.OrdinalIgnoreCase))
{
return true;
}
if (s.Equals("1"))
{
val = true;
return true;
}
if (s.Equals("0"))
{
return true;
}
s = s.ToLower();
if ('t' == s[0] || 'y' == s[0])
{
val = true;
return true;
}
if ('f' == s[0] || 'n' == s[0])
{
return true;
}
return false;
}
/// <summary>
/// From Jeremy Tammik's RvtVa3c exporter:
/// https://github.com/va3c/RvtVa3c
/// Return a string describing the given element:
/// .NET type name,
/// category name,
/// family and symbol name for a family instance,
/// element id and element name.
/// </summary>
public static string ElementDescription(Element e)
{
if (null == e)
{
return "<null>";
}
// For a wall, the element name equals the
// wall type name, which is equivalent to the
// family name ...
FamilyInstance fi = e as FamilyInstance;
string typeName = e.GetType().Name;
string categoryName = (null == e.Category)
? string.Empty
: e.Category.Name + " ";
string familyName = (null == fi)
? string.Empty
: fi.Symbol.Family.Name + " ";
string symbolName = (null == fi
|| e.Name.Equals(fi.Symbol.Name))
? string.Empty
: fi.Symbol.Name + " ";
return string.Format("{0} {1}{2}{3}<{4} {5}>",
typeName, categoryName, familyName,
symbolName, e.Id.IntegerValue, e.Name);
}
/// <summary>
/// From Jeremy Tammik's RvtVa3c exporter:
/// https://github.com/va3c/RvtVa3c
/// Return a dictionary of all the given
/// element parameter names and values.
/// </summary>
public static Dictionary<string, string> GetElementProperties(Element e, bool includeType)
{
IList<Parameter> parameters
= e.GetOrderedParameters();
Dictionary<string, string> a = new Dictionary<string, string>(parameters.Count);
// Add element category
if (e.Category != null)
{
a.Add("Element Category", e.Category.Name);
}
foreach (Parameter p in parameters)
{
string key = p.Definition.Name;
if (!a.ContainsKey(key))
{
string val;
if (StorageType.String == p.StorageType)
{
val = p.AsString();
}
else
{
val = p.AsValueString();
}
if (!string.IsNullOrEmpty(val))
{
a.Add(key, val);
}
}
}
if (includeType)
{
ElementId idType = e.GetTypeId();
if (idType != null && ElementId.InvalidElementId != idType)
{
Document doc = e.Document;
Element typ = doc.GetElement(idType);
parameters = typ.GetOrderedParameters();
foreach (Parameter p in parameters)
{
string key = "Type " + p.Definition.Name;
if (!a.ContainsKey(key))
{
string val;
if (StorageType.String == p.StorageType)
{
val = p.AsString();
}
else
{
val = p.AsValueString();
}
if (!string.IsNullOrEmpty(val))
{
a.Add(key, val);
}
}
}
}
}
if (a.Count == 0) return null;
else return a;
}
}
}
================================================
FILE: glTFRevitExport/WPF/MainWindow.xaml
================================================
<Window x:Class="glTFRevitExport.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" Background="#FFF0EFEE">
<Grid>
<Button x:Name="btnOk" Content="OK" HorizontalAlignment="Left" Margin="432,288,0,0" VerticalAlignment="Top" Width="75"/>
</Grid>
</Window>
================================================
FILE: glTFRevitExport/WPF/MainWindow.xaml.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Autodesk.Revit.ApplicationServices;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
namespace glTFRevitExport
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow(Document doc)
{
InitializeComponent();
WindowStartupLocation = System.Windows.WindowStartupLocation.CenterScreen;
btnOk.Click += (sender, e) => btnOk_Click(sender, e, doc);
}
private void btnOk_Click(object sender, RoutedEventArgs e, Document doc)
{
Close();
}
}
}
================================================
FILE: glTFRevitExport/glTF.cs
================================================
using System;
using System.Collections.Generic;
namespace glTFRevitExport
{
/// <summary>
/// Magic numbers to differentiate scalar and vector
/// array buffers.
/// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#buffers-and-buffer-views
/// </summary>
public enum Targets
{
ARRAY_BUFFER = 34962, // signals vertex data
ELEMENT_ARRAY_BUFFER = 34963 // signals index or face data
}
/// <summary>
/// Magic numbers to differentiate array buffer component
/// types.
/// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#accessor-element-size
/// </summary>
public enum ComponentType
{
BYTE = 5120,
UNSIGNED_BYTE = 5121,
SHORT = 5122,
UNSIGNED_SHORT = 5123,
UNSIGNED_INT = 5125,
FLOAT = 5126
}
public struct glTFContainer
{
public glTF glTF;
public List<glTFBinaryData> binaries;
}
/// <summary>
/// The json serializable glTF file format.
/// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0
/// </summary>
public struct glTF
{
public glTFVersion asset;
public List<glTFScene> scenes;
public List<glTFNode> nodes;
public List<glTFMesh> meshes;
public List<glTFBuffer> buffers;
public List<glTFBufferView> bufferViews;
public List<glTFAccessor> accessors;
public List<glTFMaterial> materials;
}
/// <summary>
/// A binary data store serialized to a *.bin file
/// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#binary-data-storage
/// </summary>
public class glTFBinaryData : HashedType
{
public glTFBinaryBufferContents contents { get; set; }
//public List<float> vertexBuffer { get; set; } = new List<float>();
//public List<int> indexBuffer { get; set; } = new List<int>();
//public List<float> normalBuffer { get; set; } = new List<float>();
public int vertexAccessorIndex { get; set; }
public int indexAccessorIndex { get; set; }
//public int normalsAccessorIndex { get; set; }
public string name { get; set; }
//public string hashcode { get; set; }
}
[Serializable]
public class glTFBinaryBufferContents
{
public List<float> vertexBuffer { get; set; } = new List<float>();
public List<int> indexBuffer { get; set; } = new List<int>();
}
/// <summary>
/// Required glTF asset information
/// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#asset
/// </summary>
public class glTFVersion
{
public string version = "2.0";
}
/// <summary>
/// The scenes available to render.
/// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#scenes
/// </summary>
public class glTFScene
{
public List<int> nodes = new List<int>();
}
/// <summary>
/// The nodes defining individual (or nested) elements in the scene.
/// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#nodes-and-hierarchy
/// </summary>
public class glTFNode
{
/// <summary>
/// The user-defined name of this object
/// </summary>
public string name { get; set; }
/// <summary>
/// The index of the mesh in this node.
/// </summary>
public int? mesh { get; set; } = null;
/// <summary>
/// A floating-point 4x4 transformation matrix stored in column major order.
/// </summary>
public List<double> matrix { get; set; }
/// <summary>
/// The indices of this node's children.
/// </summary>
public List<int> children { get; set; }
/// <summary>
/// The extras describing this node.
/// </summary>
public glTFExtras extras { get; set; }
}
public class HashedType
{
public string hashcode { get; set; }
}
public class MeshContainer : HashedType
{
//public string hashcode { get; set; }
public glTFMesh contents { get; set; }
}
/// <summary>
/// The array of primitives defining the mesh of an object.
/// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#meshes
/// </summary>
[Serializable]
public class glTFMesh
{
public List<glTFMeshPrimitive> primitives { get; set; }
}
/// <summary>
/// Properties defining where the GPU should look to find the mesh and material data.
/// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#meshes
/// </summary>
[Serializable]
public class glTFMeshPrimitive
{
public glTFAttribute attributes { get; set; } = new glTFAttribute();
public int indices { get; set; }
public int? material { get; set; } = null;
public int mode { get; set; } = 4; // 4 is triangles
}
/// <summary>
/// The glTF PBR Material format.
/// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#materials
/// </summary>
public class glTFMaterial
{
public string name { get; set; }
public glTFPBR pbrMetallicRoughness { get; set; }
}
public class glTFPBR
{
public List<float> baseColorFactor { get; set; }
public float metallicFactor { get; set; }
public float roughnessFactor { get; set; }
}
/// <summary>
/// The list of accessors available to the renderer for a particular mesh.
/// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#meshes
/// </summary>
[Serializable]
public class glTFAttribute
{
/// <summary>
/// The index of the accessor for position data.
/// </summary>
public int POSITION { get; set; }
//public int NORMAL { get; set; }
}
/// <summary>
/// A reference to the location and size of binary data.
/// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#buffers-and-buffer-views
/// </summary>
public class glTFBuffer
{
/// <summary>
/// The uri of the buffer.
/// </summary>
public string uri { get; set; }
/// <summary>
/// The total byte length of the buffer.
/// </summary>
public int byteLength { get; set; }
}
/// <summary>
/// A reference to a subsection of a buffer containing either vector or scalar data.
/// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#buffers-and-buffer-views
/// </summary>
public class glTFBufferView
{
/// <summary>
/// The index of the buffer.
/// </summary>
public int buffer { get; set; }
/// <summary>
/// The offset into the buffer in bytes.
/// </summary>
public int byteOffset { get; set; }
/// <summary>
/// The length of the bufferView in bytes.
/// </summary>
public int byteLength { get; set; }
/// <summary>
/// The target that the GPU buffer should be bound to.
/// </summary>
public Targets target { get; set; }
/// <summary>
/// A user defined name for this view.
/// </summary>
public string name { get; set; }
}
/// <summary>
/// A reference to a subsection of a BufferView containing a particular data type.
/// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#accessors
/// </summary>
public class glTFAccessor
{
/// <summary>
/// The index of the bufferView.
/// </summary>
public int bufferView { get; set; }
/// <summary>
/// The offset relative to the start of the bufferView in bytes.
/// </summary>
public int byteOffset { get; set; }
/// <summary>
/// the datatype of the components in the attribute
/// </summary>
public ComponentType componentType { get; set; }
/// <summary>
/// The number of attributes referenced by this accessor.
/// </summary>
public int count { get; set; }
/// <summary>
/// Specifies if the attribute is a scalar, vector, or matrix
/// </summary>
public string type { get; set; }
/// <summary>
/// Maximum value of each component in this attribute.
/// </summary>
public List<float> max { get; set; }
/// <summary>
/// Minimum value of each component in this attribute.
/// </summary>
public List<float> min { get; set; }
/// <summary>
/// A user defined name for this accessor.
/// </summary>
public string name { get; set; }
}
public class glTFExtras
{
/// <summary>
/// The Revit created UniqueId for this object
/// </summary>
public string UniqueId { get; set; }
public GridParameters GridParameters { get; set; }
public Dictionary<string, string> Properties { get; set; }
}
public class GridParameters
{
public List<double> origin { get; set; }
public List<double> direction { get; set; }
public double length { get; set; }
}
//public class glTFFunctions
//{
// public static glTFBinaryData getMeshData(glTFNode node, glTF gltf)
// {
// if(node.mesh.HasValue)
// {
// glTFMesh mesh = gltf.meshes[node.mesh.Value];
// mesh.
// }
// }
//}
}
================================================
FILE: glTFRevitExport/glTFRevitExport.addin
================================================
<?xml version="1.0" encoding="utf-8"?>
<RevitAddIns>
<AddIn Type="Command">
<Text>Command glTFRevitExport</Text>
<Description>Some description for glTFRevitExport</Description>
<Assembly>glTFRevitExport.dll</Assembly>
<FullClassName>glTFRevitExport.Command</FullClassName>
<ClientId>38555A79-E66E-49B6-8278-191F17E931B2</ClientId>
<VendorId>_RTM</VendorId>
<VendorDescription>Ryan T. McCullough</VendorDescription>
</AddIn>
<AddIn Type="Application">
<Name>Application glTFRevitExport</Name>
<Assembly>glTFRevitExport.dll</Assembly>
<FullClassName>glTFRevitExport.App</FullClassName>
<ClientId>DBBCC867-53D7-4B55-A620-88637AD9CC7E</ClientId>
<VendorId>_RTM</VendorId>
<VendorDescription>Ryan T. McCullough</VendorDescription>
</AddIn>
</RevitAddIns>
================================================
FILE: glTFRevitExport/glTFRevitExport.csproj
================================================
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{4E089540-E5C0-45D9-BB33-3CBA0E4373B5}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>glTFRevitExport</RootNamespace>
<AssemblyName>glTFRevitExport</AssemblyName>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WarningLevel>4</WarningLevel>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition="$(Configuration.Contains('2017'))">
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<RevitVersion>2017</RevitVersion>
</PropertyGroup>
<PropertyGroup Condition="$(Configuration.Contains('2018'))">
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
<RevitVersion>2018</RevitVersion>
</PropertyGroup>
<PropertyGroup Condition="$(Configuration.Contains('2019'))">
<TargetFrameworkVersion>v4.7</TargetFrameworkVersion>
<RevitVersion>2019</RevitVersion>
</PropertyGroup>
<PropertyGroup Condition="$(Configuration.Contains('2020'))">
<TargetFrameworkVersion>v4.7</TargetFrameworkVersion>
<RevitVersion>2020</RevitVersion>
</PropertyGroup>
<PropertyGroup Condition="$(Configuration.Contains('2021'))">
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<RevitVersion>2021</RevitVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug2017|x64'">
<OutputPath>bin\Debug2017\</OutputPath>
<DebugSymbols>true</DebugSymbols>
<Optimize>false</Optimize>
<DefineConstants>TRACE;DEBUG;REVIT2017</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug2018|x64'">
<OutputPath>bin\Debug2018\</OutputPath>
<DebugSymbols>true</DebugSymbols>
<Optimize>false</Optimize>
<DefineConstants>TRACE;DEBUG;REVIT2018</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug2019|x64'">
<OutputPath>bin\Debug2019\</OutputPath>
<DebugSymbols>true</DebugSymbols>
<Optimize>false</Optimize>
<DefineConstants>TRACE;DEBUG;REVIT2019</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug2020|x64'">
<OutputPath>bin\Debug2020\</OutputPath>
<DebugSymbols>true</DebugSymbols>
<Optimize>false</Optimize>
<DefineConstants>TRACE;DEBUG;REVIT2020</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug2021|x64'">
<OutputPath>bin\Debug2021\</OutputPath>
<DebugSymbols>true</DebugSymbols>
<Optimize>false</Optimize>
<DefineConstants>TRACE;DEBUG;REVIT2021</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release2017|x64'">
<OutputPath>bin\Release2017\</OutputPath>
<Optimize>true</Optimize>
<DefineConstants>REVIT2017</DefineConstants>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release2018|x64'">
<OutputPath>bin\Release2018\</OutputPath>
<Optimize>true</Optimize>
<DefineConstants>REVIT2018</DefineConstants>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release2019|x64'">
<OutputPath>bin\Release2019\</OutputPath>
<Optimize>true</Optimize>
<DefineConstants>REVIT2019</DefineConstants>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release2020|x64'">
<OutputPath>bin\Release2020\</OutputPath>
<Optimize>true</Optimize>
<DefineConstants>REVIT2020</DefineConstants>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release2021|x64'">
<OutputPath>bin\Release2021\</OutputPath>
<Optimize>true</Optimize>
<DefineConstants>REVIT2021</DefineConstants>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<StartupObject />
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Web.Extensions" />
<Reference Include="System.Xml" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Xaml">
<RequiredTargetFramework>4.0</RequiredTargetFramework>
</Reference>
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
</ItemGroup>
<ItemGroup>
<Page Include="WPF\MainWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Compile Include="App.cs" />
<Compile Include="Command.cs" />
<Compile Include="glTF.cs" />
<Compile Include="GlTFExportContext.cs" />
<Compile Include="Containers.cs" />
<Compile Include="GLTFManager.cs" />
<Compile Include="Util.cs" />
<Compile Include="WPF\MainWindow.xaml.cs">
<DependentUpon>MainWindow.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<AppDesigner Include="Properties\" />
</ItemGroup>
<ItemGroup>
<Content Include="glTFRevitExport.addin">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<EmbeddedResource Include="Embedded Media\small.png" />
<EmbeddedResource Include="Embedded Media\large.png" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json">
<Version>12.0.3</Version>
</PackageReference>
<PackageReference Include="Revit_All_Main_Versions_API_x64" Version="$(RevitVersion).0.0" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
================================================
FILE: glTFRevitExport.sln
================================================
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30320.27
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "glTFRevitExport", "glTFRevitExport\glTFRevitExport.csproj", "{4E089540-E5C0-45D9-BB33-3CBA0E4373B5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug2017|Any CPU = Debug2017|Any CPU
Debug2018|Any CPU = Debug2018|Any CPU
Debug2019|Any CPU = Debug2019|Any CPU
Debug2020|Any CPU = Debug2020|Any CPU
Debug2021|Any CPU = Debug2021|Any CPU
Release2017|Any CPU = Release2017|Any CPU
Release2018|Any CPU = Release2018|Any CPU
Release2019|Any CPU = Release2019|Any CPU
Release2020|Any CPU = Release2020|Any CPU
Release2021|Any CPU = Release2021|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{4E089540-E5C0-45D9-BB33-3CBA0E4373B5}.Debug2017|Any CPU.ActiveCfg = Debug2017|x64
{4E089540-E5C0-45D9-BB33-3CBA0E4373B5}.Debug2018|Any CPU.ActiveCfg = Debug2018|x64
{4E089540-E5C0-45D9-BB33-3CBA0E4373B5}.Debug2019|Any CPU.ActiveCfg = Debug2019|x64
{4E089540-E5C0-45D9-BB33-3CBA0E4373B5}.Debug2020|Any CPU.ActiveCfg = Debug2020|x64
{4E089540-E5C0-45D9-BB33-3CBA0E4373B5}.Debug2021|Any CPU.ActiveCfg = Debug2021|x64
{4E089540-E5C0-45D9-BB33-3CBA0E4373B5}.Release2017|Any CPU.ActiveCfg = Release2017|x64
{4E089540-E5C0-45D9-BB33-3CBA0E4373B5}.Release2018|Any CPU.ActiveCfg = Release2018|x64
{4E089540-E5C0-45D9-BB33-3CBA0E4373B5}.Release2019|Any CPU.ActiveCfg = Release2019|x64
{4E089540-E5C0-45D9-BB33-3CBA0E4373B5}.Release2020|Any CPU.ActiveCfg = Release2020|x64
{4E089540-E5C0-45D9-BB33-3CBA0E4373B5}.Release2021|Any CPU.ActiveCfg = Release2021|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {3549B740-9439-4093-BF66-9FCF49742047}
EndGlobalSection
EndGlobal
gitextract_qlio5x88/ ├── .gitignore ├── README.md ├── glTFRevitExport/ │ ├── App.cs │ ├── Command.cs │ ├── Containers.cs │ ├── GLTFManager.cs │ ├── GlTFExportContext.cs │ ├── Properties/ │ │ ├── AssemblyInfo.cs │ │ ├── Resources.Designer.cs │ │ ├── Resources.resx │ │ ├── Settings.Designer.cs │ │ └── Settings.settings │ ├── Util.cs │ ├── WPF/ │ │ ├── MainWindow.xaml │ │ └── MainWindow.xaml.cs │ ├── glTF.cs │ ├── glTFRevitExport.addin │ └── glTFRevitExport.csproj └── glTFRevitExport.sln
SYMBOL INDEX (103 symbols across 10 files)
FILE: glTFRevitExport/App.cs
class App (line 18) | class App : IExternalApplication
method OnStartup (line 20) | public Result OnStartup(UIControlledApplication a)
method OnShutdown (line 62) | public Result OnShutdown(UIControlledApplication a)
method BmpImageSource (line 67) | private ImageSource BmpImageSource(string embeddedPath)
FILE: glTFRevitExport/Command.cs
class Command (line 11) | [Transaction(TransactionMode.Manual)]
method ExportView3D (line 14) | public void ExportView3D(View3D view3d, string filename, string direct...
method Execute (line 27) | public Result Execute(ExternalCommandData commandData, ref string mess...
FILE: glTFRevitExport/Containers.cs
class GeometryData (line 12) | public class GeometryData
class IndexedDictionary (line 26) | public class IndexedDictionary<T>
method AddOrUpdateCurrent (line 67) | public bool AddOrUpdateCurrent(string uuid, T elem)
method Contains (line 86) | public bool Contains(string uuid)
method GetIndexFromUUID (line 96) | public int GetIndexFromUUID(string uuid)
method GetElement (line 107) | public T GetElement(string uuid)
method GetElement (line 118) | public T GetElement(int index)
class PointInt (line 130) | public class PointInt : IComparable<PointInt>
method ConvertFeetToMillimetres (line 151) | public static long ConvertFeetToMillimetres(double d)
method PointInt (line 167) | public PointInt(XYZ p, bool switch_coordinates)
method CompareTo (line 182) | public int CompareTo(PointInt a)
class VertexLookupInt (line 203) | public class VertexLookupInt : Dictionary<PointInt, int>
class PointIntEqualityComparer (line 208) | class PointIntEqualityComparer : IEqualityComparer<PointInt>
method Equals (line 210) | public bool Equals(PointInt p, PointInt q)
method GetHashCode (line 215) | public int GetHashCode(PointInt p)
method VertexLookupInt (line 224) | public VertexLookupInt() : base(new PointIntEqualityComparer())
method AddVertex (line 232) | public int AddVertex(PointInt p)
FILE: glTFRevitExport/GLTFManager.cs
class ManagerUtils (line 14) | static class ManagerUtils
method ConvertXForm (line 16) | static public List<double> ConvertXForm(Transform xform)
class HashSearch (line 38) | public class HashSearch
method HashSearch (line 41) | public HashSearch(string s)
method EqualTo (line 45) | public bool EqualTo(HashedType d)
method GenerateSHA256Hash (line 51) | static public string GenerateSHA256Hash<T>(T data)
class GLTFManager (line 73) | class GLTFManager
method containsNode (line 142) | public bool containsNode(string uniqueId)
method Start (line 211) | public void Start(bool exportProperties = true)
method Finish (line 225) | public glTFContainer Finish()
method OpenNode (line 244) | public void OpenNode(Element elem, Transform xform = null, bool isInst...
method CloseNode (line 292) | public void CloseNode(Element elem = null, bool isInstance = false)
method SwitchMaterial (line 324) | public void SwitchMaterial(MaterialNode matNode, string name = null, s...
method OpenGeometry (line 343) | public void OpenGeometry()
method OnGeometry (line 348) | public void OnGeometry(PolymeshTopology polymesh)
method CloseGeometry (line 381) | public void CloseGeometry()
method processGeometry (line 454) | private glTFBinaryData processGeometry(GeometryData geom, string name)
class Node (line 591) | class Node : glTFNode
method Node (line 598) | public Node(Element elem, int index, bool exportProperties = true, boo...
method Node (line 621) | public Node(int index)
method ToGLTFNode (line 628) | public glTFNode ToGLTFNode()
FILE: glTFRevitExport/GlTFExportContext.cs
class glTFExportConfigs (line 14) | public class glTFExportConfigs {
class glTFExportContext (line 37) | public class glTFExportContext : IExportContext
method glTFExportContext (line 63) | public glTFExportContext(Document doc, string filename, string directo...
method Start (line 78) | public bool Start()
method Finish (line 89) | public void Finish()
method OnElementBegin (line 209) | public RenderNodeAction OnElementBegin(ElementId elementId)
method OnMaterial (line 234) | public void OnMaterial(MaterialNode matNode)
method OnPolymesh (line 264) | public void OnPolymesh(PolymeshTopology polymesh)
method OnElementEnd (line 274) | public void OnElementEnd(ElementId elementId)
method OnInstanceBegin (line 292) | public RenderNodeAction OnInstanceBegin(InstanceNode node)
method OnInstanceEnd (line 312) | public void OnInstanceEnd(InstanceNode node)
method IsCanceled (line 322) | public bool IsCanceled()
method OnViewBegin (line 328) | public RenderNodeAction OnViewBegin(ViewNode node)
method OnViewEnd (line 334) | public void OnViewEnd(ElementId elementId)
method OnLinkBegin (line 339) | public RenderNodeAction OnLinkBegin(LinkNode node)
method OnLinkEnd (line 353) | public void OnLinkEnd(LinkNode node)
method OnFaceBegin (line 361) | public RenderNodeAction OnFaceBegin(FaceNode node)
method OnFaceEnd (line 366) | public void OnFaceEnd(FaceNode node)
method OnRPC (line 372) | public void OnRPC(RPCNode node)
method OnLight (line 377) | public void OnLight(LightNode node)
FILE: glTFRevitExport/Properties/Resources.Designer.cs
class Resources (line 22) | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resource...
method Resources (line 32) | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Mic...
FILE: glTFRevitExport/Properties/Settings.Designer.cs
class Settings (line 15) | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
FILE: glTFRevitExport/Util.cs
class Util (line 8) | class Util
method GetVec3MinMax (line 10) | public static int[] GetVec3MinMax(List<int> vec3)
method GetVec3MinMax (line 32) | public static long[] GetVec3MinMax(List<long> vec3)
method GetVec3MinMax (line 54) | public static float[] GetVec3MinMax(List<float> vec3)
method GetScalarMinMax (line 77) | public static int[] GetScalarMinMax(List<int> scalars)
method RealString (line 98) | public static string RealString(double a)
method PointString (line 110) | public static string PointString(XYZ p)
method ColorToInt (line 123) | public static int ColorToInt(Color color)
method GetTrueOrFalse (line 140) | public static bool GetTrueOrFalse(string s, out bool val)
method ElementDescription (line 187) | public static string ElementDescription(Element e)
method GetElementProperties (line 226) | public static Dictionary<string, string> GetElementProperties(Element ...
FILE: glTFRevitExport/WPF/MainWindow.xaml.cs
class MainWindow (line 26) | public partial class MainWindow : Window
method MainWindow (line 28) | public MainWindow(Document doc)
method btnOk_Click (line 35) | private void btnOk_Click(object sender, RoutedEventArgs e, Document doc)
FILE: glTFRevitExport/glTF.cs
type Targets (line 11) | public enum Targets
type ComponentType (line 22) | public enum ComponentType
type glTFContainer (line 32) | public struct glTFContainer
type glTF (line 42) | public struct glTF
class glTFBinaryData (line 58) | public class glTFBinaryData : HashedType
class glTFBinaryBufferContents (line 71) | [Serializable]
class glTFVersion (line 82) | public class glTFVersion
class glTFScene (line 91) | public class glTFScene
class glTFNode (line 100) | public class glTFNode
class HashedType (line 124) | public class HashedType
class MeshContainer (line 129) | public class MeshContainer : HashedType
class glTFMesh (line 139) | [Serializable]
class glTFMeshPrimitive (line 149) | [Serializable]
class glTFMaterial (line 162) | public class glTFMaterial
class glTFPBR (line 167) | public class glTFPBR
class glTFAttribute (line 178) | [Serializable]
class glTFBuffer (line 192) | public class glTFBuffer
class glTFBufferView (line 208) | public class glTFBufferView
class glTFAccessor (line 236) | public class glTFAccessor
class glTFExtras (line 272) | public class glTFExtras
class GridParameters (line 282) | public class GridParameters
Condensed preview — 19 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (108K chars).
[
{
"path": ".gitignore",
"chars": 6088,
"preview": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n##\n## G"
},
{
"path": "README.md",
"chars": 534,
"preview": "# Revit2glTF - A Revit glTF Exporter\nThis is currently a work in progress but the end goal is to create an open source i"
},
{
"path": "glTFRevitExport/App.cs",
"chars": 2915,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\nusi"
},
{
"path": "glTFRevitExport/Command.cs",
"chars": 1963,
"preview": "using System;\nusing System.IO;\nusing Autodesk.Revit.ApplicationServices;\nusing Autodesk.Revit.Attributes;\nusing Autodes"
},
{
"path": "glTFRevitExport/Containers.cs",
"chars": 7136,
"preview": "using System;\nusing System.Collections.Generic;\nusing Autodesk.Revit.DB;\n\nnamespace glTFRevitExport\n{\n /// <summary>"
},
{
"path": "glTFRevitExport/GLTFManager.cs",
"chars": 25026,
"preview": "using Autodesk.Revit.DB;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing Sy"
},
{
"path": "glTFRevitExport/GlTFExportContext.cs",
"chars": 14181,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.IO;\nusing Autodesk.Revit.DB;\nusing Newt"
},
{
"path": "glTFRevitExport/Properties/AssemblyInfo.cs",
"chars": 2386,
"preview": "using System.Reflection;\nusing System.Resources;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropSer"
},
{
"path": "glTFRevitExport/Properties/Resources.Designer.cs",
"chars": 2787,
"preview": "//------------------------------------------------------------------------------\n// <auto-generated>\n// This code w"
},
{
"path": "glTFRevitExport/Properties/Resources.resx",
"chars": 5494,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n <!-- \n Microsoft ResX Schema \n \n Version 2.0\n \n The prim"
},
{
"path": "glTFRevitExport/Properties/Settings.Designer.cs",
"chars": 1070,
"preview": "//------------------------------------------------------------------------------\n// <auto-generated>\n// This code w"
},
{
"path": "glTFRevitExport/Properties/Settings.settings",
"chars": 193,
"preview": "<?xml version='1.0' encoding='utf-8'?>\n<SettingsFile xmlns=\"uri:settings\" CurrentProfile=\"(Default)\">\n <Profiles>\n "
},
{
"path": "glTFRevitExport/Util.cs",
"chars": 10035,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Autodesk.Revit.DB;\n\nnamespace glTFRevitExport\n"
},
{
"path": "glTFRevitExport/WPF/MainWindow.xaml",
"chars": 422,
"preview": "<Window x:Class=\"glTFRevitExport.MainWindow\"\n xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n"
},
{
"path": "glTFRevitExport/WPF/MainWindow.xaml.cs",
"chars": 1090,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\nusi"
},
{
"path": "glTFRevitExport/glTF.cs",
"chars": 9679,
"preview": "using System;\nusing System.Collections.Generic;\n\nnamespace glTFRevitExport\n{\n /// <summary>\n /// Magic numbers to"
},
{
"path": "glTFRevitExport/glTFRevitExport.addin",
"chars": 811,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RevitAddIns>\n <AddIn Type=\"Command\">\n <Text>Command glTFRevitExport</Text>\n"
},
{
"path": "glTFRevitExport/glTFRevitExport.csproj",
"chars": 8965,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project ToolsVersion=\"12.0\" DefaultTargets=\"Build\" xmlns=\"http://schemas.micro"
},
{
"path": "glTFRevitExport.sln",
"chars": 2056,
"preview": "\r\nMicrosoft Visual Studio Solution File, Format Version 12.00\r\n# Visual Studio Version 16\r\nVisualStudioVersion = 16.0.3"
}
]
About this extraction
This page contains the full source code of the McCulloughRT/Revit2glTF GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 19 files (100.4 KB), approximately 23.7k tokens, and a symbol index with 103 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.