Skip to content

Instantly share code, notes, and snippets.

@cdiggins
Last active May 5, 2020 01:37
Show Gist options
  • Save cdiggins/7ff0db8ead17ca3df5c6ff59bb50b686 to your computer and use it in GitHub Desktop.
Save cdiggins/7ff0db8ead17ca3df5c6ff59bb50b686 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEngine;
public static class VimApi
{
/// <summary>
/// Represents a node in a VIM scene and provides access to useful information about the object associated with that node.
/// </summary>
public class VimNode
{
public VimDocument Document { get; }
public string CategoryName { get; }
public string FamilyName { get; }
public string ElementName { get; }
public string SourceFileName { get; }
public string Room { get; }
public string Level { get; }
public List<string> MaterialNames { get; }
}
/// <summary>
/// Represents a collection of VIM nodes, and provides a wrapper around the VIM document.
/// </summary>
public class VimDocument
{
public IReadOnlyList<VimNode> Nodes { get; }
public string RootSourceFileName { get; }
}
/// <summary>
/// A simple progress reporting interface with supporting utility functions and default implementations.
/// The numerical value may be in the 0..1 range to represent percentage, or some other custom range (e.g number of bytes).
/// The progress implementation may be connected to a progress bar, or logging mechanism.
/// </summary>
public interface IProgress
{
void Report(decimal x);
}
/// <summary>
/// The different types of log messages
/// </summary>
public enum LogEnum
{
Error = 0,
Assert = 1,
Warning = 2,
Log = 3,
Exception = 4
}
/// <summary>
/// A simple logging interface with supporting utility functions and default implementations.
/// </summary>
public interface ILogger
{
void Log(string msg, LogEnum type = LogEnum.Log);
}
/// <summary>
/// Combines a Cancelation event obersver (CancellationToken) and a cancelation requester (CancelTokenSource).
/// Intentionally merging two very closely related concerns that rarely have advantage in being separated.
/// https://stackoverflow.com/questions/14215784/why-cancellationtoken-is-separate-from-cancellationtokensource
/// https://docs.microsoft.com/en-us/dotnet/api/system.threading.cancellationtoken?view=netstandard-2.1
/// https://docs.microsoft.com/en-us/dotnet/api/system.threading.cancellationtokensource?view=netstandard-2.1
/// </summary>
public interface ICancelable
{
bool IsCancelRequested();
void Cancel();
}
/// <summary>
/// For convenience this combines the chores of allowing long taks to be cancelled, to report progress,
/// and to log status. See the Helper class for a function that will generate a default logger.
/// </summary>
public interface ICancelableProgressLogger : ICancelable, ILogger, IProgress
{ }
/// <summary>
/// A class containing the different configuration options for driving the VIM loader
/// </summary>
public class LoadVimOptions
{
public bool LoadTextures = false;
}
/// <summary>
/// Loads a VIM document into memory from a string file path or URI.
/// </summary>
public static async VimDocument LoadVim(
string filePathOrUri,
LoadVimOptions options = null,
ICancelableProgressLogger logger = null)
{
throw new NotImplementedException();
}
/// <summary>
/// Loads a VIM document into memory from a stream. The stream must support reading of the `Position`
/// property, which means that it does not work with NetworkStream. In this case you can copy to
/// a MemoryStream https://stackoverflow.com/a/11749081/184528 or save it to file first.
/// </summary>
public static async VimDocument LoadVim(
Stream stream,
LoadVimOptions options = null,
ICancelableProgressLogger logger = null)
{
throw new NotImplementedException();
}
/// <summary>
/// A group of settings for creating game objects
/// </summary>
public class CreateGameObjectOptions
{
public bool CreateColliders = false;
public bool CreateCameras = false;
}
/// <summary>
/// Creates or more Unity game objects from a VIM scene.
/// The behavior is configured via functions, that can be omitted, in which reasonable defaults are provided.
/// Game objects may be created from a custom mapping of VIM nodes to object (e.g. all to one, many to one, one to one).
/// The groupKeySelector is used to select a string from the VimNode that will be used for grouping purposes.
/// This is similar in design to `Enumerable.GroupBy`.
/// This function will yield GameObjects as they are created to be consumed by the client.
/// Each GameObject will have a MeshFilter, a MeshRenderer, and add an initialized VimComponent
/// to each object. The parent will be the first class returned.
/// See the Helpers class for functions which make it easier to create a groupKeySlector.
/// In the future this will support mesh splitting options.
/// </summary>
public static async IEnumerable<GameObject> CreateGameObjects(
this VimDocument vim,
CreateGameObjectOptions options = null,
GameObject parent = null,
Func<VimNode, string> groupKeySelector = null,
Func<VimNode, IReadOnlyList<Material>> materialSelector = null,
ICancelableProgressLogger logger = null)
{
throw new NotImplementedException();
}
/// <summary>
/// By default this class is added to every game object and it provides acces to the Vim nodes
/// Basically it is a collection of nodes, all from the same document.
/// It will eventually provide a number of utility functions
/// </summary>
public class VimNodeComponent : MonoBehaviour
{
public IReadOnlyList<VimNode> Nodes { get; set; }
public VimDocumentComponent DocumentComponent { get; set; }
}
/// <summary>
/// This class is added to the root node of the Vim hierarchy and provides access to the document.
/// </summary>
public class VimDocumentComponent : MonoBehaviour
{
public VimDocument Document { get; set; }
public IEnumerable<VimNodeComponent> NodeComponents
=> FindObjectsOfType<VimNodeComponent>().Where(x => x.DocumentComponent == this);
}
/// <summary>
/// This class is returned after a hit test is performed on a VIM document
/// </summary>
public class HitTestInfo
{
public VimNode Node;
public int FaceId;
public float Distance;
public Vector2 UV;
public Vector3 NormalAtHit;
public Vector3 LocationInWorldSpace;
}
/// <summary>
/// Given X, Y screen coordinates and an optional camera, computes a hit test on the VIM document.
/// Returning null if failing.
/// </summary>
public static HitTestInfo HitTest(VimDocument doc, int x, int y, Camera camera = null)
{
throw new NotImplementedException();
}
/// <summary>
/// Given a ray in world space and an optional camera, computes a hit test on the VIM document.
/// Returning null if failing.
/// </summary>
public static HitTestInfo HitTest(VimDocument doc, Ray ray, Camera camera = null)
{
throw new NotImplementedException();
}
/// <summary>
/// These are helper functions provided with the API that facilitate using it.
/// </summary>
public static class Helpers
{
/// <summary>
/// Default implementation of a cancelable progress logger. This will
/// return a version appropriate for use in the editor and the run-time
/// with slightly different characteristics.
/// </summary>
public static ICancelableProgressLogger CreateCancelableProgressLogger()
{
throw new NotImplementedException();
}
#region Helper functions for creating key grouping functions
public static Func<VimNode, string> GroupByCategorySelector()
=> x => x?.CategoryName ?? "no category";
public static Func<VimNode, string> GroupAllSelector()
=> x => "";
public static Func<VimNode, string> GroupByElementSelector()
=> x => x?.ElementName;
public static Func<VimNode, string> GroupByFamilySelector()
=> x => x?.FamilyName ?? "no family";
public static Func<VimNode, string> GroupByFirstMaterialSelector()
=> x => (x?.MaterialNames?.Count ?? 0) > 0 ? x.MaterialNames[0] : "no material";
public static Func<VimNode, string> GroupNoneSelector()
=> null;
#endregion
/// <summary>
/// This will return a simple object factory that may or may not create mesh colliders,
/// </summary>
public static Func<VimNode, IReadOnlyList<Material>> DefaultMaterialSelector(IDictionary<string, Material> createdMaterials)
{
throw new NotImplementedException();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment