44using System . Text ;
55using System . Xml . Linq ;
66
7+ using SharpGLTF . Schema2 ;
8+
79namespace SharpGLTF . Runtime
810{
911 class MaterialTemplate
@@ -19,63 +21,108 @@ internal MaterialTemplate(Schema2.Material srcMaterial, RuntimeOptions options)
1921
2022 var isolateMemory = options ? . IsolateMemory ?? false ;
2123
24+ // gather animation channels targeting this material
25+
26+ _PointerPrefix = $ "/materials/{ srcMaterial . LogicalIndex } /";
27+ _IsAnimated = false ;
28+
2229 foreach ( var srcChannel in srcMaterial . Channels )
2330 {
24- var key = srcChannel . Key ;
31+ // loop over animations to find if any animation points
32+ // to a property of this material and connect the dots.
2533
26- var txform = srcChannel . TextureTransform ;
27- var scale = txform == null ? null : new AnimatableProperty < Vector2 > ( txform . Scale ) ;
28- var rotation = txform == null ? null : new AnimatableProperty < float > ( txform . Rotation ) ;
29- var offset = txform == null ? null : new AnimatableProperty < Vector2 > ( txform . Offset ) ;
30-
31- foreach ( var srcAnim in srcMaterial . LogicalParent . LogicalAnimations )
34+ foreach ( var srcTrack in srcMaterial . LogicalParent . LogicalAnimations )
3235 {
33- var lidx = srcAnim . LogicalIndex ;
34-
35- // paths look like:
36- // "/materials/14/pbrMetallicRoughness/metallicRoughnessTexture/extensions/KHR_texture_transform/scale"
36+ var trackIdx = srcTrack . LogicalIndex ;
3737
38- var pointerPath = srcChannel . GetAnimationPointer ( ) ;
38+ var channels = srcTrack . FindChannels ( _PointerPrefix ) ;
3939
40- foreach ( var c in srcAnim . FindChannels ( pointerPath ) )
40+ foreach ( var channel in channels )
4141 {
42- System . Diagnostics . Trace . WriteLine ( c . TargetPointerPath ) ;
42+ var pointerPath = channel . TargetPointerPath ;
43+ System . Diagnostics . Debug . Assert ( pointerPath . StartsWith ( _PointerPrefix ) ) ;
44+ pointerPath = pointerPath . Substring ( _PointerPrefix . Length - 1 ) ;
45+
46+ var fieldInfo = Reflection . FieldInfo . From ( srcMaterial , pointerPath ) ;
47+
48+ if ( fieldInfo . IsEmpty )
49+ {
50+ System . Diagnostics . Debug . Fail ( "If it reaches this point it's probably because it's animating a property of an unregistered extension." ) ;
51+ continue ;
52+ }
53+
54+ if ( fieldInfo . Value is float defaultSingle )
55+ {
56+ _ScalarAnimatables ??= new Dictionary < string , AnimatableProperty < float > > ( ) ;
57+ _AddAnimatableProperty ( _ScalarAnimatables , trackIdx , channel , pointerPath , defaultSingle , isolateMemory ) ;
58+ }
4359
44- if ( c . TargetPointerPath . EndsWith ( "/extensions/KHR_texture_transform/scale" ) )
60+ if ( fieldInfo . Value is Vector2 defaultVector2 )
4561 {
46- if ( scale == null ) throw new InvalidOperationException ( "found pointer to a TextureTransform, but target was not found" ) ;
47- var sampler = c . GetSamplerOrNull < Vector2 > ( ) . CreateCurveSampler ( isolateMemory ) ;
48- scale . SetCurve ( lidx , sampler ) ;
62+ _Vector2Animatables ??= new Dictionary < string , AnimatableProperty < Vector2 > > ( ) ;
63+ _AddAnimatableProperty ( _Vector2Animatables , trackIdx , channel , pointerPath , defaultVector2 , isolateMemory ) ;
4964 }
5065
51- if ( c . TargetPointerPath . EndsWith ( "/extensions/KHR_texture_transform/rotation" ) )
66+ if ( fieldInfo . Value is Vector3 defaultVector3 )
5267 {
53- if ( rotation == null ) throw new InvalidOperationException ( "found pointer to a TextureTransform, but target was not found" ) ;
54- var sampler = c . GetSamplerOrNull < float > ( ) . CreateCurveSampler ( isolateMemory ) ;
55- rotation . SetCurve ( lidx , sampler ) ;
68+ _Vector3Animatables ??= new Dictionary < string , AnimatableProperty < Vector3 > > ( ) ;
69+ _AddAnimatableProperty ( _Vector3Animatables , trackIdx , channel , pointerPath , defaultVector3 , isolateMemory ) ;
5670 }
5771
58- if ( c . TargetPointerPath . EndsWith ( "/extensions/KHR_texture_transform/offset" ) )
72+ if ( fieldInfo . Value is Vector4 defaultVector4 )
5973 {
60- if ( offset == null ) throw new InvalidOperationException ( "found pointer to a TextureTransform, but target was not found" ) ;
61- var sampler = c . GetSamplerOrNull < Vector2 > ( ) . CreateCurveSampler ( isolateMemory ) ;
62- offset . SetCurve ( lidx , sampler ) ;
74+ _Vector4Animatables ??= new Dictionary < string , AnimatableProperty < Vector4 > > ( ) ;
75+ _AddAnimatableProperty ( _Vector4Animatables , trackIdx , channel , pointerPath , defaultVector4 , isolateMemory ) ;
6376 }
64- }
77+ }
6578 }
6679 }
6780 }
6881
82+ private void _AddAnimatableProperty < T > ( Dictionary < string , AnimatableProperty < T > > dict , int trackIdx , AnimationChannel channel , string pointerPath , T defaultSingle , bool isolateMemory )
83+ where T : struct
84+ {
85+ if ( ! dict . TryGetValue ( pointerPath , out var target ) )
86+ {
87+ target = new AnimatableProperty < T > ( defaultSingle ) ;
88+ dict [ pointerPath ] = target ;
89+ }
90+
91+ var sampler = channel . GetSamplerOrNull < T > ( ) . CreateCurveSampler ( isolateMemory ) ;
92+ target . SetCurve ( trackIdx , sampler ) ;
93+
94+ _IsAnimated = true ;
95+ }
96+
6997 #endregion
7098
7199 #region data
72-
73- private readonly int _LogicalSourceIndex ;
100+
101+ private readonly int _LogicalSourceIndex ;
102+
103+ private readonly string _PointerPrefix ;
104+
105+ private readonly Dictionary < string , AnimatableProperty < float > > _ScalarAnimatables ;
106+ private readonly Dictionary < string , AnimatableProperty < Vector2 > > _Vector2Animatables ;
107+ private readonly Dictionary < string , AnimatableProperty < Vector3 > > _Vector3Animatables ;
108+ private readonly Dictionary < string , AnimatableProperty < Vector4 > > _Vector4Animatables ;
109+
110+ private bool _IsAnimated ;
74111
75112 #endregion
76113
77114 #region properties
78115
116+ /// <summary>
117+ /// If true, it means this material is animated.
118+ /// </summary>
119+ /// <remarks>
120+ /// Before rendering a model using this material, you check this property and then call
121+ /// <see cref="UpdateRuntimeMaterial(int, float, Action{string, float})"/> to update your
122+ /// engine's material properties
123+ /// </remarks>
124+ public bool IsAnimated => _IsAnimated ;
125+
79126 public string Name { get ; set ; }
80127
81128 public Object Extras { get ; set ; }
@@ -89,9 +136,41 @@ internal MaterialTemplate(Schema2.Material srcMaterial, RuntimeOptions options)
89136
90137 #region API
91138
92- public Matrix3x2 GetTextureTransform ( int trackLogicalIndex , float time )
139+
140+ public void UpdateRuntimeMaterial ( int trackLogicalIndex , float time , Action < string , float > target )
93141 {
94- throw new NotImplementedException ( ) ;
142+ foreach ( var kvp in _ScalarAnimatables )
143+ {
144+ var val = kvp . Value . GetValueAt ( trackLogicalIndex , time ) ;
145+ target . Invoke ( kvp . Key , val ) ;
146+ }
147+ }
148+
149+ public void UpdateRuntimeMaterial ( int trackLogicalIndex , float time , Action < string , Vector2 > target )
150+ {
151+ foreach ( var kvp in _Vector2Animatables )
152+ {
153+ var val = kvp . Value . GetValueAt ( trackLogicalIndex , time ) ;
154+ target . Invoke ( kvp . Key , val ) ;
155+ }
156+ }
157+
158+ public void UpdateRuntimeMaterial ( int trackLogicalIndex , float time , Action < string , Vector3 > target )
159+ {
160+ foreach ( var kvp in _Vector3Animatables )
161+ {
162+ var val = kvp . Value . GetValueAt ( trackLogicalIndex , time ) ;
163+ target . Invoke ( kvp . Key , val ) ;
164+ }
165+ }
166+
167+ public void UpdateRuntimeMaterial ( int trackLogicalIndex , float time , Action < string , Vector4 > target )
168+ {
169+ foreach ( var kvp in _Vector4Animatables )
170+ {
171+ var val = kvp . Value . GetValueAt ( trackLogicalIndex , time ) ;
172+ target . Invoke ( kvp . Key , val ) ;
173+ }
95174 }
96175
97176 #endregion
0 commit comments