| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162 |
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using Microsoft.Xna.Framework;
- using Microsoft.Xna.Framework.Graphics;
- using SharpGLTF.Schema2;
- namespace SharpGLTF.Runtime
- {
- // tracks all the disposable objects of a model;
- // vertex buffers, index buffers, effects and textures.
- class GraphicsResourceTracker
- {
- #region data
- private readonly List<GraphicsResource> _Disposables = new List<GraphicsResource>();
- #endregion
- #region properties
- public IReadOnlyList<GraphicsResource> Disposables => _Disposables;
- #endregion
- #region API
- public void AddDisposable(GraphicsResource resource)
- {
- if (resource == null) throw new ArgumentNullException();
- if (_Disposables.Contains(resource)) throw new ArgumentException();
- _Disposables.Add(resource);
- }
- #endregion
- }
- class TextureFactory
- {
- #region lifecycle
- public TextureFactory(GraphicsDevice device, GraphicsResourceTracker disposables)
- {
- _Device = device;
- _Disposables = disposables;
- }
- #endregion
- #region data
- private readonly GraphicsDevice _Device;
- private readonly GraphicsResourceTracker _Disposables;
- private readonly Dictionary<Memory.MemoryImage, Texture2D> _Textures = new Dictionary<Memory.MemoryImage, Texture2D>();
- #endregion
- #region API
- public Texture2D UseTexture(Memory.MemoryImage image, string name = null)
- {
- if (_Device == null) throw new InvalidOperationException();
- if (!image.IsValid) return null;
- if (_Textures.TryGetValue(image, out Texture2D tex)) return tex;
- using (var m = image.Open())
- {
- tex = Texture2D.FromStream(_Device, m);
- _Disposables.AddDisposable(tex);
- tex.Name = name;
- _Textures[image] = tex;
- return tex;
- }
- }
- public Texture2D UseWhiteImage()
- {
- const string solidWhitePNg = "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAACXBIWXMAAA7DAAAOwwHHb6hkAAAAFHpUWHRUaXRsZQAACJkrz8gsSQUABoACIippo0oAAAAoelRYdEF1dGhvcgAACJkLy0xOzStJVQhIzUtMSS1WcCzKTc1Lzy8BAG89CQyAoFAQAAAAGklEQVQoz2P8//8/AymAiYFEMKphVMPQ0QAAVW0DHZ8uFaIAAAAASUVORK5CYII=";
- var toBytes = Convert.FromBase64String(solidWhitePNg);
- return UseTexture(new ArraySegment<byte>(toBytes), "_InternalSolidWhite");
- }
- #endregion
- }
- class EffectsFactory
- {
- #region lifecycle
- public EffectsFactory(GraphicsDevice device, GraphicsResourceTracker disposables)
- {
- _Device = device;
- _TexFactory = new TextureFactory(device, disposables);
- _Disposables = disposables;
- }
- #endregion
- #region data
- private readonly GraphicsDevice _Device;
- private readonly TextureFactory _TexFactory;
- private readonly GraphicsResourceTracker _Disposables;
- private readonly Dictionary<Object, Effect> _RigidEffects = new Dictionary<Object, Effect>();
- private readonly Dictionary<Object, SkinnedEffect> _SkinnedEffects = new Dictionary<Object, SkinnedEffect>();
-
- #endregion
- #region API - Schema
- public void Register(Object key, bool isSkinned, Effect effect)
- {
- if (key == null) throw new ArgumentNullException(nameof(key));
- if (effect == null) throw new ArgumentNullException(nameof(effect));
- if (isSkinned && effect is SkinnedEffect skEffect) { _SkinnedEffects[key] = skEffect; }
- else { _RigidEffects[key] = effect; }
- }
- public Effect GetMaterial(Schema2.Material srcMaterial, bool isSkinned)
- {
- if (isSkinned)
- {
- if (_SkinnedEffects.TryGetValue(srcMaterial, out SkinnedEffect dstMaterial)) return dstMaterial;
- }
- else
- {
- if (_RigidEffects.TryGetValue(srcMaterial, out Effect dstMaterial)) return dstMaterial;
- }
- return null;
- }
- internal Texture2D UseTexture(MaterialChannel? channel, string name)
- {
- if (!channel.HasValue) return _TexFactory.UseWhiteImage();
- if (channel.HasValue && name == null)
- {
- name = channel.Value.LogicalParent.Name;
- if (name == null) name = "null";
- name += $"-{channel.Value.Key}";
- }
- return _TexFactory.UseTexture(channel.Value.Texture?.PrimaryImage?.Content ?? default, name);
- }
- #endregion
- }
- }
|