From b18a84c29daceb0916033d564d636333a67304ac Mon Sep 17 00:00:00 2001 From: TonyMax Date: Wed, 7 Jun 2023 11:34:34 +0300 Subject: [PATCH] Refactor authoring workflow (#4) > **Breaking changes** * One of the major changes is **splitting current authorings** to independent from each other monobehaviours which using **modules** to bake and author specific data. You can read more in Authoring section. This was made because new features which want to be included to baking process are hard to combine in regular class inheritance. While `MonoBehaviour`s already are responsible for assigning data from inspector they should bake data and be flexible enough to be base class for arbitrary use. From now I recommend construct regular `MonoBehaviour` class and use authoring modules inside it as fields in any combination you want. * `Size` in authorings no longer contains final value. From now this value used as multiplier. So final size of a sprite (which is `Scale2D` component) calculated as `Sprite.GetSize() * authoringTransformScale * Size. This frees authoring class from maintain size value while user change sprite or do another actions which require size update. * Authorings no longer breaks **Dependency Inversion** principal and don't contain any unnecessary members for baking purposes. * All fields in authorings are now public. * Add `bool IsValid()` method to bunch of types to improve baking process. * Improve sorting layer assigning through inspector by using `[SortingLayer]` attribute. --- About/2DTransform.md | 2 +- About/Animation.md | 6 +- About/AuthoringWorkflow.md | 66 +++++++ ...ring.md.meta => AuthoringWorkflow.md.meta} | 0 .../NSprites-Foundation-Authoring.drawio.svg | 4 + ...rites-Foundation-Authoring.drawio.svg.meta | 7 + About/RenderDataAuthoring.md | 14 -- .../Authoring/AnimationAuthoringModule.cs | 43 +++++ .../AnimationAuthoringModule.cs.meta | 3 + Animation/Authoring/BakerExtensions.cs | 81 ++++++++ Animation/Authoring/BakerExtensions.cs.meta | 3 + .../SpriteAnimatedRendererAuthoring.cs | 51 +++++ ...> SpriteAnimatedRendererAuthoring.cs.meta} | 0 .../Authoring/SpriteAnimationAuthoring.cs | 163 ---------------- Animation/Data/SpriteAnimation.cs | 2 + Animation/Data/SpriteAnimationSet.cs | 24 +++ Base/Authoring/FullScreenSpriteAuthoring.cs | 2 +- Base/Authoring/Modules.meta | 3 + Base/Authoring/Modules/BakerExtensions.cs | 57 ++++++ .../Authoring/Modules/BakerExtensions.cs.meta | 3 + .../Modules/RegisterSpriteAuthoringModule.cs | 85 +++++++++ .../RegisterSpriteAuthoringModule.cs.meta | 3 + .../Modules/SpriteSettingsAuthoringModule.cs | 83 +++++++++ .../SpriteSettingsAuthoringModule.cs.meta | 3 + Base/Authoring/SpriteRendererAuthoring.cs | 174 ++---------------- Base/Authoring/SpriteRendererAuthoringBase.cs | 33 ---- .../SpriteRendererAuthoringBase.cs.meta | 11 -- Base/Common/Bounds2D.cs | 18 +- Base/Common/Utils.cs | 10 + Base/Common/Utils.cs.meta | 3 + README.md | 4 +- Sorting/Attributes.meta | 3 + Sorting/Attributes/SortingLayerAttribute.cs | 6 + .../Attributes/SortingLayerAttribute.cs.meta | 3 + Sorting/Authoring.meta | 3 + Sorting/Authoring/Modules.meta | 3 + Sorting/Authoring/Modules/BakerExtensions.cs | 28 +++ .../Authoring/Modules/BakerExtensions.cs.meta | 3 + .../Modules/SortingAuthoringModule.cs | 29 +++ .../Modules/SortingAuthoringModule.cs.meta | 3 + Sorting/Editor.meta | 3 + Sorting/Editor/SortingLayerPropertyDrawer.cs | 34 ++++ .../Editor/SortingLayerPropertyDrawer.cs.meta | 3 + Sorting/Systems/SpriteSortingSystem.cs | 1 + package.json | 2 +- 45 files changed, 699 insertions(+), 386 deletions(-) create mode 100644 About/AuthoringWorkflow.md rename About/{RenderDataAuthoring.md.meta => AuthoringWorkflow.md.meta} (100%) create mode 100644 About/NSprites-Foundation-Authoring.drawio.svg create mode 100644 About/NSprites-Foundation-Authoring.drawio.svg.meta delete mode 100644 About/RenderDataAuthoring.md create mode 100644 Animation/Authoring/AnimationAuthoringModule.cs create mode 100644 Animation/Authoring/AnimationAuthoringModule.cs.meta create mode 100644 Animation/Authoring/BakerExtensions.cs create mode 100644 Animation/Authoring/BakerExtensions.cs.meta create mode 100644 Animation/Authoring/SpriteAnimatedRendererAuthoring.cs rename Animation/Authoring/{SpriteAnimationAuthoring.cs.meta => SpriteAnimatedRendererAuthoring.cs.meta} (100%) delete mode 100644 Animation/Authoring/SpriteAnimationAuthoring.cs create mode 100644 Base/Authoring/Modules.meta create mode 100644 Base/Authoring/Modules/BakerExtensions.cs create mode 100644 Base/Authoring/Modules/BakerExtensions.cs.meta create mode 100644 Base/Authoring/Modules/RegisterSpriteAuthoringModule.cs create mode 100644 Base/Authoring/Modules/RegisterSpriteAuthoringModule.cs.meta create mode 100644 Base/Authoring/Modules/SpriteSettingsAuthoringModule.cs create mode 100644 Base/Authoring/Modules/SpriteSettingsAuthoringModule.cs.meta delete mode 100644 Base/Authoring/SpriteRendererAuthoringBase.cs delete mode 100644 Base/Authoring/SpriteRendererAuthoringBase.cs.meta create mode 100644 Base/Common/Utils.cs create mode 100644 Base/Common/Utils.cs.meta create mode 100644 Sorting/Attributes.meta create mode 100644 Sorting/Attributes/SortingLayerAttribute.cs create mode 100644 Sorting/Attributes/SortingLayerAttribute.cs.meta create mode 100644 Sorting/Authoring.meta create mode 100644 Sorting/Authoring/Modules.meta create mode 100644 Sorting/Authoring/Modules/BakerExtensions.cs create mode 100644 Sorting/Authoring/Modules/BakerExtensions.cs.meta create mode 100644 Sorting/Authoring/Modules/SortingAuthoringModule.cs create mode 100644 Sorting/Authoring/Modules/SortingAuthoringModule.cs.meta create mode 100644 Sorting/Editor.meta create mode 100644 Sorting/Editor/SortingLayerPropertyDrawer.cs create mode 100644 Sorting/Editor/SortingLayerPropertyDrawer.cs.meta diff --git a/About/2DTransform.md b/About/2DTransform.md index f8c7b0a..9d20cce 100644 --- a/About/2DTransform.md +++ b/About/2DTransform.md @@ -2,4 +2,4 @@ Provides similar to `Unity.Transforms` 2D implementation of local / world position and parent / child relationship. Contains components / systems / authoring. Also provides a way to remove default 3D transform components from baking. -Existing of this part doesn't mean that NSprites only renders 2D, but for 2D needs we don't want to have unnecessary data. \ No newline at end of file +> **Existing of this part doesn't mean that NSprites only renders 2D, but for 2D needs we don't want to have unnecessary data.** \ No newline at end of file diff --git a/About/Animation.md b/About/Animation.md index 763dd87..dae5dbe 100644 --- a/About/Animation.md +++ b/About/Animation.md @@ -8,12 +8,12 @@ All animation data lives in provided `ScriptableObject`s (mentioned below). In baking phase it bakes all immutable animation data into blob (see `SpriteAnimationAuthoring`). Then in runtime it changes `UVAtlas` component value over time to perform flipbook animation. -## [`SpriteAnimationAuthoring`](https://github.com/Antoshidza/NSprites-Foundation/blob/main/Animation/Authoring/SpriteAnimationAuthoring.cs) -Inherited from [`SpriteRenderAuthoring`](https://github.com/Antoshidza/NSprites-Foundation/blob/main/Base/Authoring/SpriteRendererAuthoring.cs) it also bakes all needed animation data provided as [`SpriteAnimationSet`](https://github.com/Antoshidza/NSprites-Foundation/blob/main/Animation/Data/SpriteAnimationSet.cs). +## [`SpriteAnimatedRendererAuthoring`](../Animation/Authoring/SpriteAnimatedRendererAuthoring.cs) +Inherited from [`SpriteRenderAuthoring`](/Base/Authoring/SpriteRendererAuthoring.cs) it also bakes all needed animation data provided as [`SpriteAnimationSet`](/Animation/Data/SpriteAnimationSet.cs). If you want to implement your own authoring you can still use static methods provided by this class to perform same baking. ## Prepare assets -To work with animation part you need to create [`SpriteAnimationSet`](https://github.com/Antoshidza/NSprites-Foundation/blob/main/Animation/Data/SpriteAnimationSet.cs) and bunch of [`SpriteAnimation`](https://github.com/Antoshidza/NSprites-Foundation/blob/main/Animation/Data/SpriteAnimation.cs). +To work with animation part you need to create [`SpriteAnimationSet`](/Animation/Data/SpriteAnimationSet.cs) and bunch of [`SpriteAnimation`](/Animation/Data/SpriteAnimation.cs). You can create them like most of `ScriptableObjects` by calling context menu in project and selecting `Create/NSprites/Animation Set` / `Create/Nsprites/Animation (sprite sequence)`. ### `SpriteAnimation` diff --git a/About/AuthoringWorkflow.md b/About/AuthoringWorkflow.md new file mode 100644 index 0000000..6ed6a73 --- /dev/null +++ b/About/AuthoringWorkflow.md @@ -0,0 +1,66 @@ +# Authoring workflow +This package provides flexible authoring possibilities to serve your purposes. + +### Regular **Authorings** +The most simple way is to use ready monobehaviour authorings from this package. +Those authorings gives you all data assigning you need to render sprites withing pipeline of this package. + +* [`SpriteRendererAuthoring`](../Base/Authoring/SpriteRendererAuthoring.cs) - bakes default render components. Adds [2D transform](2DTransform.md) components / removes unity default 3D transforms / adds sorting components. +* [`SpriteAnimatedRendererAuthoring`](../Animation/Authoring/SpriteAnimatedRendererAuthoring.cs) - same as previous, but also adds animation related components. Though not inherited from previous one (because it hard to keep all in place when you deal with unity serialization) + +### Modules +However you may want to implement your own register system or your own shader or some other components, I can never know. +So you may want to use authorings partially, for example you want to use only sorting bake part, +then you can use **Authoring Modules** which is just serialized types with `Bake()` method. +So you can use [`SortingAuthoringModule`](/Sorting/Authoring/Modules/SortingAuthoringModule.cs) +and other modules as a field in your custom authoring `MonoBehaviour` class and call `Bake()` in `Baker` like +```csharp +public class FooAuthoring : MonoBehaviour +{ + private class Baker : Baker + { + public void override Bake(FooAuthoring authoring) + { + aithoring.Sorting.Bake(this); + } + } + + public SortingAuthoringModule Sorting; +} +``` + +### Baker Extensions +Again however if modules doesn't fit your needs or have extra unnecessary data then you can +still use **Baker Extensions** which is used by modules. So if you still want to use sorting +but you, for example, don't need set any sorting data, because it constant, then you can do something like: +```csharp +public class FooAuthoring : MonoBehaviour +{ + private class Baker : Baker + { + public void override Bake(FooAuthoring authoring) + { + this.BakeSpriteSorting + ( + GetEntity(TransformUsageFlags.None), + SortingIndex, + SortingLayer, + UseStaticSorting + ); + } + } + + private const int SortingIndex = 0; + private const int SortingLayer = 0; + private const bool UseStaticSorting = false; +} +``` + +### You can look at diagram below to see how this parts related to each other. + + + +# Assets used with authoring workflow +* [`PropertiesSet`](/Base/Data/PropertiesSet.cs) - contains properties components names with update strategy type (read more about [properties](https://github.com/Antoshidza/NSprites/wiki/Register-components-as-properties) and [update modes](https://github.com/Antoshidza/NSprites/wiki/Property-update-modes)). +This `ScriptableObject` used by **authoring** / **modules** / **extensions** to bake registration data. You can create it by call context menu in project `Create/NSprites/Properties Set`. +* [`SpriteAnimation`](/Animation/Data/SpriteAnimation.cs) & [`SpriteAnimationSet`](/Animation/Data/SpriteAnimationSet.cs) - scriptable objects, first contains animation data and second contains a set of `SpriteAnimation` diff --git a/About/RenderDataAuthoring.md.meta b/About/AuthoringWorkflow.md.meta similarity index 100% rename from About/RenderDataAuthoring.md.meta rename to About/AuthoringWorkflow.md.meta diff --git a/About/NSprites-Foundation-Authoring.drawio.svg b/About/NSprites-Foundation-Authoring.drawio.svg new file mode 100644 index 0000000..23ed8dc --- /dev/null +++ b/About/NSprites-Foundation-Authoring.drawio.svg @@ -0,0 +1,4 @@ + + + +
SpriteRendererAuthoring
SpriteRendererAuthoring
SpriteAnimatedRendererAuthoring
SpriteAnimatedRendererAuthoring

Authorings

Classic authoring monobehaviours with simple purpose - contain data to bake and bake it by baker

Authorings...

Modules

Serialized types to use with authorings. Contains fields and bake logic.

Modules...

Baker extensions

Extensions bake methods to use with Baker<T>

Baker extensions...
RegisterSpriteAuthoringModule
RegisterSpriteAuthoringModule
SpriteSettingsModule
SpriteSettingsModule
Regular sprite authoring
Regular sprite authoring
More special sprite authoring where sprite data comes from animation assets and extra animation components added
More special sprite authoring where spri...
SortingAuthroingModule
SortingAuthroingModule
AnimationAuthoringModule
AnimationAuthoringModule
consists of
consists of
calls
calls
Baker.BakeSpriteBase()
Baker.BakeSpriteBase()
Baker.BakeSpriteRender()
Baker.BakeSpriteRender()
Baker.BakeSpriteSorting()
Baker.BakeSpriteSorting()
Baker.BakeAnimation()
Baker.BakeAnimation()
Text is not SVG - cannot display
\ No newline at end of file diff --git a/About/NSprites-Foundation-Authoring.drawio.svg.meta b/About/NSprites-Foundation-Authoring.drawio.svg.meta new file mode 100644 index 0000000..902b670 --- /dev/null +++ b/About/NSprites-Foundation-Authoring.drawio.svg.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 3e1338d700292f84fb6930a87c6ffdb5 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/About/RenderDataAuthoring.md b/About/RenderDataAuthoring.md deleted file mode 100644 index d70fe39..0000000 --- a/About/RenderDataAuthoring.md +++ /dev/null @@ -1,14 +0,0 @@ -# Render data authoring -Contains several authoring classes which can be used to rapidly create sprite entities. - -## abstract [SpriteRenderAuthoringBase](https://github.com/Antoshidza/NSprites-Foundation/blob/main/Base/Authoring/SpriteRendererAuthoringBase.cs) -Abstract base class which uses [render data registration]() part to bake sprite data. It just creates [`SpriteRenderDataToRegister`](https://github.com/Antoshidza/NSprites-Foundation/blob/main/Base/Authoring/SpriteRenderDataToRegister.cs) to setup rendering system. If you want use registration part then you can inherit your authoring classes from this class. -> Note: all other authoring classes inherited from this one, so if you want to implement your own render register approach then avoid using this part. - -## [SpriteRenderAuthoring](https://github.com/Antoshidza/NSprites-Foundation/blob/main/Base/Authoring/SpriteRendererAuthoring.cs) -Bakes default render components. Optionally adds [2D transform](2DTransform.md) components / removes unity default 3D transforms / adds sorting components. Provides static functions bake logic to use in custom authorings. Use this, when - -## Prepare assets -There is [`PropertiesSet`](https://github.com/Antoshidza/NSprites-Foundation/blob/main/Base/Data/PropertiesSet.cs) -which contains properties components names with update strategy type (read more about [properties](https://github.com/Antoshidza/NSprites/wiki/Register-components-as-properties) and [update modes](https://github.com/Antoshidza/NSprites/wiki/Property-update-modes)). -This `ScriptableObject` used by authoring to bake registration data. You can create it by call context menu in project `Create/NSprites/Properties Set`. \ No newline at end of file diff --git a/Animation/Authoring/AnimationAuthoringModule.cs b/Animation/Authoring/AnimationAuthoringModule.cs new file mode 100644 index 0000000..a6b5504 --- /dev/null +++ b/Animation/Authoring/AnimationAuthoringModule.cs @@ -0,0 +1,43 @@ +using System; +using System.Linq; +using Unity.Entities; +using UnityEngine; + +namespace NSprites.Authoring +{ + [Serializable] + public struct AnimationAuthoringModule + { + [SerializeField] public SpriteAnimationSet AnimationSet; + [SerializeField] public int InitialAnimationIndex; + + public SpriteAnimation InitialAnimationData => AnimationSet.Animations.ElementAt(InitialAnimationIndex).data; + + public bool IsValid() + { + if (AnimationSet == null) + { + Debug.LogWarning(new NSpritesException($"{nameof(AnimationSet)} is null")); + return false; + } + + if (InitialAnimationIndex >= AnimationSet.Animations.Count) + { + Debug.LogWarning(new NSpritesException($"{nameof(InitialAnimationIndex)} can't be greater than animations count. {nameof(InitialAnimationIndex)}: {InitialAnimationIndex}, animation count: {AnimationSet.Animations.Count}")); + return false; + } + + if (InitialAnimationIndex < 0) + { + Debug.LogWarning(new NSpritesException($"{nameof(InitialAnimationIndex)} can't be lower 0. Currently it is {InitialAnimationIndex}")); + return false; + } + + return AnimationSet.IsValid(InitialAnimationData.SpriteSheet.texture); + } + + public void Bake(Baker baker) + where TAuthoring : MonoBehaviour + => baker.BakeAnimation(baker.GetEntity(TransformUsageFlags.None), AnimationSet, InitialAnimationIndex); + } +} \ No newline at end of file diff --git a/Animation/Authoring/AnimationAuthoringModule.cs.meta b/Animation/Authoring/AnimationAuthoringModule.cs.meta new file mode 100644 index 0000000..bd512cd --- /dev/null +++ b/Animation/Authoring/AnimationAuthoringModule.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6acd59fe408249b8bfab4fead1346f6c +timeCreated: 1681150612 \ No newline at end of file diff --git a/Animation/Authoring/BakerExtensions.cs b/Animation/Authoring/BakerExtensions.cs new file mode 100644 index 0000000..4a5e994 --- /dev/null +++ b/Animation/Authoring/BakerExtensions.cs @@ -0,0 +1,81 @@ +using Unity.Collections; +using Unity.Entities; +using Unity.Mathematics; +using UnityEngine; + +namespace NSprites.Authoring +{ + public static partial class BakerExtensions + { + public static void BakeAnimation(this Baker baker, in Entity entity, SpriteAnimationSet animationSet, int initialAnimationIndex = 0) + where T : Component + { + if(baker == null) + { + Debug.LogError(new NSpritesException("Passed Baker is null")); + return; + } + if (animationSet == null) + { + Debug.LogError(new NSpritesException("Passed AnimationSet is null")); + return; + } + + baker.DependsOn(animationSet); + + if (animationSet == null) + return; + + if (initialAnimationIndex >= animationSet.Animations.Count || initialAnimationIndex < 0) + { + Debug.LogError(new NSpritesException($"Initial animation index {initialAnimationIndex} can't be less than 0 or great/equal to animation count {animationSet.Animations.Count}")); + return; + } + + #region create animation blob asset + var blobBuilder = new BlobBuilder(Allocator.Temp); //can't use `using` keyword because there is extension which use this + ref + ref var root = ref blobBuilder.ConstructRoot>(); + var animations = animationSet.Animations; + var animationArray = blobBuilder.Allocate(ref root, animations.Count); + + var animIndex = 0; + foreach (var anim in animations) + { + var animData = anim.data; + var animationDuration = 0f; + for (int i = 0; i < animData.FrameDurations.Length; i++) + animationDuration += animData.FrameDurations[i]; + + animationArray[animIndex] = new SpriteAnimationBlobData + { + ID = Animator.StringToHash(anim.name), + GridSize = animData.FrameCount, + UVAtlas = NSpritesUtils.GetTextureST(animData.SpriteSheet), + Scale2D = new float2(animData.SpriteSheet.bounds.size.x, animData.SpriteSheet.bounds.size.y), + AnimationDuration = animationDuration + // FrameDuration - allocate lately + }; + + var durations = blobBuilder.Allocate(ref animationArray[animIndex].FrameDurations, animData.FrameDurations.Length); + for (int di = 0; di < durations.Length; di++) + durations[di] = animData.FrameDurations[di]; + + animIndex++; + } + + var blobAssetReference = blobBuilder.CreateBlobAssetReference>(Allocator.Persistent); + baker.AddBlobAsset(ref blobAssetReference, out _); + blobBuilder.Dispose(); + #endregion + + ref var initialAnim = ref blobAssetReference.Value[initialAnimationIndex]; + + baker.AddComponent(entity, new AnimationSetLink { value = blobAssetReference }); + baker.AddComponent(entity, new AnimationIndex { value = initialAnimationIndex }); + baker.AddComponent(entity, new AnimationTimer { value = initialAnim.FrameDurations[0] }); + baker.AddComponent(entity); + + baker.AddComponent(entity, new MainTexSTInitial { value = initialAnim.UVAtlas }); + } + } +} \ No newline at end of file diff --git a/Animation/Authoring/BakerExtensions.cs.meta b/Animation/Authoring/BakerExtensions.cs.meta new file mode 100644 index 0000000..8b0723f --- /dev/null +++ b/Animation/Authoring/BakerExtensions.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: f35278b948614e239af0ca4fdba49f2e +timeCreated: 1683909751 \ No newline at end of file diff --git a/Animation/Authoring/SpriteAnimatedRendererAuthoring.cs b/Animation/Authoring/SpriteAnimatedRendererAuthoring.cs new file mode 100644 index 0000000..9a7b8c4 --- /dev/null +++ b/Animation/Authoring/SpriteAnimatedRendererAuthoring.cs @@ -0,0 +1,51 @@ +using NSprites.Authoring; +using Unity.Entities; +using Unity.Mathematics; +using UnityEngine; + +namespace NSprites +{ + /// + /// Advanced which also bakes animation data as blob asset and adds animation components. + /// + public class SpriteAnimatedRendererAuthoring : MonoBehaviour + { + private class Baker : Baker + { + public override void Bake(SpriteAnimatedRendererAuthoring authoring) + { + if(!authoring.IsValid) + return; + + var initialAnimData = authoring.AnimationAuthoringModule.InitialAnimationData; + var initialSheetUVAtlas = (float4)NSpritesUtils.GetTextureST(initialAnimData.SpriteSheet); + var initialFrameUVAtlas = new float4(new float2(initialSheetUVAtlas.xy / initialAnimData.FrameCount), initialSheetUVAtlas.zw); + var frameSize = initialAnimData.SpriteSheet.GetSize() / initialAnimData.FrameCount; + + authoring.RegisterSpriteData.Bake(this, initialAnimData.SpriteSheet.texture); + authoring.AnimationAuthoringModule.Bake(this); + authoring.RenderSettings.Bake(this, authoring, frameSize, initialFrameUVAtlas); + authoring.Sorting.Bake(this); + } + } + + [SerializeField] public AnimationAuthoringModule AnimationAuthoringModule; + [SerializeField] public RegisterSpriteAuthoringModule RegisterSpriteData; + [SerializeField] public SpriteSettingsAuthoringModule RenderSettings; + [SerializeField] public SortingAuthoringModule Sorting; + + protected virtual bool IsValid + { + get + { + if (!RegisterSpriteData.IsValid(out var message)) + { + Debug.LogWarning($"{nameof(SpriteAnimatedRendererAuthoring)}: {message}" ); + return false; + } + + return AnimationAuthoringModule.IsValid(); + } + } + } +} \ No newline at end of file diff --git a/Animation/Authoring/SpriteAnimationAuthoring.cs.meta b/Animation/Authoring/SpriteAnimatedRendererAuthoring.cs.meta similarity index 100% rename from Animation/Authoring/SpriteAnimationAuthoring.cs.meta rename to Animation/Authoring/SpriteAnimatedRendererAuthoring.cs.meta diff --git a/Animation/Authoring/SpriteAnimationAuthoring.cs b/Animation/Authoring/SpriteAnimationAuthoring.cs deleted file mode 100644 index 670f662..0000000 --- a/Animation/Authoring/SpriteAnimationAuthoring.cs +++ /dev/null @@ -1,163 +0,0 @@ -using System.Linq; -using Unity.Collections; -using Unity.Entities; -using Unity.Mathematics; -using UnityEngine; -using UnityEngine.Serialization; - -namespace NSprites -{ - /// - /// Advanced which also bakes animation data as blob asset and adds animation components. - /// - public class SpriteAnimationAuthoring : SpriteRendererAuthoring - { - private class Baker : Baker - { - public override void Bake(SpriteAnimationAuthoring authoring) - { - if(!authoring.IsValid) - return; - - var entity = GetEntity(TransformUsageFlags.None); - - BakeSpriteAnimation(this, entity, authoring.AnimationSet, authoring.InitialAnimationIndex); - - var initialAnimData = authoring.AnimationSet.Animations.ElementAt(authoring.InitialAnimationIndex).data; - var initialAnimUVAtlas = (float4)NSpritesUtils.GetTextureST(initialAnimData.SpriteSheet); - - BakeSpriteRender - ( - this, - entity, - authoring, - new float4(new float2(initialAnimUVAtlas.xy / initialAnimData.FrameCount), initialAnimUVAtlas.zw), - authoring._tilingAndOffset, - authoring._pivot, - authoring.VisualSize, - flipX: authoring._flip.x, - flipY: authoring._flip.y - ); - if(!authoring._disableSorting) - BakeSpriteSorting - ( - this, - entity, - authoring._sortingIndex, - authoring._sortingLayer, - authoring._staticSorting - ); - } - } - - [Header("Animation Data")] - [FormerlySerializedAs("_animationSet")] public SpriteAnimationSet AnimationSet; - [FormerlySerializedAs("_initialAnimationIndex")] public int InitialAnimationIndex; - - public override float2 VisualSize - { - get - { - var animationData = AnimationSet.Animations.ElementAt(InitialAnimationIndex).data; - return GetSpriteSize(animationData.SpriteSheet) / animationData.FrameCount; - } - } - - protected override bool IsValid - { - get - { - if (AnimationSet == null) - { - Debug.LogWarning(new NSpritesException($"{nameof(AnimationSet)} is null")); - return false; - } - - if (InitialAnimationIndex >= AnimationSet.Animations.Count) - { - Debug.LogWarning(new NSpritesException($"{nameof(InitialAnimationIndex)} can't be greater than animations count. {nameof(InitialAnimationIndex)}: {InitialAnimationIndex}, animation count: {AnimationSet.Animations.Count}")); - return false; - } - - if (InitialAnimationIndex < 0) - { - Debug.LogWarning(new NSpritesException($"{nameof(InitialAnimationIndex)} can't be lower 0. Currently it is {InitialAnimationIndex}")); - return false; - } - - return true; - } - } - - public static void BakeSpriteAnimation(Baker baker, in Entity entity, SpriteAnimationSet animationSet, int initialAnimationIndex = 0) - where TAuthoring : MonoBehaviour - { - if(baker == null) - { - Debug.LogError(new NSpritesException("Passed Baker is null")); - return; - } - if (animationSet == null) - { - Debug.LogError(new NSpritesException("Passed AnimationSet is null")); - return; - } - - baker.DependsOn(animationSet); - - if (animationSet == null) - return; - - if (initialAnimationIndex >= animationSet.Animations.Count || initialAnimationIndex < 0) - { - Debug.LogError(new NSpritesException($"Initial animation index {initialAnimationIndex} can't be less than 0 or great/equal to animation count {animationSet.Animations.Count}")); - return; - } - - #region create animation blob asset - var blobBuilder = new BlobBuilder(Allocator.Temp); //can't use `using` keyword because there is extension which use this + ref - ref var root = ref blobBuilder.ConstructRoot>(); - var animations = animationSet.Animations; - var animationArray = blobBuilder.Allocate(ref root, animations.Count); - - var animIndex = 0; - foreach (var anim in animations) - { - var animData = anim.data; - var animationDuration = 0f; - for (int i = 0; i < animData.FrameDurations.Length; i++) - animationDuration += animData.FrameDurations[i]; - - animationArray[animIndex] = new SpriteAnimationBlobData - { - ID = Animator.StringToHash(anim.name), - GridSize = animData.FrameCount, - UVAtlas = NSpritesUtils.GetTextureST(animData.SpriteSheet), - Scale2D = new float2(animData.SpriteSheet.bounds.size.x, animData.SpriteSheet.bounds.size.y), - AnimationDuration = animationDuration - // FrameDuration - allocate lately - }; - - var durations = blobBuilder.Allocate(ref animationArray[animIndex].FrameDurations, animData.FrameDurations.Length); - for (int di = 0; di < durations.Length; di++) - durations[di] = animData.FrameDurations[di]; - - animIndex++; - } - - var blobAssetReference = blobBuilder.CreateBlobAssetReference>(Allocator.Persistent); - baker.AddBlobAsset(ref blobAssetReference, out _); - blobBuilder.Dispose(); - #endregion - - ref var initialAnim = ref blobAssetReference.Value[initialAnimationIndex]; - - baker.AddComponent(entity, new AnimationSetLink { value = blobAssetReference }); - baker.AddComponent(entity, new AnimationIndex { value = initialAnimationIndex }); - baker.AddComponent(entity, new AnimationTimer { value = initialAnim.FrameDurations[0] }); - baker.AddComponent(entity); - - baker.AddComponent(entity, new MainTexSTInitial { value = initialAnim.UVAtlas }); - } - } -} \ No newline at end of file diff --git a/Animation/Data/SpriteAnimation.cs b/Animation/Data/SpriteAnimation.cs index f94145d..439258c 100644 --- a/Animation/Data/SpriteAnimation.cs +++ b/Animation/Data/SpriteAnimation.cs @@ -4,6 +4,7 @@ [CreateAssetMenu(fileName = "NewNSpriteAnimation", menuName = "NSprites/Animation (frame sequence)")] public class SpriteAnimation : ScriptableObject { + // Sprite here required because whe want to know UV of animation frame sequence on atlas public Sprite SpriteSheet; public int2 FrameCount = new(1); public float[] FrameDurations = new float[1] { 0.1f }; @@ -26,5 +27,6 @@ private void OnValidate() } } #endif + #endregion } \ No newline at end of file diff --git a/Animation/Data/SpriteAnimationSet.cs b/Animation/Data/SpriteAnimationSet.cs index 2ab2633..7ea0d18 100644 --- a/Animation/Data/SpriteAnimationSet.cs +++ b/Animation/Data/SpriteAnimationSet.cs @@ -17,5 +17,29 @@ public struct NamedAnimation [SerializeField] private NamedAnimation[] _animations; public IReadOnlyCollection Animations => _animations; + + // returns true if all animation's sprites have the same texture as passed in + public bool IsValid(Texture2D mainTexture) + { + var passed = true; + + foreach (var animation in _animations) + { + var texture = animation.data.SpriteSheet.texture; + + if (texture == null) + { + Debug.LogException(new NSpritesException($"{nameof(SpriteAnimationSet)} {name}: all {nameof(_animations)}'s {nameof(SpriteAnimation.SpriteSheet)} must be not null"), this); + passed = false; + } + else if (animation.data.SpriteSheet.texture != mainTexture) + { + Debug.LogException(new NSpritesException($"{nameof(SpriteAnimationSet)} {name}: all {nameof(_animations)}'s {nameof(SpriteAnimation.SpriteSheet)} must have same texture as passed \"{mainTexture.name}\", but animation \"{animation.name}\" have {nameof(SpriteAnimation.SpriteSheet)}'s texture \"{animation.data.SpriteSheet.name}\""), this); + passed = false; + } + } + + return passed; + } } } \ No newline at end of file diff --git a/Base/Authoring/FullScreenSpriteAuthoring.cs b/Base/Authoring/FullScreenSpriteAuthoring.cs index 0508228..fd0077b 100644 --- a/Base/Authoring/FullScreenSpriteAuthoring.cs +++ b/Base/Authoring/FullScreenSpriteAuthoring.cs @@ -16,7 +16,7 @@ public override void Bake(FullScreenSpriteAuthoring authoring) var entity = GetEntity(TransformUsageFlags.None); AddComponent(entity); - AddComponent(entity, new NativeSpriteSize{ Value = authoring._spriteAuthoring.NativeSpriteSize }); + AddComponent(entity, new NativeSpriteSize{ Value = authoring._spriteAuthoring.Sprite.GetSize() }); DependsOn(authoring._spriteAuthoring); } diff --git a/Base/Authoring/Modules.meta b/Base/Authoring/Modules.meta new file mode 100644 index 0000000..8157f43 --- /dev/null +++ b/Base/Authoring/Modules.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ae9a43bad18f453da15b2d47c73732a4 +timeCreated: 1681150598 \ No newline at end of file diff --git a/Base/Authoring/Modules/BakerExtensions.cs b/Base/Authoring/Modules/BakerExtensions.cs new file mode 100644 index 0000000..fde56e1 --- /dev/null +++ b/Base/Authoring/Modules/BakerExtensions.cs @@ -0,0 +1,57 @@ +using Unity.Entities; +using Unity.Mathematics; +using UnityEngine; + +namespace NSprites.Authoring +{ + public static partial class BakerExtensions + { + /// + /// Bakes basic sprite data. Use this method only if you using registration from this package. + /// If you want implement your own registration process please implement your own baking method. + /// + public static void BakeSpriteBase(this Baker baker, in SpriteRenderData renderData) + where TAuthoring : Component + { + //baker.DependsOn(renderData.Material); + baker.DependsOn(renderData.PropertiesSet); + + var entity = baker.GetEntity(TransformUsageFlags.None); + // this comes from NSprites-Foundation and appears as common way to register renderers in runtime + baker.AddComponentObject(entity, new SpriteRenderDataToRegister { data = renderData }); + // this comes from NSprites as extension method to add all required components to entity to let it be sprite rendered + baker.AddSpriteRenderComponents(entity, renderData.ID); + } + + /// + /// Bakes all passed data to make entity be able to rendered though shader from this package. + /// If you use another shader and you need some another data, please implement your own baking method. + /// + public static void BakeSpriteRender(this Baker baker, in Entity entity, TAuthoring authoring, in float4 uvAtlas, in float4 uvTilingAndOffset, in float2 pivot, in float2 scale, bool flipX = false, bool flipY = false, bool add2DTransform = true) + where TAuthoring : Component + { + if (baker == null) + { + Debug.LogError(new NSpritesException($"Passed baker is null"), authoring.gameObject); + return; + } + if (authoring == null) + { + Debug.LogError(new NSpritesException($"Passed authoring object is null"), authoring.gameObject); + return; + } + + baker.AddComponent(entity, new UVAtlas { value = uvAtlas }); + baker.AddComponent(entity, new UVTilingAndOffset { value = uvTilingAndOffset }); + baker.AddComponent(entity, new Pivot { value = pivot }); + baker.AddComponent(entity, new Scale2D { value = scale }); + baker.AddComponent(entity, new Flip { Value = new(flipX ? -1 : 0, flipY ? -1 : 0) }); + + if (add2DTransform) + { + baker.AddComponentObject(entity, new Transform2DRequest { sourceGameObject = authoring.gameObject }); + baker.DependsOn(authoring.transform); + } + } + } +} \ No newline at end of file diff --git a/Base/Authoring/Modules/BakerExtensions.cs.meta b/Base/Authoring/Modules/BakerExtensions.cs.meta new file mode 100644 index 0000000..5d94a1e --- /dev/null +++ b/Base/Authoring/Modules/BakerExtensions.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e77a03b0c7584edab741f81282ab9a4d +timeCreated: 1683975931 \ No newline at end of file diff --git a/Base/Authoring/Modules/RegisterSpriteAuthoringModule.cs b/Base/Authoring/Modules/RegisterSpriteAuthoringModule.cs new file mode 100644 index 0000000..a670f9d --- /dev/null +++ b/Base/Authoring/Modules/RegisterSpriteAuthoringModule.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections.Generic; +using JetBrains.Annotations; +using Unity.Entities; +using UnityEngine; + +namespace NSprites.Authoring +{ + /// + /// Register by creating new with overrided from + /// + [Serializable] + public struct RegisterSpriteAuthoringModule + { + [SerializeField] public SpriteRenderData SpriteRenderData; + + private static readonly Dictionary OverridedMaterials = new(); + private static readonly int MainTexPropertyID = Shader.PropertyToID("_MainTex"); + + public bool IsValid(out string message) + { + if (SpriteRenderData.Material == null) + { + message = $"{nameof(SpriteRenderData.Material)} is null"; + return false; + } + + if (SpriteRenderData.PropertiesSet == null) + { + message = $"{nameof(SpriteRenderData.PropertiesSet)} is null"; + return false; + } + + message = string.Empty; + return true; + } + + public void Bake(Baker baker, Texture2D overrideTexture = null) + where TAuthoring : Component => + baker.BakeSpriteBase(GetRenderData(overrideTexture)); + + private SpriteRenderData GetRenderData([CanBeNull] Texture overrideTexture = null) + { + if (overrideTexture == null) + return SpriteRenderData; + + if (SpriteRenderData.Material == null) + { + Debug.LogException(new NSpritesException($"{nameof(SpriteRenderData.Material)} is null")); + return default; + } + + return overrideTexture == null + ? SpriteRenderData + // create new instance with overrided material + : new() + { + Material = GetOrCreateOverridedMaterial(overrideTexture), + PropertiesSet = SpriteRenderData.PropertiesSet + }; + } + + private Material GetOrCreateOverridedMaterial(Texture texture) + { + if (!OverridedMaterials.TryGetValue(texture, out var material)) + material = CreateOverridedMaterial(texture); +#if UNITY_EDITOR // for SubScene + domain reload + else if (material == null) + { + _ = OverridedMaterials.Remove(texture); + material = CreateOverridedMaterial(texture); + } +#endif + return material; + } + + private Material CreateOverridedMaterial(Texture texture) + { + var material = new Material(SpriteRenderData.Material); + material.SetTexture(MainTexPropertyID, texture); + OverridedMaterials.Add(texture, material); + return material; + } + } +} \ No newline at end of file diff --git a/Base/Authoring/Modules/RegisterSpriteAuthoringModule.cs.meta b/Base/Authoring/Modules/RegisterSpriteAuthoringModule.cs.meta new file mode 100644 index 0000000..8e2daf2 --- /dev/null +++ b/Base/Authoring/Modules/RegisterSpriteAuthoringModule.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ead7da4cb5d44773a10770a62390eed5 +timeCreated: 1683992220 \ No newline at end of file diff --git a/Base/Authoring/Modules/SpriteSettingsAuthoringModule.cs b/Base/Authoring/Modules/SpriteSettingsAuthoringModule.cs new file mode 100644 index 0000000..3126f7a --- /dev/null +++ b/Base/Authoring/Modules/SpriteSettingsAuthoringModule.cs @@ -0,0 +1,83 @@ +using System; +using Unity.Entities; +using Unity.Mathematics; +using UnityEngine; + +namespace NSprites.Authoring +{ + [Serializable] + public class SpriteSettingsAuthoringModule + { + public enum DrawModeType + { + /// Sprite will be simply stretched to it's size. + Simple, + /// Sprite will be tiled depending in it's size and native size (default sprite size). + Tiled + } + + public float2 Pivot = new(.5f); + public float2 Size = new(1f); + [Tooltip("Prevents changing Size when Sprite changed")] public bool LockSize; + public DrawModeType DrawMode; + public float4 TilingAndOffset = new(1f, 1f, 0f, 0f); + public bool2 Flip; + + /// + /// Bakes sprite default (for NSprites-Foundation package) such as + /// + /// and + /// + /// + /// + /// + /// + /// baker bruh + /// authoring monobehaviour + /// The native size of a sprite being baked. Needs because sprite and it's params can come from arbitrary source, so need to be passed + /// The same as should be passed, because of external sprite + public void Bake(Baker baker, TAuthoring authoring, in float2 nativeSize, in float4 uvAtlas) + where TAuthoring : Component + { + var authoringTransform = authoring.transform; + var authoringScale = authoringTransform.lossyScale; + + baker.BakeSpriteRender + ( + baker.GetEntity(TransformUsageFlags.None), + authoring, + uvAtlas, + GetTilingAndOffsetByDrawMode(), + Pivot, + Size * nativeSize * new float2(authoringScale.x, authoringScale.y), + flipX: Flip.x, + flipY: Flip.y + ); + } + + public void TrySetSize(in float2 value) + { + if (LockSize) + Debug.LogWarning($"{nameof(SpriteSettingsAuthoringModule)}: can't change size because {nameof(LockSize)} enabled"); + else + Size = value; + } + + /// + /// Returns UV Tiling & Offset accounting selected . + /// + public float4 GetTilingAndOffsetByDrawMode() + { + return DrawMode switch + { + // just return default user defined Tiling&Offset from inspector + DrawModeType.Simple => TilingAndOffset, + // while size of a sprite can be different it's UVs stay the same - in range [(0,0) ; (1,1)] + // so in this case we want to get ratio of size to sprite NativeSize (which should be "default" sprite size depending on it's import data) and then correct Tiling part in that ratio + DrawModeType.Tiled => new(TilingAndOffset.xy * Size, TilingAndOffset.zw), + + _ => throw new ArgumentOutOfRangeException($"{GetType().Name}.{nameof(UVTilingAndOffset)} ({nameof(SpriteRendererAuthoring)}): can't handle draw mode {DrawMode}") + }; + } + } +} \ No newline at end of file diff --git a/Base/Authoring/Modules/SpriteSettingsAuthoringModule.cs.meta b/Base/Authoring/Modules/SpriteSettingsAuthoringModule.cs.meta new file mode 100644 index 0000000..bb416e1 --- /dev/null +++ b/Base/Authoring/Modules/SpriteSettingsAuthoringModule.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 873c319a41774daaa741c2faaeb895ea +timeCreated: 1684843977 \ No newline at end of file diff --git a/Base/Authoring/SpriteRendererAuthoring.cs b/Base/Authoring/SpriteRendererAuthoring.cs index bcddb12..6994f5c 100644 --- a/Base/Authoring/SpriteRendererAuthoring.cs +++ b/Base/Authoring/SpriteRendererAuthoring.cs @@ -1,6 +1,5 @@ -using System.Collections.Generic; +using NSprites.Authoring; using Unity.Entities; -using Unity.Mathematics; using UnityEngine; namespace NSprites @@ -9,7 +8,7 @@ namespace NSprites /// Adds basic render components such as , , , . /// Optionally adds sorting components, removes built-in 3D transforms and adds 2D transforms. /// - public class SpriteRendererAuthoring : SpriteRendererAuthoringBase + public class SpriteRendererAuthoring : MonoBehaviour { private class Baker : Baker { @@ -19,176 +18,39 @@ public override void Bake(SpriteRendererAuthoring authoring) return; DependsOn(authoring); - DependsOn(authoring._sprite); - var entity = GetEntity(TransformUsageFlags.None); - - BakeSpriteRender - ( - this, - entity, - authoring, - NSpritesUtils.GetTextureST(authoring._sprite), - authoring._tilingAndOffset, - authoring._pivot, - authoring.VisualSize, - flipX: authoring._flip.x, - flipY: authoring._flip.y - ); - if (!authoring._disableSorting) - BakeSpriteSorting - ( - this, - entity, - authoring._sortingIndex, - authoring._sortingLayer, - authoring._staticSorting - ); + authoring.RegisterSpriteData.Bake(this, authoring.OverrideTextureFromSprite ? authoring.Sprite.texture : null); + authoring.RenderSettings.Bake(this, authoring, authoring.Sprite.GetSize(), NSpritesUtils.GetTextureST(authoring.Sprite)); + authoring.Sorting.Bake(this); } } - [SerializeField] protected Sprite _sprite; - private Sprite _lastAssignedSprite; - [SerializeField] protected SpriteRenderData _spriteRenderData; - [SerializeField] protected bool _overrideSpriteTexture = true; - [SerializeField] protected float2 _pivot = new(.5f); - [SerializeField] protected float2 _size; - [Tooltip("Prevents changing Size when Sprite changed")][SerializeField] private bool _lockSize; - [SerializeField] protected float4 _tilingAndOffset = new(1f, 1f, 0f, 0f); - [SerializeField] protected bool2 _flip; + [SerializeField] public Sprite Sprite; + [SerializeField] public RegisterSpriteAuthoringModule RegisterSpriteData; + [SerializeField] public bool OverrideTextureFromSprite = true; - [Header("Sorting")] - [SerializeField] protected bool _disableSorting; - [SerializeField] protected bool _staticSorting; - [SerializeField] protected int _sortingIndex; - [SerializeField] protected int _sortingLayer; - - public static float2 GetSpriteSize(Sprite sprite) => new(sprite.bounds.size.x, sprite.bounds.size.y); - public virtual float2 VisualSize => _size * new float2(transform.lossyScale.x, transform.lossyScale.y); - public float2 NativeSpriteSize => GetSpriteSize(_sprite); - - private void OnValidate() - { - if (_sprite != _lastAssignedSprite && _sprite != null) - { - _lastAssignedSprite = _sprite; - - if(!_lockSize) - _size = NativeSpriteSize; - } - } - - public static void BakeSpriteRender(Baker baker, in Entity entity, TAuthoring authoring, in float4 uvAtlas, in float4 uvTilingAndOffset, in float2 pivot, in float2 scale, bool flipX = false, bool flipY = false, bool add2DTransform = true) - where TAuthoring : MonoBehaviour - { - if (baker == null) - { - Debug.LogError(new NSpritesException($"Passed baker is null"), authoring.gameObject); - return; - } - if (authoring == null) - { - Debug.LogError(new NSpritesException($"Passed authoring object is null"), authoring.gameObject); - return; - } - - baker.AddComponent(entity, new UVAtlas { value = uvAtlas }); - baker.AddComponent(entity, new UVTilingAndOffset { value = uvTilingAndOffset }); - baker.AddComponent(entity, new Pivot { value = pivot }); - baker.AddComponent(entity, new Scale2D { value = scale }); - baker.AddComponent(entity, new Flip { Value = new(flipX ? -1 : 0, flipY ? -1 : 0) }); - - if (add2DTransform) - { - baker.AddComponentObject(entity, new Transform2DRequest { sourceGameObject = authoring.gameObject }); - baker.DependsOn(authoring.transform); - } - } - - public static void BakeSpriteSorting(Baker baker, in Entity entity, int sortingIndex, int sortingLayer, bool staticSorting = false) - where TAuthoring : MonoBehaviour - { - if (baker == null) - { - Debug.LogError(new NSpritesException($"Passed baker is null")); - return; - } + [SerializeField] public SpriteSettingsAuthoringModule RenderSettings; + [SerializeField] public SortingAuthoringModule Sorting; - baker.AddComponent(entity); - baker.AddComponent(entity); - baker.AddComponent(entity, new SortingIndex { value = sortingIndex }); - baker.AddSharedComponent(entity, new SortingLayer { index = sortingLayer }); - if (staticSorting) - baker.AddComponent(entity); - } - - private static readonly Dictionary _overridedMaterials = new(); - - protected Material GetOrCreateOverridedMaterial(Texture texture) - { - if (!_overridedMaterials.TryGetValue(texture, out var material)) - material = CreateOverridedMaterial(texture); -#if UNITY_EDITOR //for SubScene + domain reload - else if (material == null) - { - _ = _overridedMaterials.Remove(texture); - material = CreateOverridedMaterial(texture); - } -#endif - return material; - } - protected Material CreateOverridedMaterial(Texture texture) - { - var material = new Material(_spriteRenderData.Material); - material.SetTexture("_MainTex", _sprite.texture); - _overridedMaterials.Add(texture, material); - return material; - } - - protected override SpriteRenderData RenderData + private bool IsValid { get { - if (_spriteRenderData.Material == null) - { - Debug.LogException(new NSpritesException($"{nameof(_spriteRenderData.Material)} is null"), gameObject); - return default; - } - - if (_overrideSpriteTexture && _sprite != null) - // create new instance with overrided material - return new() - { - Material = GetOrCreateOverridedMaterial(_sprite.texture), - PropertiesSet = _spriteRenderData.PropertiesSet - }; - return _spriteRenderData; - } - } - - protected override bool IsValid - { - get - { - if (_sprite == null) - { - Debug.LogWarning(new NSpritesException($"{nameof(_sprite)} is null"), gameObject); - return false; - } - - if (_spriteRenderData.Material == null) + if (!RegisterSpriteData.IsValid(out var message)) { - Debug.LogWarning(new NSpritesException($"{nameof(SpriteRenderData.Material)} is null"), gameObject); + Debug.LogWarning(new NSpritesException(message), gameObject); return false; } + + // Settings just have struct values and there is nothing to validate - if (_spriteRenderData.PropertiesSet == null) + if (Sprite == null) { - Debug.LogWarning(new NSpritesException($"{nameof(SpriteRenderData.PropertiesSet)} is null"), gameObject); + Debug.LogWarning(new NSpritesException($"{GetType().Name}: {nameof(Sprite)} is null"), gameObject); return false; } - return base.IsValid; + return true; } } } diff --git a/Base/Authoring/SpriteRendererAuthoringBase.cs b/Base/Authoring/SpriteRendererAuthoringBase.cs deleted file mode 100644 index 04f117b..0000000 --- a/Base/Authoring/SpriteRendererAuthoringBase.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Unity.Entities; -using UnityEngine; - -namespace NSprites -{ - /// - /// Gets through virtual property then adds . - /// Lately baking system will catch those entities and add needed components for rendering. - /// - public abstract class SpriteRendererAuthoringBase : MonoBehaviour - { - [BakeDerivedTypes] - private class Baker : Baker - { - public override void Bake(SpriteRendererAuthoringBase authoring) - { - if (!authoring.IsValid) - return; - - var renderData = authoring.RenderData; - DependsOn(renderData.PropertiesSet); - var entity = GetEntity(TransformUsageFlags.None); - AddComponentObject(entity, new SpriteRenderDataToRegister { data = renderData }); - this.AddSpriteRenderComponents(entity, renderData.ID); - } - } - - protected abstract SpriteRenderData RenderData { get; } - - /// While returns true base baker works, otherwise does nothing - protected virtual bool IsValid => true; - } -} \ No newline at end of file diff --git a/Base/Authoring/SpriteRendererAuthoringBase.cs.meta b/Base/Authoring/SpriteRendererAuthoringBase.cs.meta deleted file mode 100644 index b5b8f4f..0000000 --- a/Base/Authoring/SpriteRendererAuthoringBase.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 54e1b70b8d12781468a1c0d5a8eca35e -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Base/Common/Bounds2D.cs b/Base/Common/Bounds2D.cs index 6d5a69c..402fd61 100644 --- a/Base/Common/Bounds2D.cs +++ b/Base/Common/Bounds2D.cs @@ -1,4 +1,5 @@ -using Unity.Mathematics; +using System; +using Unity.Mathematics; namespace NSprites { @@ -38,6 +39,21 @@ private static bool Equals(Bounds2D lhs, Bounds2D rhs) { return !Equals(lhs, rhs); } + + public bool Equals(Bounds2D other) + { + return _position.Equals(other._position) && _extents.Equals(other._extents); + } + + public override bool Equals(object obj) + { + return obj is Bounds2D other && Equals(other); + } + + public override int GetHashCode() + { + return HashCode.Combine(_position, _extents); + } public bool Intersects(in Bounds2D bounds) { diff --git a/Base/Common/Utils.cs b/Base/Common/Utils.cs new file mode 100644 index 0000000..56a0679 --- /dev/null +++ b/Base/Common/Utils.cs @@ -0,0 +1,10 @@ +using Unity.Mathematics; +using UnityEngine; + +namespace NSprites +{ + public static class Utils + { + public static float2 GetSize(this Sprite sprite) => new(sprite.bounds.size.x, sprite.bounds.size.y); + } +} \ No newline at end of file diff --git a/Base/Common/Utils.cs.meta b/Base/Common/Utils.cs.meta new file mode 100644 index 0000000..e5fc3a3 --- /dev/null +++ b/Base/Common/Utils.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: bcc65e1ce99a43edb515d415bd6f76b0 +timeCreated: 1684843095 \ No newline at end of file diff --git a/README.md b/README.md index 1fac285..e63865f 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Also before working with this package please read [NSprites documentation](https | **name** | **running** | description | |:------------------------------------------------------------------------------------------|:------------|:-----------------------------------------------------------------------| | [Components](https://github.com/Antoshidza/NSprites-Foundation/tree/main/Base/Components) | runtime | Contains components to be used with NSprites | -| [Render data authoring](About/RenderDataAuthoring.md) | editor | Bakes basic render data, uses all other parts | +| [Authoring](About/AuthoringWorkflow.md) | editor | Bakes basic render data, uses all other parts | | Render data registration | runtime | Register render data for NSprites render system | | [Sorting](About/Sorting.md) | runtime | Calculate SortingValue depending on 2D position to use in shader | | Culling | runtime | Disables / Enables rendering based on 2D position relatively to camera | @@ -21,7 +21,7 @@ Also before working with this package please read [NSprites documentation](https Diagram below illustrates dependencies between parts -## Limitations +## Probably you should know * You can use included shaders only with URP, so before anything rendered you should [import, create and assign URP asset in project settings](https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@14.0/manual/InstallingAndConfiguringURP.html). If you want use another render pipeline then you need to implement your own [shader and create material](https://github.com/Antoshidza/NSprites/wiki/Prepare-compatible-material) with it. * Some components registered as properties in this package, so by default you will have component properties (you can see them [this window](https://github.com/Antoshidza/NSprites/wiki/Debug-NSprites-data)). diff --git a/Sorting/Attributes.meta b/Sorting/Attributes.meta new file mode 100644 index 0000000..565441e --- /dev/null +++ b/Sorting/Attributes.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e4bd922b0247492f9605f5cdb90852a0 +timeCreated: 1684154117 \ No newline at end of file diff --git a/Sorting/Attributes/SortingLayerAttribute.cs b/Sorting/Attributes/SortingLayerAttribute.cs new file mode 100644 index 0000000..33cb8be --- /dev/null +++ b/Sorting/Attributes/SortingLayerAttribute.cs @@ -0,0 +1,6 @@ +using UnityEngine; + +namespace NSprites +{ + public class SortingLayerAttribute : PropertyAttribute { } +} \ No newline at end of file diff --git a/Sorting/Attributes/SortingLayerAttribute.cs.meta b/Sorting/Attributes/SortingLayerAttribute.cs.meta new file mode 100644 index 0000000..763c0fe --- /dev/null +++ b/Sorting/Attributes/SortingLayerAttribute.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: c5bf89616a2a411bb6cf008e7b1b7809 +timeCreated: 1684154132 \ No newline at end of file diff --git a/Sorting/Authoring.meta b/Sorting/Authoring.meta new file mode 100644 index 0000000..facfd1a --- /dev/null +++ b/Sorting/Authoring.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2e83f00e57a14e0d9f516f96f95a519e +timeCreated: 1684842487 \ No newline at end of file diff --git a/Sorting/Authoring/Modules.meta b/Sorting/Authoring/Modules.meta new file mode 100644 index 0000000..fddb026 --- /dev/null +++ b/Sorting/Authoring/Modules.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ec6e6afe77344262a687a72c47ea7145 +timeCreated: 1684842494 \ No newline at end of file diff --git a/Sorting/Authoring/Modules/BakerExtensions.cs b/Sorting/Authoring/Modules/BakerExtensions.cs new file mode 100644 index 0000000..046ee4c --- /dev/null +++ b/Sorting/Authoring/Modules/BakerExtensions.cs @@ -0,0 +1,28 @@ +using Unity.Entities; +using UnityEngine; + +namespace NSprites +{ + public static partial class BakerExtensions + { + /// + /// Bakes sorting components for NSprites-Foundation sorting system + /// + public static void BakeSpriteSorting(this Baker baker, in Entity entity, int sortingIndex, int sortingLayer, bool staticSorting = false) + where TAuthoring : MonoBehaviour + { + if (baker == null) + { + Debug.LogError(new NSpritesException($"Passed baker is null")); + return; + } + + baker.AddComponent(entity); + baker.AddComponent(entity); + baker.AddComponent(entity, new SortingIndex { value = sortingIndex }); + baker.AddSharedComponent(entity, new SortingLayer { index = sortingLayer }); + if (staticSorting) + baker.AddComponent(entity); + } + } +} \ No newline at end of file diff --git a/Sorting/Authoring/Modules/BakerExtensions.cs.meta b/Sorting/Authoring/Modules/BakerExtensions.cs.meta new file mode 100644 index 0000000..b0af801 --- /dev/null +++ b/Sorting/Authoring/Modules/BakerExtensions.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: fd128ffecd5e446895df4371c2969f12 +timeCreated: 1684842506 \ No newline at end of file diff --git a/Sorting/Authoring/Modules/SortingAuthoringModule.cs b/Sorting/Authoring/Modules/SortingAuthoringModule.cs new file mode 100644 index 0000000..12b18df --- /dev/null +++ b/Sorting/Authoring/Modules/SortingAuthoringModule.cs @@ -0,0 +1,29 @@ +using System; +using Unity.Entities; +using UnityEngine; + +namespace NSprites +{ + /// + /// Bakes sorting components for NSprites-Foundation sorting system + /// + [Serializable] + public struct SortingAuthoringModule + { + [SerializeField] public bool StaticSorting; + [SerializeField] public int SortingIndex; + [SortingLayer] [SerializeField] public int SortingLayer; + + public void Bake(Baker baker) + where TAuthoring : MonoBehaviour + { + baker.BakeSpriteSorting + ( + baker.GetEntity(TransformUsageFlags.None), + SortingIndex, + UnityEngine.SortingLayer.GetLayerValueFromID(SortingLayer), + StaticSorting + ); + } + } +} \ No newline at end of file diff --git a/Sorting/Authoring/Modules/SortingAuthoringModule.cs.meta b/Sorting/Authoring/Modules/SortingAuthoringModule.cs.meta new file mode 100644 index 0000000..54aff94 --- /dev/null +++ b/Sorting/Authoring/Modules/SortingAuthoringModule.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 8762f15a8cb644298cfa254df987ed61 +timeCreated: 1685790547 \ No newline at end of file diff --git a/Sorting/Editor.meta b/Sorting/Editor.meta new file mode 100644 index 0000000..826f9da --- /dev/null +++ b/Sorting/Editor.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: b851edc697064fdfa69659e8ad7bda0e +timeCreated: 1684153879 \ No newline at end of file diff --git a/Sorting/Editor/SortingLayerPropertyDrawer.cs b/Sorting/Editor/SortingLayerPropertyDrawer.cs new file mode 100644 index 0000000..7b59738 --- /dev/null +++ b/Sorting/Editor/SortingLayerPropertyDrawer.cs @@ -0,0 +1,34 @@ +using UnityEngine; +using UnityEditor; +using System.Reflection; + +namespace NSprites.Editor +{ + [CustomPropertyDrawer(typeof(SortingLayerAttribute))] + public class SortingLayerPropertyDrawer : PropertyDrawer + { + private const string SortingLayerFieldMethodName = "SortingLayerField"; + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + if (property.propertyType != SerializedPropertyType.Integer && property.propertyType != SerializedPropertyType.String) + Debug.LogError("SortedLayer property should be an integer or string ( the layer id )"); + else + SortingLayerField(new GUIContent("Sorting Layer"), property, EditorStyles.popup, EditorStyles.label); + } + + public static void SortingLayerField(GUIContent label, SerializedProperty layerID, GUIStyle style, GUIStyle labelStyle) + { + var methodInfo = typeof(EditorGUILayout).GetMethod(SortingLayerFieldMethodName, BindingFlags.Static | BindingFlags.NonPublic, null, new[] { typeof(GUIContent), typeof(SerializedProperty), typeof(GUIStyle), typeof(GUIStyle) }, null); + + if (methodInfo == null) + { + Debug.LogWarning($"{nameof(SortingLayerPropertyDrawer)} can't find {SortingLayerFieldMethodName}."); + return; + } + + var parameters = new object[] { label, layerID, style, labelStyle }; + methodInfo.Invoke(null, parameters); + } + } +} \ No newline at end of file diff --git a/Sorting/Editor/SortingLayerPropertyDrawer.cs.meta b/Sorting/Editor/SortingLayerPropertyDrawer.cs.meta new file mode 100644 index 0000000..4a98305 --- /dev/null +++ b/Sorting/Editor/SortingLayerPropertyDrawer.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a4ca514bb0f942858a3b786b795351d7 +timeCreated: 1684153895 \ No newline at end of file diff --git a/Sorting/Systems/SpriteSortingSystem.cs b/Sorting/Systems/SpriteSortingSystem.cs index bcbadaf..7732534 100644 --- a/Sorting/Systems/SpriteSortingSystem.cs +++ b/Sorting/Systems/SpriteSortingSystem.cs @@ -12,6 +12,7 @@ namespace NSprites { + // TODO: if user can define any index of a layer, then we should recalculate layers actual indices. So for example layers -1, 1, 2 should become 0, 1, 2. This needed because sorting value should be in [0,1] range, but negative layers will produce negative results [BurstCompile] [WorldSystemFilter(WorldSystemFilterFlags.Default | WorldSystemFilterFlags.Editor)] public partial struct SpriteSortingSystem : ISystem diff --git a/package.json b/package.json index 6e16e4c..c1099ab 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "com.tonymax.nsprites.foundation", - "version": "3.1.0", + "version": "4.0.0", "displayName": "NSprites Foundation", "description": "Contains solutions based on NSprites package such as authoring sprite data, animation, sorting, culling systems.", "unity": "2022.2",