10using System.Collections.Generic;
35 public JaggedRects(
int length) : base(length) { }
50 case UVChannelFlags.UV0:
52 case UVChannelFlags.UV1:
54 case UVChannelFlags.UV2:
56 case UVChannelFlags.UV3:
59 throw new InvalidOperationException();
65 #region INSPECTOR FIELDS
67 [Tooltip(
"Should this renderer include uv0 coordinates in the generated meshes.")]
69 private bool _useUv0 =
true;
71 [Tooltip(
"Should this renderer include uv1 coordinates in the generated meshes.")]
73 private bool _useUv1 =
false;
75 [Tooltip(
"Should this renderer include uv2 coordinates in the generated meshes.")]
77 private bool _useUv2 =
false;
79 [Tooltip(
"Should this renderer include uv3 coordinates in the generated meshes.")]
81 private bool _useUv3 =
false;
83 [Tooltip(
"Should this renderer include vertex colors in the generated meshes.")]
85 private bool _useColors =
true;
87 [Tooltip(
"Multiply all vertex colors for all graphics by this color.")]
91 [Tooltip(
"Should this renderer include normals in the generated meshes.")]
93 private bool _useNormals =
false;
96 [Tooltip(
"Shader to use to display the graphics.")]
100 [Tooltip(
"The layer that the visual representation of the graphics. It is independent from the layer the graphics occupy.")]
104 [Tooltip(
"The atlas combines multiple textures into a single texture automatically, allowing each graphic to have a different " +
105 "texture but still allow the graphics as a whole to render efficiently.")]
121 protected List<LeapRuntimeTintFeature>
_tintFeatures =
new List<LeapRuntimeTintFeature>();
164 public virtual bool IsAtlasDirty {
170 public virtual void RebuildAtlas(
ProgressBar progress) {
171 Undo.RecordObject(
renderer,
"Rebuilt atlas");
173 progress.
Begin(2,
"Rebuilding Atlas",
"", () => {
174 Texture2D[] packedTextures;
178 _atlas.
RebuildAtlas(progress, out packedTextures, out _atlasUvs);
180 progress.
Begin(3,
"",
"", () => {
181 progress.
Step(
"Post-Process Atlas");
183 for (
int i = 0; i < packedTextures.Length; i++) {
186 }
catch (Exception e) {
187 Debug.LogException(e);
191 progress.
Step(
"Saving To Asset");
195 for (
int i = 0; i < packedTextures.Length; i++) {
196 packedTextures[i].Apply(updateMipmaps:
false, makeNoLongerReadable:
true);
202 foreach (var feature in _textureFeatures) {
203 _material.SetTexture(feature.propertyName, _packedTextures.GetTexture(feature.propertyName));
211 public virtual void GetSupportInfo(List<LeapTextureFeature> features, List<SupportInfo> info) {
212 for (
int i = 0; i < features.Count; i++) {
213 var feature = features[i];
214 if (group.features.Query().OfType<
LeapSpriteFeature>().Any(s => s.channel == feature.channel)) {
215 info[i] = info[i].OrWorse(
SupportInfo.
Error(
"Texture features cannot currently share uvs with sprite features."));
220 public virtual void GetSupportInfo(List<LeapSpriteFeature> features, List<SupportInfo> info) {
224 #if !UNITY_2020_1_OR_NEWER
225 if (!Application.isPlaying) {
226 Packer.RebuildAtlasCacheIfNeeded(EditorUserBuildSettings.activeBuildTarget);
230 for (
int i = 0; i < features.Count; i++) {
231 var feature = features[i];
233 if (!feature.AreAllSpritesPacked()) {
237 if (!feature.AreAllSpritesOnSameTexture()) {
243 for (
int i = 0; i < features.Count; i++) {
244 var feature = features[i];
245 if (group.features.Query().OfType<
LeapTextureFeature>().Any(s => s.channel == feature.channel)) {
246 info[i] = info[i].
OrWorse(
SupportInfo.
Error(
"Sprite features cannot currently share uvs with texture features."));
251 public virtual void GetSupportInfo(List<LeapRuntimeTintFeature> features, List<SupportInfo> info) {
255 public virtual void GetSupportInfo(List<LeapBlendShapeFeature> features, List<SupportInfo> info) {
260 public virtual void GetSupportInfo(List<CustomFloatChannelFeature> features, List<SupportInfo> info) { }
261 public virtual void GetSupportInfo(List<CustomVectorChannelFeature> features, List<SupportInfo> info) { }
262 public virtual void GetSupportInfo(List<CustomColorChannelFeature> features, List<SupportInfo> info) { }
263 public virtual void GetSupportInfo(List<CustomMatrixChannelFeature> features, List<SupportInfo> info) { }
266 loadAllSupportedFeatures();
271 if (_spriteFeatures !=
null) {
272 uploadSpriteTextures();
279 if (_material ==
null) {
285 updateCustomChannels();
289 public override void OnDisableRendererEditor() {
290 base.OnDisableRendererEditor();
293 public override void OnUpdateRendererEditor() {
294 base.OnUpdateRendererEditor();
301 PreventDuplication(ref _material);
309 foreach (var tintFeature
in _tintFeatures) {
310 if (!tintFeature.isDirtyOrEditTime)
continue;
313 if (QualitySettings.activeColorSpace == ColorSpace.Linear) {
314 tintFeature.featureData.Query().Select(d => (Vector4)d.color.linear).FillList(_tintColors);
316 tintFeature.featureData.Query().Select(d => (Vector4)d.color).FillList(_tintColors);
318 _material.SetVectorArraySafe(TINTS_PROPERTY, _tintColors);
324 foreach (var blendShapeFeature
in _blendShapeFeatures) {
325 if (!blendShapeFeature.isDirtyOrEditTime)
continue;
328 blendShapeFeature.featureData.Query().Select(d => d.amount).FillList(_blendShapeAmounts);
329 _material.SetFloatArraySafe(BLEND_SHAPE_AMOUNTS_PROPERTY, _blendShapeAmounts);
336 foreach (var floatChannelFeature
in _floatChannelFeatures) {
337 if (!floatChannelFeature.isDirtyOrEditTime)
continue;
339 floatChannelFeature.featureData.Query().Select(d => d.value).FillList(_customFloatChannelData);
340 _material.SetFloatArraySafe(floatChannelFeature.channelName, _customFloatChannelData);
343 foreach (var vectorChannelFeature
in _vectorChannelFeatures) {
344 if (!vectorChannelFeature.isDirtyOrEditTime)
continue;
346 vectorChannelFeature.featureData.Query().Select(d => d.value).FillList(_customVectorChannelData);
347 _material.SetVectorArraySafe(vectorChannelFeature.channelName, _customVectorChannelData);
350 foreach (var colorChannelFeature
in _colorChannelFeatures) {
351 if (!colorChannelFeature.isDirtyOrEditTime)
continue;
353 colorChannelFeature.featureData.Query().Select(d => d.value).FillList(_customColorChannelData);
354 _material.SetColorArraySafe(colorChannelFeature.channelName, _customColorChannelData);
357 foreach (var matrixChannelFeature
in _matrixChannelFeatures) {
358 if (!matrixChannelFeature.isDirty)
continue;
360 matrixChannelFeature.featureData.Query().Select(d => d.value).FillList(_customMatrixChannelData);
361 _material.SetMatrixArraySafe(matrixChannelFeature.channelName, _customMatrixChannelData);
367 #region GENERATION SETUP
371 loadAllSupportedFeatures();
375 if (_textureFeatures.Count != 0) {
379 if (_spriteFeatures.Count != 0) {
380#if UNITY_EDITOR && !UNITY_2020_1_OR_NEWER
381 Packer.RebuildAtlasCacheIfNeeded(EditorUserBuildSettings.activeBuildTarget);
383 extractSpriteRects();
384 uploadSpriteTextures();
391 group.GetSupportedFeatures(_textureFeatures);
392 group.GetSupportedFeatures(_spriteFeatures);
393 group.GetSupportedFeatures(_tintFeatures);
394 group.GetSupportedFeatures(_blendShapeFeatures);
396 group.GetSupportedFeatures(_floatChannelFeatures);
397 group.GetSupportedFeatures(_vectorChannelFeatures);
398 group.GetSupportedFeatures(_colorChannelFeatures);
399 group.GetSupportedFeatures(_matrixChannelFeatures);
401 _doesRequireColors = doesRequireMeshColors();
402 _doesRequireNormals = doesRequireMeshNormals();
403 _doesRequireVertInfo = doesRequireVertInfo();
405 _requiredUvChannels.Clear();
406 foreach (var channel
in MeshUtil.allUvChannels) {
407 if (channel == UVChannelFlags.UV3 && _doesRequireVertInfo)
continue;
409 if (doesRequireUvChannel(channel)) {
410 _requiredUvChannels.Add(channel);
422 if (_material ==
null) {
423 _material =
new Material(_shader);
427 Undo.RecordObject(_material,
"Touched material");
430 _material.shader = _shader;
431 _material.name =
"Procedural Graphic Material";
433 foreach (var keyword
in _material.shaderKeywords) {
434 _material.DisableKeyword(keyword);
437 if (_spriteTextureBlock ==
null) {
438 _spriteTextureBlock =
new MaterialPropertyBlock();
440 _spriteTextureBlock.Clear();
442 if (_doesRequireColors) {
443 _material.EnableKeyword(COLORS_FEATURE);
446 if (_doesRequireNormals) {
447 _material.EnableKeyword(NORMALS_FEATURE);
450 foreach (var channel
in _requiredUvChannels) {
451 _material.EnableKeyword(GetUvFeature(channel));
454 if (_customColorChannelData.Count > 0 ||
455 _customFloatChannelData.Count > 0 ||
456 _customVectorChannelData.Count > 0 ||
457 _customMatrixChannelData.Count > 0) {
458 _material.EnableKeyword(CUSTOM_CHANNEL_KEYWORD);
461 if (_textureFeatures.Count != 0) {
462 foreach (var feature
in _textureFeatures) {
463 _material.SetTexture(feature.propertyName, _packedTextures.
GetTexture(feature.propertyName));
467 if (_tintFeatures.Count != 0) {
471 if (_blendShapeFeatures.Count != 0) {
478 foreach (var spriteFeature
in _spriteFeatures) {
479 for (
int i = 0; i < spriteFeature.featureData.Count; i++) {
480 var dataObj = spriteFeature.featureData[i];
481 var sprite = dataObj.sprite;
482 if (sprite ==
null)
continue;
485 if (SpriteAtlasUtil.TryGetAtlasedRect(sprite, out rect)) {
486 _atlasUvs.SetRect(spriteFeature.channel.Index(), sprite, rect);
488 _atlasUvs.SetRect(spriteFeature.channel.Index(), sprite,
default(Rect));
497 foreach (var spriteFeature
in _spriteFeatures) {
498 var tex = spriteFeature.featureData.Query().
499 Select(d => d.sprite).
500 Where(s => s !=
null).
502 Select(s => SpriteUtility.GetSpriteTexture(s, getAtlasData:
true)).
504 Select(s => s.texture).
510 if (!Application.isPlaying) {
511 _spriteTextureBlock.SetTexture(spriteFeature.propertyName, tex);
515 _material.SetTexture(spriteFeature.propertyName, tex);
523 #region MESH GENERATION
552 if (_doesRequireColors) {
556 foreach (var channel
in _requiredUvChannels) {
560 if (_doesRequireVertInfo) {
564 foreach (var blendShapeFeature
in _blendShapeFeatures) {
565 buildBlendShapes(blendShapeFeature.featureData[_generation.
graphicIndex]);
580 var topology = MeshCache.GetTopology(_generation.
graphic.
mesh);
582 int vertOffset = _generation.
verts.Count;
583 for (
int i = 0; i < topology.tris.Length; i++) {
584 _generation.
tris.Add(topology.tris[i] + vertOffset);
587 if (_doesRequireNormals) {
588 var normals = MeshCache.GetNormals(_generation.
graphic.
mesh);
589 for (
int i = 0; i < topology.verts.Length; i++) {
592 graphicVertNormalToMeshVertNormal(topology.verts[i], normals[i], out meshVert, out meshNormal);
594 _generation.
verts.Add(meshVert);
595 _generation.
normals.Add(meshNormal);
598 for (
int i = 0; i < topology.verts.Length; i++) {
599 _generation.
verts.Add(graphicVertToMeshVert(topology.verts[i]));
608 if (QualitySettings.activeColorSpace == ColorSpace.Linear) {
614 var colors = MeshCache.GetColors(_generation.
graphic.
mesh);
615 if (QualitySettings.activeColorSpace == ColorSpace.Linear) {
616 for (
int i = 0; i < colors.Length; i++) {
617 _generation.
colors.Add(colors[i].linear * totalTint);
620 for (
int i = 0; i < colors.Length; i++) {
621 _generation.
colors.Add(colors[i] * totalTint);
627 protected virtual void buildUvs(UVChannelFlags channel) {
629 var uvs = MeshCache.GetUvs(_generation.
graphic.
mesh, channel);
630 var targetList = _generation.
uvs[channel.Index()];
632 targetList.AddRange(uvs);
640 if (_textureFeatures.Count > 0) {
641 key = _textureFeatures[0].featureData[_generation.
graphicIndex].texture;
642 }
else if (_spriteFeatures.Count > 0) {
643 key = _spriteFeatures[0].featureData[_generation.
graphicIndex].sprite;
648 Rect rect = _atlasUvs.GetRect(channel.Index(), key);
649 MeshUtil.RemapUvs(targetList, rect, uvs.Count);
656 new Vector4(0, 0, 0, _generation.
graphicId));
662 List<Vector3> blendVerts = Pool<List<Vector3>>.Spawn();
669 int offset = _generation.
verts.Count - blendVerts.Count;
670 for (
int i = 0; i < blendVerts.Count; i++) {
671 Vector3 shapeVert = blendVerts[i];
672 Vector3 delta = blendShapeDelta(shapeVert, _generation.
verts[i + offset]);
674 Vector4 currVertInfo = _generation.
vertInfo[i + offset];
675 currVertInfo.x = delta.x;
676 currVertInfo.y = delta.y;
677 currVertInfo.z = delta.z;
678 _generation.
vertInfo[i + offset] = currVertInfo;
682 Pool<List<Vector3>>.Recycle(blendVerts);
688 return graphicVertToMeshVert(shapeVert) - originalVert;
692 Assert.IsNull(_generation.
mesh,
"Cannot begin a new mesh without finishing the current mesh.");
699 mesh.Clear(keepVertexLayout:
false);
702 mesh.name =
"Procedural Graphic Mesh";
703 mesh.hideFlags = HideFlags.None;
705 _generation.
mesh = mesh;
708 protected virtual void finishMesh(
bool deleteEmptyMeshes =
true) {
711 if (_generation.
verts.Count == 0 && deleteEmptyMeshes) {
712 if (!Application.isPlaying) {
713 UnityEngine.Object.DestroyImmediate(_generation.
mesh, allowDestroyingAssets:
true);
715 _generation.
mesh =
null;
719 _generation.
mesh.SetVertices(_generation.
verts);
720 _generation.
mesh.SetTriangles(_generation.
tris, 0);
722 if (_generation.
normals.Count == _generation.
verts.Count) {
730 if (_generation.
colors.Count == _generation.
verts.Count) {
731 _generation.
mesh.SetColors(_generation.
colors);
734 foreach (var channel
in _requiredUvChannels) {
735 _generation.
mesh.SetUVs(channel.Index(), _generation.
uvs[channel.Index()]);
743 finishMesh(deleteEmptyMeshes);
745 if (_generation.
mesh !=
null) {
747 _generation.
mesh =
null;
764 public List<Vector4>[]
uvs;
766 public bool isGenerating {
775 state.
verts =
new List<Vector3>();
776 state.
normals =
new List<Vector3>();
777 state.
vertInfo =
new List<Vector4>();
778 state.
tris =
new List<int>();
779 state.
colors =
new List<Color>();
780 state.
uvs =
new List<Vector4>[4] {
796 for (
int i = 0; i < 4; i++) {
805 protected IEnumerable<UVChannelFlags> enabledUvChannels {
807 if (_useUv0) yield
return UVChannelFlags.UV0;
808 if (_useUv1) yield
return UVChannelFlags.UV1;
809 if (_useUv2) yield
return UVChannelFlags.UV2;
810 if (_useUv3) yield
return UVChannelFlags.UV3;
824 case UVChannelFlags.UV0:
826 case UVChannelFlags.UV1:
828 case UVChannelFlags.UV2:
830 case UVChannelFlags.UV3:
833 throw new ArgumentException(
"Invalid channel argument.");
837 protected void drawMesh(Mesh mesh, Matrix4x4 transform) {
839 if (!Application.isPlaying) {
840 Graphics.DrawMesh(mesh, transform, _material, _visualLayer,
null, 0, _spriteTextureBlock);
844 Graphics.DrawMesh(mesh, transform, _material, _visualLayer);
849 return _tintFeatures.Count != 0 ||
850 _blendShapeFeatures.Count != 0 ||
851 _customFloatChannelData.Count != 0 ||
852 _customVectorChannelData.Count != 0 ||
853 _customMatrixChannelData.Count != 0 ||
854 _customColorChannelData.Count != 0;
void RebuildAtlas(ProgressBar progress, out Texture2D[] packedTextures, out AtlasUvs channelMapping)
Actually perform the build for the atlas. This method outputs the atlas textures, and the atlas uvs t...
bool isDirty
Returns whether or not the results built by this atlas have become invalid.
void UpdateTextureList(List< LeapTextureFeature > textureFeatures)
Updates the internal list of textures given some texture features to build an atlas for....
A class that contains mapping information that specifies how a texture is packed into an atlas.
bool TryGetBlendShape(List< Vector3 > blendVerts)
Returns the blended vertices based on the current mesh this blend shape is attached to....
const string FEATURE_NAME
bool isRepresentationDirty
An internal flag that returns true if the visual representation of this graphic needs to be updated....
const string FEATURE_PREFIX
const string PROPERTY_PREFIX
This class is a base class for all graphics that can be represented by a mesh object.
abstract void RefreshMeshData()
When this method is called, the mesh property and the remappableChannels property must be assigned to...
Mesh mesh
Returns the mesh that represents this graphic. It can have any topology, any number of uv channels,...
UVChannelFlags remappableChannels
Returns an enum mask that represents the union of all channels that are allowed to be remapped for th...
virtual void prepareMaterial()
virtual void buildVertInfo()
virtual void extractSpriteRects()
virtual bool doesRequireUvChannel(UVChannelFlags channel)
virtual void postProcessMesh()
const string UV_0_FEATURE
virtual void updateCustomChannels()
List< Vector4 > _customVectorChannelData
const string TINTS_PROPERTY
virtual void GetSupportInfo(List< CustomVectorChannelFeature > features, List< SupportInfo > info)
virtual void finishMesh(bool deleteEmptyMeshes=true)
virtual void buildBlendShapes(LeapBlendShapeData blendShapeData)
virtual void buildTopology()
override void OnUpdateRenderer()
Called from LateUpdate during runtime. Use this to update the renderer using any changes made to duri...
override void OnEnableRenderer()
Called when the renderer is enabled at runtime.
List< CustomFloatChannelFeature > _floatChannelFeatures
abstract Vector3 graphicVertToMeshVert(Vector3 vertex)
List< float > _customFloatChannelData
List< LeapSpriteFeature > _spriteFeatures
virtual void GetSupportInfo(List< LeapBlendShapeFeature > features, List< SupportInfo > info)
virtual void refreshMeshData()
List< CustomVectorChannelFeature > _vectorChannelFeatures
virtual void buildColors()
const string NORMALS_FEATURE
virtual void GetSupportInfo(List< LeapSpriteFeature > features, List< SupportInfo > info)
static string GetUvFeature(UVChannelFlags flags)
List< float > _blendShapeAmounts
const string MESH_ASSET_NAME
MaterialPropertyBlock _spriteTextureBlock
virtual void uploadSpriteTextures()
virtual void updateBlendShapes()
virtual void buildGraphic()
List< Matrix4x4 > _customMatrixChannelData
virtual void buildUvs(UVChannelFlags channel)
bool _doesRequireVertInfo
const string UV_2_FEATURE
const string UV_1_FEATURE
Action< Texture2D, AtlasUvs > OnPostProcessAtlas
List< LeapTextureFeature > _textureFeatures
const string TEXTURE_ASSET_NAME
virtual void updateTinting()
List< Color > _customColorChannelData
List< UVChannelFlags > _requiredUvChannels
virtual void finishAndAddMesh(bool deleteEmptyMeshes=true)
virtual void loadAllSupportedFeatures()
const string COLORS_FEATURE
virtual void GetSupportInfo(List< LeapRuntimeTintFeature > features, List< SupportInfo > info)
virtual void GetSupportInfo(List< CustomFloatChannelFeature > features, List< SupportInfo > info)
List< CustomColorChannelFeature > _colorChannelFeatures
virtual bool doesRequireMeshNormals()
List< Vector4 > _tintColors
virtual bool doesRequireMeshColors()
override void OnDisableRenderer()
Called when the renderer is disabled at runtime.
virtual void GetSupportInfo(List< CustomMatrixChannelFeature > features, List< SupportInfo > info)
RendererTextureData _packedTextures
virtual void setupForBuilding()
virtual Vector3 blendShapeDelta(Vector3 shapeVert, Vector3 originalVert)
List< LeapBlendShapeFeature > _blendShapeFeatures
virtual void GetSupportInfo(List< CustomColorChannelFeature > features, List< SupportInfo > info)
const string UV_3_FEATURE
virtual bool doesRequireVertInfo()
abstract void graphicVertNormalToMeshVertNormal(Vector3 vertex, Vector3 normal, out Vector3 meshVert, out Vector3 meshNormal)
List< CustomMatrixChannelFeature > _matrixChannelFeatures
const string BLEND_SHAPE_AMOUNTS_PROPERTY
void drawMesh(Mesh mesh, Matrix4x4 transform)
List< LeapRuntimeTintFeature > _tintFeatures
GenerationState _generation
virtual void GetSupportInfo(List< LeapTextureFeature > features, List< SupportInfo > info)
const string CUSTOM_CHANNEL_KEYWORD
virtual void beginMesh(Mesh mesh=null)
virtual void prepareMeshes()
LeapGraphicGroup group
Gets the group this rendering method is attached to.
LeapGraphicRenderer renderer
Gets the renderer this rendering method is attached to.
const string FEATURE_NAME
Mesh GetMeshFromPoolOrNew()
void Validate(LeapRenderingMethod renderingMethod)
void Validate(LeapRenderingMethod renderingMethod)
void AssignTextures(Texture2D[] textures, string[] propertyNames)
Texture2D GetTexture(string propertyName)
This class allows you to easily give feedback of an action as it completes.
void Begin(int sections, string title, string info, Action action)
Begins a new chunk. If this call is made from within a chunk it will generate a sub-chunk that repres...
void Step(string infoString="")
Steps through one section of the current chunk. You can provide an optional info string that will be ...
LeapMeshGraphicBase graphic
static GenerationState GetGenerationState()
The support info class provides a very basic way to notify that something is fully supported,...
static SupportInfo Error(string message)
Helper getter to return a struct that signifies no support with an error message.
SupportInfo OrWorse(SupportInfo other)
Helper method that returns either the current support info struct, or the argument support info struc...
A utility struct for ease of use when you want to wrap a piece of code in a Profiler....
An object you can use to represent a single Unity layer as a dropdown in the inspector....