diff --git a/Assets/_ModularAvatar/EditModeTests/ExpressionMenuFixupTests.meta b/Assets/_ModularAvatar/EditModeTests/ExpressionMenuFixupTests.meta new file mode 100644 index 00000000..20cdccd5 --- /dev/null +++ b/Assets/_ModularAvatar/EditModeTests/ExpressionMenuFixupTests.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8caa5ed1b0324604cb456b0d5d7a92fb +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_ModularAvatar/EditModeTests/ExpressionMenuFixupTests/384x512.png b/Assets/_ModularAvatar/EditModeTests/ExpressionMenuFixupTests/384x512.png new file mode 100644 index 00000000..987f0766 Binary files /dev/null and b/Assets/_ModularAvatar/EditModeTests/ExpressionMenuFixupTests/384x512.png differ diff --git a/Assets/_ModularAvatar/EditModeTests/ExpressionMenuFixupTests/384x512.png.meta b/Assets/_ModularAvatar/EditModeTests/ExpressionMenuFixupTests/384x512.png.meta new file mode 100644 index 00000000..81228872 --- /dev/null +++ b/Assets/_ModularAvatar/EditModeTests/ExpressionMenuFixupTests/384x512.png.meta @@ -0,0 +1,116 @@ +fileFormatVersion: 2 +guid: adf82baccd885794cb63be6da2bf289e +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_ModularAvatar/EditModeTests/ExpressionMenuFixupTests/512x384.png b/Assets/_ModularAvatar/EditModeTests/ExpressionMenuFixupTests/512x384.png new file mode 100644 index 00000000..a6c3209d Binary files /dev/null and b/Assets/_ModularAvatar/EditModeTests/ExpressionMenuFixupTests/512x384.png differ diff --git a/Assets/_ModularAvatar/EditModeTests/ExpressionMenuFixupTests/512x384.png.meta b/Assets/_ModularAvatar/EditModeTests/ExpressionMenuFixupTests/512x384.png.meta new file mode 100644 index 00000000..63d7e083 --- /dev/null +++ b/Assets/_ModularAvatar/EditModeTests/ExpressionMenuFixupTests/512x384.png.meta @@ -0,0 +1,116 @@ +fileFormatVersion: 2 +guid: 9bb00a795610e1f4998410320612d6bd +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_ModularAvatar/EditModeTests/ExpressionMenuFixupTests/ExpressionMenuFixupTests.cs b/Assets/_ModularAvatar/EditModeTests/ExpressionMenuFixupTests/ExpressionMenuFixupTests.cs new file mode 100644 index 00000000..91f8ac6e --- /dev/null +++ b/Assets/_ModularAvatar/EditModeTests/ExpressionMenuFixupTests/ExpressionMenuFixupTests.cs @@ -0,0 +1,38 @@ +using nadena.dev.modular_avatar.core.editor; +using NUnit.Framework; +using VRC.SDK3.Avatars.Components; + +namespace modular_avatar_tests +{ + public class ExpressionMenuFixupTests : TestBase + { + [Test] + public void testExpMenuFixup() + { + var avatar = CreatePrefab("ExpressionsMenuFixupTestAvatar.prefab"); + AvatarProcessor.ProcessAvatar(avatar); + + var descriptor = avatar.GetComponent(); + var expMenu = descriptor.expressionsMenu; + + Assert.AreEqual(3, expMenu.controls.Count); + + Assert.AreEqual("testparam", expMenu.controls[0].parameter.name); + Assert.AreEqual(256, expMenu.controls[0].icon.height); + Assert.AreEqual(192, expMenu.controls[0].icon.width); + + Assert.AreEqual("", expMenu.controls[1].parameter.name); + Assert.AreEqual(192, expMenu.controls[1].icon.height); + Assert.AreEqual(256, expMenu.controls[1].icon.width); + + Assert.AreEqual("testparam", expMenu.controls[2].subParameters[0].name); + Assert.AreEqual("", expMenu.controls[2].subParameters[1].name); + + foreach (var label in expMenu.controls[2].labels) + { + Assert.LessOrEqual(label.icon.width, 256); + Assert.LessOrEqual(label.icon.height, 256); + } + } + } +} \ No newline at end of file diff --git a/Assets/_ModularAvatar/EditModeTests/ExpressionMenuFixupTests/ExpressionMenuFixupTests.cs.meta b/Assets/_ModularAvatar/EditModeTests/ExpressionMenuFixupTests/ExpressionMenuFixupTests.cs.meta new file mode 100644 index 00000000..978bbc9b --- /dev/null +++ b/Assets/_ModularAvatar/EditModeTests/ExpressionMenuFixupTests/ExpressionMenuFixupTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9c1bfdcd79a862e40a2c896f18ae0ca0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_ModularAvatar/EditModeTests/ExpressionMenuFixupTests/ExpressionsMenuFixupTestAvatar.prefab b/Assets/_ModularAvatar/EditModeTests/ExpressionMenuFixupTests/ExpressionsMenuFixupTestAvatar.prefab new file mode 100644 index 00000000..84ad5fdf --- /dev/null +++ b/Assets/_ModularAvatar/EditModeTests/ExpressionMenuFixupTests/ExpressionsMenuFixupTestAvatar.prefab @@ -0,0 +1,322 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &6204877465042736622 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6776946804248067904} + - component: {fileID: 5187824885137632139} + - component: {fileID: 1283586302596586804} + - component: {fileID: 3838643251041431458} + m_Layer: 0 + m_Name: ExpressionsMenuFixupTestAvatar + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &6776946804248067904 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6204877465042736622} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 20.384737, y: 1.6344047, z: 3.1785903} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &5187824885137632139 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6204877465042736622} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 542108242, guid: 67cc4cb7839cd3741b63733d5adf0442, type: 3} + m_Name: + m_EditorClassIdentifier: + Name: + ViewPosition: {x: 0, y: 1.6, z: 0.2} + Animations: 0 + ScaleIPD: 1 + lipSync: 0 + lipSyncJawBone: {fileID: 0} + lipSyncJawClosed: {x: 0, y: 0, z: 0, w: 1} + lipSyncJawOpen: {x: 0, y: 0, z: 0, w: 1} + VisemeSkinnedMesh: {fileID: 0} + MouthOpenBlendShapeName: Facial_Blends.Jaw_Down + VisemeBlendShapes: [] + unityVersion: + portraitCameraPositionOffset: {x: 0, y: 0, z: 0} + portraitCameraRotationOffset: {x: 0, y: 1, z: 0, w: -0.00000004371139} + networkIDs: [] + customExpressions: 1 + expressionsMenu: {fileID: 11400000, guid: f2f0d7df290a6bc48bcb1efe964c6281, type: 2} + expressionParameters: {fileID: 11400000, guid: 16746f1009cf9ae4fb8391d44dc8257a, + type: 2} + enableEyeLook: 0 + customEyeLookSettings: + eyeMovement: + confidence: 0.5 + excitement: 0.5 + leftEye: {fileID: 0} + rightEye: {fileID: 0} + eyesLookingStraight: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyesLookingUp: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyesLookingDown: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyesLookingLeft: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyesLookingRight: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidType: 0 + upperLeftEyelid: {fileID: 0} + upperRightEyelid: {fileID: 0} + lowerLeftEyelid: {fileID: 0} + lowerRightEyelid: {fileID: 0} + eyelidsDefault: + upper: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + lower: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidsClosed: + upper: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + lower: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidsLookingUp: + upper: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + lower: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidsLookingDown: + upper: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + lower: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidsSkinnedMesh: {fileID: 0} + eyelidsBlendshapes: + customizeAnimationLayers: 0 + baseAnimationLayers: + - isEnabled: 0 + type: 0 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + - isEnabled: 0 + type: 4 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + - isEnabled: 0 + type: 5 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + specialAnimationLayers: + - isEnabled: 0 + type: 6 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + - isEnabled: 0 + type: 7 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + - isEnabled: 0 + type: 8 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + AnimationPreset: {fileID: 0} + animationHashSet: [] + autoFootsteps: 1 + autoLocomotion: 1 + collider_head: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_torso: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_footR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_footL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_handR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_handL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerIndexL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerMiddleL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerRingL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerLittleL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerIndexR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerMiddleR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerRingR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerLittleR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &1283586302596586804 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6204877465042736622} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -1427037861, guid: 4ecd63eff847044b68db9453ce219299, type: 3} + m_Name: + m_EditorClassIdentifier: + launchedFromSDKPipeline: 0 + completedSDKPipeline: 0 + blueprintId: + contentType: 0 + assetBundleUnityVersion: + fallbackStatus: 0 +--- !u!95 &3838643251041431458 +Animator: + serializedVersion: 3 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6204877465042736622} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 0} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorControllerStateOnDisable: 0 diff --git a/Assets/_ModularAvatar/EditModeTests/ExpressionMenuFixupTests/ExpressionsMenuFixupTestAvatar.prefab.meta b/Assets/_ModularAvatar/EditModeTests/ExpressionMenuFixupTests/ExpressionsMenuFixupTestAvatar.prefab.meta new file mode 100644 index 00000000..48f3e97c --- /dev/null +++ b/Assets/_ModularAvatar/EditModeTests/ExpressionMenuFixupTests/ExpressionsMenuFixupTestAvatar.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 188009d5762353447bb0a11e779c1abb +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_ModularAvatar/EditModeTests/ExpressionMenuFixupTests/parameters.asset b/Assets/_ModularAvatar/EditModeTests/ExpressionMenuFixupTests/parameters.asset new file mode 100644 index 00000000..ba1df815 --- /dev/null +++ b/Assets/_ModularAvatar/EditModeTests/ExpressionMenuFixupTests/parameters.asset @@ -0,0 +1,20 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -1506855854, guid: 67cc4cb7839cd3741b63733d5adf0442, type: 3} + m_Name: parameters + m_EditorClassIdentifier: + parameters: + - name: testparam + valueType: 0 + saved: 1 + defaultValue: 0 + networkSynced: 1 diff --git a/Assets/_ModularAvatar/EditModeTests/ExpressionMenuFixupTests/parameters.asset.meta b/Assets/_ModularAvatar/EditModeTests/ExpressionMenuFixupTests/parameters.asset.meta new file mode 100644 index 00000000..8f6bed4c --- /dev/null +++ b/Assets/_ModularAvatar/EditModeTests/ExpressionMenuFixupTests/parameters.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 16746f1009cf9ae4fb8391d44dc8257a +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_ModularAvatar/EditModeTests/ExpressionMenuFixupTests/test menu.asset b/Assets/_ModularAvatar/EditModeTests/ExpressionMenuFixupTests/test menu.asset new file mode 100644 index 00000000..c19977fa --- /dev/null +++ b/Assets/_ModularAvatar/EditModeTests/ExpressionMenuFixupTests/test menu.asset @@ -0,0 +1,55 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -340790334, guid: 67cc4cb7839cd3741b63733d5adf0442, type: 3} + m_Name: test menu + m_EditorClassIdentifier: + controls: + - name: retain + icon: {fileID: 2800000, guid: adf82baccd885794cb63be6da2bf289e, type: 3} + type: 101 + parameter: + name: testparam + value: 1 + style: 0 + subMenu: {fileID: 0} + subParameters: [] + labels: [] + - name: redact + icon: {fileID: 2800000, guid: 9bb00a795610e1f4998410320612d6bd, type: 3} + type: 101 + parameter: + name: redact + value: 1 + style: 0 + subMenu: {fileID: 0} + subParameters: [] + labels: [] + - name: New Control + icon: {fileID: 0} + type: 201 + parameter: + name: + value: 1 + style: 0 + subMenu: {fileID: 0} + subParameters: + - name: testparam + - name: redact + labels: + - name: + icon: {fileID: 2800000, guid: 9bb00a795610e1f4998410320612d6bd, type: 3} + - name: + icon: {fileID: 2800000, guid: adf82baccd885794cb63be6da2bf289e, type: 3} + - name: + icon: {fileID: 2800000, guid: 9bb00a795610e1f4998410320612d6bd, type: 3} + - name: + icon: {fileID: 2800000, guid: adf82baccd885794cb63be6da2bf289e, type: 3} diff --git a/Assets/_ModularAvatar/EditModeTests/ExpressionMenuFixupTests/test menu.asset.meta b/Assets/_ModularAvatar/EditModeTests/ExpressionMenuFixupTests/test menu.asset.meta new file mode 100644 index 00000000..24b88168 --- /dev/null +++ b/Assets/_ModularAvatar/EditModeTests/ExpressionMenuFixupTests/test menu.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f2f0d7df290a6bc48bcb1efe964c6281 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/nadena.dev.modular-avatar/Editor/AvatarProcessor.cs b/Packages/nadena.dev.modular-avatar/Editor/AvatarProcessor.cs index c450d9fd..527ad00c 100644 --- a/Packages/nadena.dev.modular-avatar/Editor/AvatarProcessor.cs +++ b/Packages/nadena.dev.modular-avatar/Editor/AvatarProcessor.cs @@ -221,6 +221,8 @@ namespace nadena.dev.modular_avatar.core.editor context.AnimationDatabase.Commit(); new GCGameObjectsPass(context, avatarGameObject).OnPreprocessAvatar(); + + FixupExpressionsMenuPass.FixupExpressionsMenu(context); context.CommitReferencedAssets(); diff --git a/Packages/nadena.dev.modular-avatar/Editor/BuildContext.cs b/Packages/nadena.dev.modular-avatar/Editor/BuildContext.cs index 47bc3db6..248edd24 100644 --- a/Packages/nadena.dev.modular-avatar/Editor/BuildContext.cs +++ b/Packages/nadena.dev.modular-avatar/Editor/BuildContext.cs @@ -102,20 +102,6 @@ namespace nadena.dev.modular_avatar.core.editor foreach (var control in newMenu.controls) { - if (Util.ValidateExpressionMenuIcon(control.icon) != Util.ValidateExpressionMenuIconResult.Success) - control.icon = null; - - for (int i = 0; i < control.labels.Length; i++) - { - var label = control.labels[i]; - var labelResult = Util.ValidateExpressionMenuIcon(label.icon); - if (labelResult != Util.ValidateExpressionMenuIconResult.Success) - { - label.icon = null; - control.labels[i] = label; - } - } - if (control.type == VRCExpressionsMenu.Control.ControlType.SubMenu) { control.subMenu = CloneMenu(control.subMenu); diff --git a/Packages/nadena.dev.modular-avatar/Editor/FixupPasses.meta b/Packages/nadena.dev.modular-avatar/Editor/FixupPasses.meta new file mode 100644 index 00000000..aa4a4bd8 --- /dev/null +++ b/Packages/nadena.dev.modular-avatar/Editor/FixupPasses.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 597d4035b7eb43e180a013ceac128a84 +timeCreated: 1694687629 \ No newline at end of file diff --git a/Packages/nadena.dev.modular-avatar/Editor/FixupPasses/FixupExpressionsMenuPass.cs b/Packages/nadena.dev.modular-avatar/Editor/FixupPasses/FixupExpressionsMenuPass.cs new file mode 100644 index 00000000..29d0fae0 --- /dev/null +++ b/Packages/nadena.dev.modular-avatar/Editor/FixupPasses/FixupExpressionsMenuPass.cs @@ -0,0 +1,136 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using UnityEditor; +using UnityEngine; +using UnityEngine.Experimental.Rendering; +using VRC.SDK3.Avatars.ScriptableObjects; + +namespace nadena.dev.modular_avatar.core.editor +{ + internal class FixupExpressionsMenuPass + { + internal static void FixupExpressionsMenu(BuildContext context) + { + var expressionsMenu = context.AvatarDescriptor.expressionsMenu; + if (expressionsMenu == null) return; + + var parameters = context.AvatarDescriptor.expressionParameters?.parameters + ?? new VRCExpressionParameters.Parameter[0]; + var parameterNames = parameters.Select(p=> p.name).ToImmutableHashSet(); + + if (!Util.IsTemporaryAsset(expressionsMenu)) + { + expressionsMenu = context.CloneMenu(expressionsMenu); + context.AvatarDescriptor.expressionsMenu = expressionsMenu; + } + + // Walk menu recursively + var visitedMenus = new HashSet(); + var iconMapping = new Dictionary(); + + VisitMenu(expressionsMenu); + + void VisitMenu(VRCExpressionsMenu menu) + { + if (!visitedMenus.Add(menu)) return; + + foreach (var control in menu.controls) + { + if (control.parameter != null && + !string.IsNullOrEmpty(control.parameter.name) && + !parameterNames.Contains(control.parameter.name)) + { + control.parameter.name = ""; + } + + foreach (var subParam in control.subParameters ?? Array.Empty()) + { + if (subParam != null && + !string.IsNullOrEmpty(subParam.name) && + !parameterNames.Contains(subParam.name)) + { + subParam.name = ""; + } + } + + if (control.icon != null) + { + if (!iconMapping.TryGetValue(control.icon, out var newIcon)) + { + iconMapping[control.icon] = newIcon = MaybeScaleIcon(context, control.icon); + } + + control.icon = newIcon; + } + + if (control.labels != null) + { + for (int i = 0; i < control.labels.Length; i++) + { + var label = control.labels[i]; + + if (label.icon != null) + { + if (!iconMapping.TryGetValue(label.icon, out var newIcon)) + { + iconMapping[label.icon] = newIcon = MaybeScaleIcon(context, label.icon); + } + + label.icon = newIcon; + control.labels[i] = label; + } + } + } + } + } + } + + #if UNITY_ANDROID + private const TextureFormat TargetFormat = TextureFormat.ASTC_4x4; + #else + private const TextureFormat TargetFormat = TextureFormat.DXT5; + #endif + + private static Texture2D MaybeScaleIcon(BuildContext context, Texture2D original) + { + if (original.width <= 256 && original.height <= 256 && IsCompressedFormat(original.format)) + { + return original; + } + + var newRatio = Math.Min(256f / original.width, 256f / original.height); + var newWidth = Math.Min(256, Mathf.RoundToInt(original.width * newRatio)); + var newHeight = Math.Min(256, Mathf.RoundToInt(original.height * newRatio)); + + var newTex = new Texture2D(newWidth, newHeight, TextureFormat.RGBA32, true); + context.SaveAsset(newTex); + + var tmpRenderTex = RenderTexture.GetTemporary(newWidth, newHeight, 0, RenderTextureFormat.ARGB32); + var originalActiveRenderTex = RenderTexture.active; + + try + { + Graphics.Blit(original, tmpRenderTex); + RenderTexture.active = tmpRenderTex; + newTex.ReadPixels(new Rect(0, 0, newWidth, newHeight), 0, 0); + newTex.Apply(); + EditorUtility.CompressTexture(newTex, TargetFormat, TextureCompressionQuality.Normal); + + return newTex; + } + finally + { + RenderTexture.active = originalActiveRenderTex; + RenderTexture.ReleaseTemporary(tmpRenderTex); + } + } + + private static bool IsCompressedFormat(TextureFormat format) + { + var name = format.ToString(); + return name.StartsWith("DXT") || name.StartsWith("ASTC"); + } + } +} \ No newline at end of file diff --git a/Packages/nadena.dev.modular-avatar/Editor/FixupPasses/FixupExpressionsMenuPass.cs.meta b/Packages/nadena.dev.modular-avatar/Editor/FixupPasses/FixupExpressionsMenuPass.cs.meta new file mode 100644 index 00000000..889510ab --- /dev/null +++ b/Packages/nadena.dev.modular-avatar/Editor/FixupPasses/FixupExpressionsMenuPass.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 1020bef86d91452ba6b138c249d25bb5 +timeCreated: 1694688050 \ No newline at end of file