diff --git a/.idea/.idea.HALLUCINATE/.idea/workspace.xml b/.idea/.idea.HALLUCINATE/.idea/workspace.xml index 6596c14b..e7858031 100644 --- a/.idea/.idea.HALLUCINATE/.idea/workspace.xml +++ b/.idea/.idea.HALLUCINATE/.idea/workspace.xml @@ -6,6 +6,10 @@ + + + + - @@ -25,6 +28,7 @@ + @@ -160,6 +164,7 @@ + @@ -169,6 +174,7 @@ + diff --git a/Assets/Scove/UITesting.unity b/Assets/Scove/UITesting.unity index 594fb148..0001a4a2 100644 --- a/Assets/Scove/UITesting.unity +++ b/Assets/Scove/UITesting.unity @@ -447,6 +447,75 @@ RectTransform: m_AnchoredPosition: {x: 0, y: 0} m_SizeDelta: {x: 0, y: 0} m_Pivot: {x: 0, y: 0} +--- !u!1 &1218059261 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1218059262} + - component: {fileID: 1218059264} + - component: {fileID: 1218059263} + m_Layer: 0 + m_Name: GameObject + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1218059262 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1218059261} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 4687.4375, y: -0.00017, z: 5715.602} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1218059263 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1218059261} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -688943309, guid: 178891466f3f1d447aa5cfbf83d7a8b5, type: 3} + m_Name: + m_EditorClassIdentifier: UXImporterUnityUiToolKit.dll::FigmaToUnityUiToolKit.DataHubRoot + _dataHub: {fileID: 0} +--- !u!114 &1218059264 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1218059261} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 19102, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: UnityEngine.dll::UnityEngine.UIElements.UIDocument + m_PanelSettings: {fileID: 0} + m_ParentUI: {fileID: 0} + sourceAsset: {fileID: 0} + m_SortingOrder: 0 + m_Position: 0 + m_WorldSpaceSizeMode: 1 + m_WorldSpaceWidth: 1920 + m_WorldSpaceHeight: 1080 + m_PivotReferenceSize: 0 + m_Pivot: 0 + m_WorldSpaceCollider: {fileID: 0} --- !u!1 &1234188887 GameObject: m_ObjectHideFlags: 0 @@ -586,6 +655,14 @@ PrefabInstance: propertyPath: m_Name value: Game_UI objectReference: {fileID: 0} + - target: {fileID: 4705652128730820444, guid: dbc10f9802034f443bd0ac18329875c5, type: 3} + propertyPath: m_SizeDelta.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4705652128730820444, guid: dbc10f9802034f443bd0ac18329875c5, type: 3} + propertyPath: m_SizeDelta.y + value: 0 + objectReference: {fileID: 0} - target: {fileID: 5704081308080066381, guid: dbc10f9802034f443bd0ac18329875c5, type: 3} propertyPath: m_Pivot.x value: 0 @@ -800,3 +877,4 @@ SceneRoots: - {fileID: 1234188889} - {fileID: 671850023} - {fileID: 705824387} + - {fileID: 1218059262} diff --git a/Assets/Temp.meta b/Assets/Temp.meta new file mode 100644 index 00000000..17603306 --- /dev/null +++ b/Assets/Temp.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d120eab0fb2b73041b12a7af764c2966 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Temp/Section_1.json b/Assets/Temp/Section_1.json new file mode 100644 index 00000000..55a0d3c9 --- /dev/null +++ b/Assets/Temp/Section_1.json @@ -0,0 +1,2111 @@ +{ + "flattenLayers": [ + { + "id": "2022:2", + "name": "Section 1", + "type": "SECTION", + "parentID": "0:1", + "parentName": "Game_UI", + "childrenNames": [ + { + "id": "2008:2", + "name": "Panel_GlobalSettings", + "type": "FRAME", + "parentID": "2022:2", + "parentName": "Section 1" + }, + { + "id": "2008:3", + "name": "Modal_PauseMenu", + "type": "FRAME", + "parentID": "2022:2", + "parentName": "Section 1" + }, + { + "id": "2008:4", + "name": "Canvas_GameplayHUD", + "type": "FRAME", + "parentID": "2022:2", + "parentName": "Section 1" + }, + { + "id": "2008:5", + "name": "Modal_Login", + "type": "FRAME", + "parentID": "2022:2", + "parentName": "Section 1" + }, + { + "id": "2008:6", + "name": "Panel_ProfileMenu", + "type": "FRAME", + "parentID": "2022:2", + "parentName": "Section 1" + }, + { + "id": "2008:7", + "name": "Panel_Lobby", + "type": "FRAME", + "parentID": "2022:2", + "parentName": "Section 1" + }, + { + "id": "2008:8", + "name": "Panel_MainMenu", + "type": "FRAME", + "parentID": "2022:2", + "parentName": "Section 1" + }, + { + "id": "2013:81", + "name": "osu_2026-05-13_22-06-22 1", + "type": "RECTANGLE", + "parentID": "2022:2", + "parentName": "Section 1" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_SectionNode": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.2666666805744171, + "g": 0.2666666805744171, + "b": 0.2666666805744171 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "opaqueNodeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "dimensionAndPositionMixin": { + "width": 18907, + "height": 4839, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + } + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + } + } + }, + { + "id": "2008:2", + "name": "Panel_GlobalSettings", + "type": "FRAME", + "parentID": "2022:2", + "parentName": "Section 1", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_FrameNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 1, + "g": 1, + "b": 1 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 1929, + "height": 1080, + "tx": 16452, + "ty": 1195, + "x": 16452, + "y": 1195 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": -180, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "NONE", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 0, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": true, + "guides": [] + } + } + } + }, + { + "id": "2008:3", + "name": "Modal_PauseMenu", + "type": "FRAME", + "parentID": "2022:2", + "parentName": "Section 1", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_FrameNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 1, + "g": 1, + "b": 1 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 1929, + "height": 1080, + "tx": 13796, + "ty": 1195, + "x": 13796, + "y": 1195 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": -180, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "NONE", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 0, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": true, + "guides": [] + } + } + } + }, + { + "id": "2008:4", + "name": "Canvas_GameplayHUD", + "type": "FRAME", + "parentID": "2022:2", + "parentName": "Section 1", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_FrameNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 1, + "g": 1, + "b": 1 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 1929, + "height": 1080, + "tx": 11140, + "ty": 1195, + "x": 11140, + "y": 1195 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": -180, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "NONE", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 0, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": true, + "guides": [] + } + } + } + }, + { + "id": "2008:5", + "name": "Modal_Login", + "type": "FRAME", + "parentID": "2022:2", + "parentName": "Section 1", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_FrameNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 1, + "g": 1, + "b": 1 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 1929, + "height": 1080, + "tx": 8484, + "ty": 1195, + "x": 8484, + "y": 1195 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": -180, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "NONE", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 0, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": true, + "guides": [] + } + } + } + }, + { + "id": "2008:6", + "name": "Panel_ProfileMenu", + "type": "FRAME", + "parentID": "2022:2", + "parentName": "Section 1", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_FrameNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 1, + "g": 1, + "b": 1 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 1929, + "height": 1080, + "tx": 5828, + "ty": 1195, + "x": 5828, + "y": 1195 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": -180, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "NONE", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 0, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": true, + "guides": [] + } + } + } + }, + { + "id": "2008:7", + "name": "Panel_Lobby", + "type": "FRAME", + "parentID": "2022:2", + "parentName": "Section 1", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_FrameNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 1, + "g": 1, + "b": 1 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 1929, + "height": 1080, + "tx": 3172, + "ty": 1195, + "x": 3172, + "y": 1195 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": -180, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "NONE", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 0, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": true, + "guides": [] + } + } + } + }, + { + "id": "2008:8", + "name": "Panel_MainMenu", + "type": "FRAME", + "parentID": "2022:2", + "parentName": "Section 1", + "childrenNames": [ + { + "id": "2013:128", + "name": "Osu_Button_Container", + "type": "FRAME", + "parentID": "2008:8", + "parentName": "Panel_MainMenu" + }, + { + "id": "2013:123", + "name": "Background_Container", + "type": "INSTANCE", + "parentID": "2008:8", + "parentName": "Panel_MainMenu" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_FrameNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 1, + "g": 1, + "b": 1 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 1920, + "height": 1080, + "tx": 525, + "ty": 1195, + "x": 525, + "y": 1195 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "VERTICAL", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "CENTER", + "counterAxisAlignItems": "CENTER", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 10, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "VERTICAL", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "CENTER", + "counterAxisAlignItems": "CENTER", + "itemSpacing": 10 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": true, + "guides": [] + } + } + } + }, + { + "id": "2013:128", + "name": "Osu_Button_Container", + "type": "FRAME", + "parentID": "2008:8", + "parentName": "Panel_MainMenu", + "childrenNames": [ + { + "id": "2013:129", + "name": "Osu_Button_Bottom", + "type": "ELLIPSE", + "parentID": "2013:128", + "parentName": "Osu_Button_Container" + }, + { + "id": "2013:130", + "name": "Osu_Button_Inner", + "type": "ELLIPSE", + "parentID": "2013:128", + "parentName": "Osu_Button_Container" + }, + { + "id": "2013:131", + "name": "Osu_Button_Text", + "type": "FRAME", + "parentID": "2013:128", + "parentName": "Osu_Button_Container" + }, + { + "id": "2013:133", + "name": "Osu_Button_Stoke", + "type": "ELLIPSE", + "parentID": "2013:128", + "parentName": "Osu_Button_Container" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_FrameNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 648, + "height": 648, + "tx": 636, + "ty": -329, + "x": 636, + "y": -329 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "NONE", + "layoutWrap": "NO_WRAP", + "paddingLeft": 10, + "paddingRight": 10, + "paddingTop": 10, + "paddingBottom": 10, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "CENTER", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 10, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": { + "x": 648, + "y": 648 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + } + } + }, + { + "id": "2013:129", + "name": "Osu_Button_Bottom", + "type": "ELLIPSE", + "parentID": "2013:128", + "parentName": "Osu_Button_Container", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": true, + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.8509804010391235, + "g": 0.8509804010391235, + "b": 0.8509804010391235 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 628, + "height": 628, + "tx": 10, + "ty": 10, + "x": 10, + "y": 10 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "aspectRatioLockMixin": { + "targetAspectRatio": { + "x": 628, + "y": 628 + } + } + } + }, + { + "id": "2013:130", + "name": "Osu_Button_Inner", + "type": "ELLIPSE", + "parentID": "2013:128", + "parentName": "Osu_Button_Container", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": true, + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.9647058844566345, + "g": 0.3843137323856354, + "b": 0.6470588445663452 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 628, + "height": 628, + "tx": 10, + "ty": 10, + "x": 10, + "y": 10 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "aspectRatioLockMixin": { + "targetAspectRatio": { + "x": 566, + "y": 566 + } + } + } + }, + { + "id": "2013:131", + "name": "Osu_Button_Text", + "type": "FRAME", + "parentID": "2013:128", + "parentName": "Osu_Button_Container", + "childrenNames": [ + { + "id": "2013:132", + "name": "B4B4 Y4G4", + "type": "TEXT", + "parentID": "2013:131", + "parentName": "Osu_Button_Text" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_FrameNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 388, + "height": 330, + "tx": 130, + "ty": 159, + "x": 130, + "y": 159 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "layoutWrap": "NO_WRAP", + "paddingLeft": 10, + "paddingRight": 10, + "paddingTop": 10, + "paddingBottom": 10, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "AUTO", + "primaryAxisAlignItems": "CENTER", + "counterAxisAlignItems": "CENTER", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 10, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "paddingLeft": 10, + "paddingRight": 10, + "paddingTop": 10, + "paddingBottom": 10, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "AUTO", + "primaryAxisAlignItems": "CENTER", + "counterAxisAlignItems": "CENTER", + "itemSpacing": 10 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + } + } + }, + { + "id": "2013:132", + "name": "B4B4 Y4G4", + "type": "TEXT", + "parentID": "2013:131", + "parentName": "Osu_Button_Text", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_TextNode": { + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 1, + "g": 1, + "b": 1 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 368, + "height": 310, + "tx": 10, + "ty": 10, + "x": 10, + "y": 10 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "nonResizableTextMixin": { + "paragraphIndent": 0, + "listSpacing": 0, + "hangingPunctuation": false, + "hangingList": false, + "fontSize": 128, + "fontName": { + "family": "Inter", + "style": "Black Italic" + }, + "fontWeight": 900, + "textCase": "ORIGINAL", + "textDecoration": "NONE", + "textDecorationStyle": null, + "letterSpacing": { + "value": 0, + "unit": "PERCENT" + }, + "lineHeight": { + "unit": "AUTO" + }, + "characters": "B4B4\nY4G4" + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "textAlignHorizontal": "CENTER", + "textAlignVertical": "CENTER", + "textAutoResize": "WIDTH_AND_HEIGHT", + "textTruncation": "DISABLED", + "maxLines": null, + "autoRename": true, + "textStyleId": "" + } + }, + { + "id": "2013:133", + "name": "Osu_Button_Stoke", + "type": "ELLIPSE", + "parentID": "2013:128", + "parentName": "Osu_Button_Container", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": true, + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.8509804010391235, + "g": 0.8509804010391235, + "b": 0.8509804010391235 + }, + "visible": true, + "opacity": 0 + } + ] + }, + "minimalStrokesMixin": { + "stroke": { + "strokes": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 1, + "g": 1, + "b": 1 + }, + "visible": true, + "opacity": 1 + } + ], + "strokeWeight": 34, + "strokeAlign": "OUTSIDE", + "strokeJoin": "MITER" + } + }, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 566, + "height": 566, + "tx": 41, + "ty": 41, + "x": 41, + "y": 41 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "aspectRatioLockMixin": { + "targetAspectRatio": { + "x": 566, + "y": 566 + } + } + } + }, + { + "id": "2013:123", + "name": "Background_Container", + "type": "INSTANCE", + "parentID": "2008:8", + "parentName": "Panel_MainMenu", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": true + }, + "nodeParameters_InstanceNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 1920, + "height": 1080, + "tx": 0, + "ty": 329, + "x": 0, + "y": 329 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "NONE", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 0, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": true, + "guides": [] + } + }, + "variantMixin": { + "variantProperties": { + "BG": "BG3" + } + }, + "button": false + } + }, + { + "id": "2013:81", + "name": "osu_2026-05-13_22-06-22 1", + "type": "RECTANGLE", + "parentID": "2022:2", + "parentName": "Section 1", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": true, + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 1920, + "height": 1080, + "tx": 590, + "ty": 2438, + "x": 590, + "y": 2438 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "aspectRatioLockMixin": { + "targetAspectRatio": { + "x": 1920, + "y": 1080 + } + } + } + } + ], + "visualNode": [ + { + "id": "2013:129", + "name": "Osu_Button_Bottom", + "type": "ELLIPSE", + "parentID": "2013:128", + "parentName": "Osu_Button_Container", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": true, + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.8509804010391235, + "g": 0.8509804010391235, + "b": 0.8509804010391235 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 628, + "height": 628, + "tx": 10, + "ty": 10, + "x": 10, + "y": 10 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "aspectRatioLockMixin": { + "targetAspectRatio": { + "x": 628, + "y": 628 + } + } + } + }, + { + "id": "2013:130", + "name": "Osu_Button_Inner", + "type": "ELLIPSE", + "parentID": "2013:128", + "parentName": "Osu_Button_Container", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": true, + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.9647058844566345, + "g": 0.3843137323856354, + "b": 0.6470588445663452 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 628, + "height": 628, + "tx": 10, + "ty": 10, + "x": 10, + "y": 10 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "aspectRatioLockMixin": { + "targetAspectRatio": { + "x": 566, + "y": 566 + } + } + } + }, + { + "id": "2013:133", + "name": "Osu_Button_Stoke", + "type": "ELLIPSE", + "parentID": "2013:128", + "parentName": "Osu_Button_Container", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": true, + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.8509804010391235, + "g": 0.8509804010391235, + "b": 0.8509804010391235 + }, + "visible": true, + "opacity": 0 + } + ] + }, + "minimalStrokesMixin": { + "stroke": { + "strokes": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 1, + "g": 1, + "b": 1 + }, + "visible": true, + "opacity": 1 + } + ], + "strokeWeight": 34, + "strokeAlign": "OUTSIDE", + "strokeJoin": "MITER" + } + }, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 566, + "height": 566, + "tx": 41, + "ty": 41, + "x": 41, + "y": 41 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "aspectRatioLockMixin": { + "targetAspectRatio": { + "x": 566, + "y": 566 + } + } + } + }, + { + "id": "2013:123", + "name": "Background_Container", + "type": "INSTANCE", + "parentID": "2008:8", + "parentName": "Panel_MainMenu", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": true + }, + "nodeParameters_InstanceNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 1920, + "height": 1080, + "tx": 0, + "ty": 329, + "x": 0, + "y": 329 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "NONE", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 0, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": true, + "guides": [] + } + }, + "variantMixin": { + "variantProperties": { + "BG": "BG3" + } + }, + "button": false + } + }, + { + "id": "2013:81", + "name": "osu_2026-05-13_22-06-22 1", + "type": "RECTANGLE", + "parentID": "2022:2", + "parentName": "Section 1", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": true, + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 1920, + "height": 1080, + "tx": 590, + "ty": 2438, + "x": 590, + "y": 2438 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "aspectRatioLockMixin": { + "targetAspectRatio": { + "x": 1920, + "y": 1080 + } + } + } + } + ] +} \ No newline at end of file diff --git a/Assets/Temp/Section_1.json.meta b/Assets/Temp/Section_1.json.meta new file mode 100644 index 00000000..d281c475 --- /dev/null +++ b/Assets/Temp/Section_1.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 27b1b7c76d74f1a4b823e2cea76aa62c +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Temp/images.meta b/Assets/Temp/images.meta new file mode 100644 index 00000000..584f3373 --- /dev/null +++ b/Assets/Temp/images.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7b94eafedddb0c04d974ba1c8fa25843 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Temp/images/2013_123.png b/Assets/Temp/images/2013_123.png new file mode 100644 index 00000000..7c8cefe3 Binary files /dev/null and b/Assets/Temp/images/2013_123.png differ diff --git a/Assets/Temp/images/2013_123.png.meta b/Assets/Temp/images/2013_123.png.meta new file mode 100644 index 00000000..656c7d7b --- /dev/null +++ b/Assets/Temp/images/2013_123.png.meta @@ -0,0 +1,130 @@ +fileFormatVersion: 2 +guid: e3f5cc198f705e84a80152d1d3c18ec3 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 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: 1 + 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: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 4 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Temp/images/2013_129.png b/Assets/Temp/images/2013_129.png new file mode 100644 index 00000000..086469fa Binary files /dev/null and b/Assets/Temp/images/2013_129.png differ diff --git a/Assets/Temp/images/2013_129.png.meta b/Assets/Temp/images/2013_129.png.meta new file mode 100644 index 00000000..c7cccf1a --- /dev/null +++ b/Assets/Temp/images/2013_129.png.meta @@ -0,0 +1,130 @@ +fileFormatVersion: 2 +guid: d0d24ca34a852eb40ac7a722a0004fb7 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 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: 1 + 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: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 4 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Temp/images/2013_130.png b/Assets/Temp/images/2013_130.png new file mode 100644 index 00000000..0a9434f5 Binary files /dev/null and b/Assets/Temp/images/2013_130.png differ diff --git a/Assets/Temp/images/2013_130.png.meta b/Assets/Temp/images/2013_130.png.meta new file mode 100644 index 00000000..d8c07836 --- /dev/null +++ b/Assets/Temp/images/2013_130.png.meta @@ -0,0 +1,130 @@ +fileFormatVersion: 2 +guid: 8e67c60a36198d04485cb81643e360b1 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 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: 1 + 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: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 4 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Temp/images/2013_133.png b/Assets/Temp/images/2013_133.png new file mode 100644 index 00000000..3b7b6294 Binary files /dev/null and b/Assets/Temp/images/2013_133.png differ diff --git a/Assets/Temp/images/2013_133.png.meta b/Assets/Temp/images/2013_133.png.meta new file mode 100644 index 00000000..0d183b28 --- /dev/null +++ b/Assets/Temp/images/2013_133.png.meta @@ -0,0 +1,130 @@ +fileFormatVersion: 2 +guid: a382aca638da8b64ca42bad0b839d00c +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 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: 1 + 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: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 4 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Temp/images/2013_81.png b/Assets/Temp/images/2013_81.png new file mode 100644 index 00000000..1f3dc703 Binary files /dev/null and b/Assets/Temp/images/2013_81.png differ diff --git a/Assets/Temp/images/2013_81.png.meta b/Assets/Temp/images/2013_81.png.meta new file mode 100644 index 00000000..9987c1f9 --- /dev/null +++ b/Assets/Temp/images/2013_81.png.meta @@ -0,0 +1,130 @@ +fileFormatVersion: 2 +guid: 067507b989868c64084dabb40d85ab19 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 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: 1 + 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: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 4 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/UXImporterUnityUiToolKit.meta b/Assets/UXImporterUnityUiToolKit.meta new file mode 100644 index 00000000..9e001cce --- /dev/null +++ b/Assets/UXImporterUnityUiToolKit.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9c962719e2f05ae47bdc320ee7ff2e54 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/UXImporterUnityUiToolKit/.gemini-workspace-history/active-context.md b/Assets/UXImporterUnityUiToolKit/.gemini-workspace-history/active-context.md new file mode 100644 index 00000000..5b572ad1 --- /dev/null +++ b/Assets/UXImporterUnityUiToolKit/.gemini-workspace-history/active-context.md @@ -0,0 +1 @@ +No previous session history found for this workspace. \ No newline at end of file diff --git a/Assets/UXImporterUnityUiToolKit/.gemini-workspace-history/session-2026-05-18-01-26.json.gz b/Assets/UXImporterUnityUiToolKit/.gemini-workspace-history/session-2026-05-18-01-26.json.gz new file mode 100644 index 00000000..312b794c Binary files /dev/null and b/Assets/UXImporterUnityUiToolKit/.gemini-workspace-history/session-2026-05-18-01-26.json.gz differ diff --git a/Assets/UXImporterUnityUiToolKit/CHANGELOG.md b/Assets/UXImporterUnityUiToolKit/CHANGELOG.md new file mode 100644 index 00000000..5aaa434b --- /dev/null +++ b/Assets/UXImporterUnityUiToolKit/CHANGELOG.md @@ -0,0 +1,6 @@ +# Changelog + +## [0.1.6] - 2025-12-29 +### Fixed +- Fixed a bug where `unity-text-align` was output instead of `-unity-text-align`. +- Fixed an issue where Addressable Group Schemas were incorrectly instantiated using `new`. \ No newline at end of file diff --git a/Assets/UXImporterUnityUiToolKit/CHANGELOG.md.meta b/Assets/UXImporterUnityUiToolKit/CHANGELOG.md.meta new file mode 100644 index 00000000..fb0abbe7 --- /dev/null +++ b/Assets/UXImporterUnityUiToolKit/CHANGELOG.md.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 2198b75ff830ac24396d1481f8817f55 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 337438 + packageName: UX Importer for UI Toolkit + packageVersion: 0.1.6 + assetPath: Assets/UXImporterUnityUiToolKit/CHANGELOG.md + uploadId: 840350 diff --git a/Assets/UXImporterUnityUiToolKit/Editor.meta b/Assets/UXImporterUnityUiToolKit/Editor.meta new file mode 100644 index 00000000..938e4fb9 --- /dev/null +++ b/Assets/UXImporterUnityUiToolKit/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2b1e9d8f8b3babc4e92a9dcd30d5d6a4 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/UXImporterUnityUiToolKit/Editor/JsonDiffPatchDotNet.dll b/Assets/UXImporterUnityUiToolKit/Editor/JsonDiffPatchDotNet.dll new file mode 100644 index 00000000..e248c861 Binary files /dev/null and b/Assets/UXImporterUnityUiToolKit/Editor/JsonDiffPatchDotNet.dll differ diff --git a/Assets/UXImporterUnityUiToolKit/Editor/JsonDiffPatchDotNet.dll.meta b/Assets/UXImporterUnityUiToolKit/Editor/JsonDiffPatchDotNet.dll.meta new file mode 100644 index 00000000..bd6cbb28 --- /dev/null +++ b/Assets/UXImporterUnityUiToolKit/Editor/JsonDiffPatchDotNet.dll.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: db12bd705fb15ce4888fb9e049cb5359 +AssetOrigin: + serializedVersion: 1 + productId: 337438 + packageName: UX Importer for UI Toolkit + packageVersion: 0.1.6 + assetPath: Assets/UXImporterUnityUiToolKit/Editor/JsonDiffPatchDotNet.dll + uploadId: 840350 diff --git a/Assets/UXImporterUnityUiToolKit/Editor/ToolAsset.meta b/Assets/UXImporterUnityUiToolKit/Editor/ToolAsset.meta new file mode 100644 index 00000000..7110b5b0 --- /dev/null +++ b/Assets/UXImporterUnityUiToolKit/Editor/ToolAsset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: df91b23b175eb104589b3f0c20c4668a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/UXImporterUnityUiToolKit/Editor/ToolAsset/UXImporterToUITK.uss b/Assets/UXImporterUnityUiToolKit/Editor/ToolAsset/UXImporterToUITK.uss new file mode 100644 index 00000000..21359113 --- /dev/null +++ b/Assets/UXImporterUnityUiToolKit/Editor/ToolAsset/UXImporterToUITK.uss @@ -0,0 +1,48 @@ +/* ヘッダー */ +.header { + flex-direction: row; + justify-content: space-between; + align-items: center; + padding: 5px; + background-color: rgb(56, 56, 56); +} + +.title { + -unity-font-style: bold; + font-size: 14px; + color: white; +} + +ScrollView { + background-color: #383838; + border-width: 1px; + border-color: #2b2b2b; + border-radius: 4px; + padding: 10px; +} + +Button { + margin-top: 10px; +} + +.label-fixed-width .unity-label { + min-width: 220px; + max-width: 220px; +} + +#exportButton { + height: 30px; + width: 90%; + font-size: 14px; + align-self: center; + border-width: 1px; + border-color: white; +} + +#cancelImportButton { + height: 30px; + width: 90%; + font-size: 14px; + align-self: center; + margin-top: 5px; +} \ No newline at end of file diff --git a/Assets/UXImporterUnityUiToolKit/Editor/ToolAsset/UXImporterToUITK.uss.meta b/Assets/UXImporterUnityUiToolKit/Editor/ToolAsset/UXImporterToUITK.uss.meta new file mode 100644 index 00000000..c55535a2 --- /dev/null +++ b/Assets/UXImporterUnityUiToolKit/Editor/ToolAsset/UXImporterToUITK.uss.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 163109c4175a61c4a893aa85977bce79 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0} + disableValidation: 0 +AssetOrigin: + serializedVersion: 1 + productId: 337438 + packageName: UX Importer for UI Toolkit + packageVersion: 0.1.6 + assetPath: Assets/UXImporterUnityUiToolKit/Editor/ToolAsset/UXImporterToUITK.uss + uploadId: 840350 diff --git a/Assets/UXImporterUnityUiToolKit/Editor/ToolAsset/UXImporterToUITK.uxml b/Assets/UXImporterUnityUiToolKit/Editor/ToolAsset/UXImporterToUITK.uxml new file mode 100644 index 00000000..53a512f4 --- /dev/null +++ b/Assets/UXImporterUnityUiToolKit/Editor/ToolAsset/UXImporterToUITK.uxml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Assets/UXImporterUnityUiToolKit/Editor/ToolAsset/UXImporterToUITK.uxml.meta b/Assets/UXImporterUnityUiToolKit/Editor/ToolAsset/UXImporterToUITK.uxml.meta new file mode 100644 index 00000000..e3fe70d7 --- /dev/null +++ b/Assets/UXImporterUnityUiToolKit/Editor/ToolAsset/UXImporterToUITK.uxml.meta @@ -0,0 +1,17 @@ +fileFormatVersion: 2 +guid: 5c5ecbe294d46374b83b27654f8e8ffe +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0} +AssetOrigin: + serializedVersion: 1 + productId: 337438 + packageName: UX Importer for UI Toolkit + packageVersion: 0.1.6 + assetPath: Assets/UXImporterUnityUiToolKit/Editor/ToolAsset/UXImporterToUITK.uxml + uploadId: 840350 diff --git a/Assets/UXImporterUnityUiToolKit/Editor/UIAsset.meta b/Assets/UXImporterUnityUiToolKit/Editor/UIAsset.meta new file mode 100644 index 00000000..2e6d2cce --- /dev/null +++ b/Assets/UXImporterUnityUiToolKit/Editor/UIAsset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 25e9b1edf68820246aa2c364dccef6c3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/UXImporterUnityUiToolKit/Editor/UIAsset/DataHubEditor.uss b/Assets/UXImporterUnityUiToolKit/Editor/UIAsset/DataHubEditor.uss new file mode 100644 index 00000000..14c9ee26 --- /dev/null +++ b/Assets/UXImporterUnityUiToolKit/Editor/UIAsset/DataHubEditor.uss @@ -0,0 +1,58 @@ +/* ヘッダー */ +.header { + flex-direction: row; + justify-content: space-between; + align-items: center; + padding: 0 5px 5px 5px; + border-bottom: 1px solid rgb(56, 56, 56); + margin-bottom: 5px; +} + + + +/* Inspector全体のコンテナ */ +.root-container { + padding: 5px; +} + +.title { + -unity-font-style: bold; + font-size: 14px; + color: white; +} + +/* 警告メッセージのラベル */ +.warning-label { + font-size: 14px; + padding: 10px 5px; + white-space: normal; /* テキストの折り返しを許可 */ +} + +/* 区切り線 */ +.separator { + height: 1px; + background-color: rgb(56, 56, 56); + margin: 5px 0; +} + +/* テーブルリストのセクション */ +.tables-section { + padding: 10px 5px; +} + +/* テーブルリストのタイトル */ +.title-label { + -unity-font-style: bold; + font-size: 14px; + margin-bottom: 5px; + white-space: normal; /* テキストの折り返しを許可 */ +} + +/* テーブル名リストのコンテナ */ +.list-container {} + +/* 個々のテーブル名のラベル */ +.table-name-label { + margin-left: 15px; /* リスト項目をインデント */ + padding: 1px 0; +} \ No newline at end of file diff --git a/Assets/UXImporterUnityUiToolKit/Editor/UIAsset/DataHubEditor.uss.meta b/Assets/UXImporterUnityUiToolKit/Editor/UIAsset/DataHubEditor.uss.meta new file mode 100644 index 00000000..edd0e317 --- /dev/null +++ b/Assets/UXImporterUnityUiToolKit/Editor/UIAsset/DataHubEditor.uss.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 71de67d97a4bd4345a4a2ef330ca58fb +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0} + disableValidation: 0 +AssetOrigin: + serializedVersion: 1 + productId: 337438 + packageName: UX Importer for UI Toolkit + packageVersion: 0.1.6 + assetPath: Assets/UXImporterUnityUiToolKit/Editor/UIAsset/DataHubEditor.uss + uploadId: 840350 diff --git a/Assets/UXImporterUnityUiToolKit/Editor/UIAsset/DataHubEditor.uxml b/Assets/UXImporterUnityUiToolKit/Editor/UIAsset/DataHubEditor.uxml new file mode 100644 index 00000000..60695109 --- /dev/null +++ b/Assets/UXImporterUnityUiToolKit/Editor/UIAsset/DataHubEditor.uxml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Assets/UXImporterUnityUiToolKit/Editor/UIAsset/DataHubEditor.uxml.meta b/Assets/UXImporterUnityUiToolKit/Editor/UIAsset/DataHubEditor.uxml.meta new file mode 100644 index 00000000..d618e78f --- /dev/null +++ b/Assets/UXImporterUnityUiToolKit/Editor/UIAsset/DataHubEditor.uxml.meta @@ -0,0 +1,17 @@ +fileFormatVersion: 2 +guid: 7c99c36ae4294b54b9012a7074087582 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0} +AssetOrigin: + serializedVersion: 1 + productId: 337438 + packageName: UX Importer for UI Toolkit + packageVersion: 0.1.6 + assetPath: Assets/UXImporterUnityUiToolKit/Editor/UIAsset/DataHubEditor.uxml + uploadId: 840350 diff --git a/Assets/UXImporterUnityUiToolKit/Editor/UXImporterUnityUiToolKit.Editor.dll b/Assets/UXImporterUnityUiToolKit/Editor/UXImporterUnityUiToolKit.Editor.dll new file mode 100644 index 00000000..a37a9d98 Binary files /dev/null and b/Assets/UXImporterUnityUiToolKit/Editor/UXImporterUnityUiToolKit.Editor.dll differ diff --git a/Assets/UXImporterUnityUiToolKit/Editor/UXImporterUnityUiToolKit.Editor.dll.meta b/Assets/UXImporterUnityUiToolKit/Editor/UXImporterUnityUiToolKit.Editor.dll.meta new file mode 100644 index 00000000..ea5c4d74 --- /dev/null +++ b/Assets/UXImporterUnityUiToolKit/Editor/UXImporterUnityUiToolKit.Editor.dll.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 570e536497cc67846b92166e0bbd644e +AssetOrigin: + serializedVersion: 1 + productId: 337438 + packageName: UX Importer for UI Toolkit + packageVersion: 0.1.6 + assetPath: Assets/UXImporterUnityUiToolKit/Editor/UXImporterUnityUiToolKit.Editor.dll + uploadId: 840350 diff --git a/Assets/UXImporterUnityUiToolKit/README.md b/Assets/UXImporterUnityUiToolKit/README.md new file mode 100644 index 00000000..496c7ede --- /dev/null +++ b/Assets/UXImporterUnityUiToolKit/README.md @@ -0,0 +1,68 @@ +# UX Importer for Unity UI Toolkit + +## Description + +**UX Importer for Unity UI Toolkit** is a toolset for converting UI designs created in **external design platforms** into Unity's UI Toolkit format (UXML and USS). It consists of the **UX Exporter plugin** and a Unity editor extension, smoothing the collaboration between designers and developers. + + +Export a JSON file with all scene information and necessary asset files as a ZIP using the **UX Exporter plugin**. Simply import that ZIP file into your Unity project to faithfully reproduce the layout from the original design. + + +Please obtain the UX Exporter plugin here. +https://bamboo-up.app/ + +## Workflow + +1. **Design Creation**: + * The designer creates the UI design in the external design platform. + +2. **Design Export**: + * Use the **UX Exporter plugin** (available for download at [https://bamboo-up.app/](https://bamboo-up.app/)) to export the design as a **ZIP file containing the JSON data and required image assets**. + +3. **Placement in Unity Project**: + * **Unzip** the exported ZIP file and place its contents (the JSON file and assets) into any folder within your Unity project (e.g., `Assets/DesignExports/`). + +4. **Scene Setup (DataHub Root)**: + * In your Unity scene, add a new GameObject and attach the **`DataHub Root` component** to it. This component is essential for centralizing references to Addressables and Localization data, and it will serve as the **parent object for the generated UI structure**. + +5. **UXML/USS Automatic Generation**: + * After Unity recognizes the JSON file, launch the tool from the editor menu: `Window/BambooUp studio/UX Importer for UUIT`. + * Within the tool, specify the JSON file to automatically generate the **UXML and USS stylesheets** ready for use with the UI Toolkit. + +## Tool Configuration + +The following settings must be configured within the GUI of the "UX Importer for Unity UI Toolkit" import tool. + +### 1. Input Settings + +| Item | Description | +| :--- | :--- | +| **JSON File** | Specify the JSON file containing the design information exported by the UX Exporter plugin. | + +### 2. Output Settings + +| Item | Description | +| :--- | :--- | +| **Output Folder** | Specify the project folder where the generated **UXML files**, **USS stylesheets**, and **DataHub files** will be saved. | +| **DataHub Root Reference** | Specify the **`DataHub Root` component** placed in your scene. The generated UI will be structured as a child of this root. | + +### 3. Localization Settings + +| Item | Description | +| :--- | :--- | +| **Localization Asset Folder** | Specify the folder where **assets like String Tables** generated by the Unity Localization package will be stored. | + +### 4. Font Settings + +| Item | Description | +| :--- | :--- | +| **Default Font** | Specify a default font asset to be used as a substitute if a font utilized in the original design cannot be found in the Unity project. | + +*** + +## Operations (Import and Undo) + +| Operation | Description | +| :--- | :--- | +| **Execute Import** | Reads the JSON file based on the settings above and generates the UXML/USS and associated assets. | +| **Undo Import** | Reverts (deletes) the results of the last executed import operation (UXML/USS and DataHub files, etc.) from the specified output folder. | \ No newline at end of file diff --git a/Assets/UXImporterUnityUiToolKit/README.md.meta b/Assets/UXImporterUnityUiToolKit/README.md.meta new file mode 100644 index 00000000..62263f45 --- /dev/null +++ b/Assets/UXImporterUnityUiToolKit/README.md.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 16b2182b71b79594e844b2633b67893c +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 337438 + packageName: UX Importer for UI Toolkit + packageVersion: 0.1.6 + assetPath: Assets/UXImporterUnityUiToolKit/README.md + uploadId: 840350 diff --git a/Assets/UXImporterUnityUiToolKit/Runtime.meta b/Assets/UXImporterUnityUiToolKit/Runtime.meta new file mode 100644 index 00000000..424a217e --- /dev/null +++ b/Assets/UXImporterUnityUiToolKit/Runtime.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a7654789c6e0fd743adf5c5b63f14613 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/UXImporterUnityUiToolKit/Runtime/UXImporterUnityUiToolKit.dll b/Assets/UXImporterUnityUiToolKit/Runtime/UXImporterUnityUiToolKit.dll new file mode 100644 index 00000000..39c75844 Binary files /dev/null and b/Assets/UXImporterUnityUiToolKit/Runtime/UXImporterUnityUiToolKit.dll differ diff --git a/Assets/UXImporterUnityUiToolKit/Runtime/UXImporterUnityUiToolKit.dll.meta b/Assets/UXImporterUnityUiToolKit/Runtime/UXImporterUnityUiToolKit.dll.meta new file mode 100644 index 00000000..7ffb5436 --- /dev/null +++ b/Assets/UXImporterUnityUiToolKit/Runtime/UXImporterUnityUiToolKit.dll.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 178891466f3f1d447aa5cfbf83d7a8b5 +AssetOrigin: + serializedVersion: 1 + productId: 337438 + packageName: UX Importer for UI Toolkit + packageVersion: 0.1.6 + assetPath: Assets/UXImporterUnityUiToolKit/Runtime/UXImporterUnityUiToolKit.dll + uploadId: 840350 diff --git a/Assets/UXImporterUnityUiToolKit/Samples~/Section_1.json b/Assets/UXImporterUnityUiToolKit/Samples~/Section_1.json new file mode 100644 index 00000000..e92859ed --- /dev/null +++ b/Assets/UXImporterUnityUiToolKit/Samples~/Section_1.json @@ -0,0 +1,15610 @@ +{ + "flattenLayers": [ + { + "id": "1:3", + "name": "Section 1", + "type": "SECTION", + "parentID": "0:1", + "parentName": "Page 1", + "childrenNames": [ + { + "id": "1:4", + "name": "logo_all 1", + "type": "RECTANGLE", + "parentID": "1:3", + "parentName": "Section 1" + }, + { + "id": "81:258", + "name": "Footer", + "type": "FRAME", + "parentID": "1:3", + "parentName": "Section 1" + }, + { + "id": "1:2820", + "name": "Panel Image Content Reverse", + "type": "INSTANCE", + "parentID": "1:3", + "parentName": "Section 1" + }, + { + "id": "1:2838", + "name": "bamboo-shoots-7181496_1280 1", + "type": "RECTANGLE", + "parentID": "1:3", + "parentName": "Section 1" + }, + { + "id": "4:240", + "name": "Group 1", + "type": "GROUP", + "parentID": "1:3", + "parentName": "Section 1" + }, + { + "id": "1:1330", + "name": "Menu", + "type": "INSTANCE", + "parentID": "1:3", + "parentName": "Section 1" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_SectionNode": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 1, + "g": 1, + "b": 1 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "opaqueNodeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "dimensionAndPositionMixin": { + "width": 1920, + "height": 1080, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + } + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + } + } + }, + { + "id": "1:4", + "name": "logo_all 1", + "type": "RECTANGLE", + "parentID": "1:3", + "parentName": "Section 1", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": true, + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 412.69921875, + "height": 117, + "tx": 1423, + "ty": 894, + "x": 1423, + "y": 894 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "MAX", + "vertical": "MAX" + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "aspectRatioLockMixin": { + "targetAspectRatio": { + "x": 1806, + "y": 512 + } + } + } + }, + { + "id": "81:258", + "name": "Footer", + "type": "FRAME", + "parentID": "1:3", + "parentName": "Section 1", + "childrenNames": [ + { + "id": "81:271", + "name": "Text Link List", + "type": "INSTANCE", + "parentID": "81:258", + "parentName": "Footer" + }, + { + "id": "81:272", + "name": "Text Link List", + "type": "INSTANCE", + "parentID": "81:258", + "parentName": "Footer" + }, + { + "id": "81:273", + "name": "Text Link List", + "type": "INSTANCE", + "parentID": "81:258", + "parentName": "Footer" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_FrameNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 1, + "g": 1, + "b": 1 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": { + "stroke": { + "strokes": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.8509804010391235, + "g": 0.8509804010391235, + "b": 0.8509804010391235 + }, + "visible": true, + "opacity": 1 + } + ], + "strokeWeight": 0, + "strokeAlign": "INSIDE", + "strokeJoin": "MITER" + } + }, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 1200, + "height": 468, + "tx": 129, + "ty": 746, + "x": 129, + "y": 746 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 0, + "strokeLeftWeight": 0, + "strokeRightWeight": 0 + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "layoutWrap": "WRAP", + "paddingLeft": 32, + "paddingRight": 32, + "paddingTop": 32, + "paddingBottom": 160, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "AUTO", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 16, + "counterAxisSpacing": 16, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "paddingLeft": 32, + "paddingRight": 32, + "paddingTop": 32, + "paddingBottom": 160, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "AUTO", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "itemSpacing": 16 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": true, + "guides": [] + } + } + } + }, + { + "id": "81:271", + "name": "Text Link List", + "type": "INSTANCE", + "parentID": "81:258", + "parentName": "Footer", + "childrenNames": [ + { + "id": "I81:271;2162:7479", + "name": "Title", + "type": "FRAME", + "parentID": "81:271", + "parentName": "Text Link List" + }, + { + "id": "I81:271;2153:7976", + "name": "Text Link List Item", + "type": "INSTANCE", + "parentID": "81:271", + "parentName": "Text Link List" + }, + { + "id": "I81:271;2153:7978", + "name": "Text Link List Item", + "type": "INSTANCE", + "parentID": "81:271", + "parentName": "Text Link List" + }, + { + "id": "I81:271;2153:7980", + "name": "Text Link List Item", + "type": "INSTANCE", + "parentID": "81:271", + "parentName": "Text Link List" + }, + { + "id": "I81:271;2153:7982", + "name": "Text Link List Item", + "type": "INSTANCE", + "parentID": "81:271", + "parentName": "Text Link List" + }, + { + "id": "I81:271;2153:7984", + "name": "Text Link List Item", + "type": "INSTANCE", + "parentID": "81:271", + "parentName": "Text Link List" + }, + { + "id": "I81:271;2153:7986", + "name": "Text Link List Item", + "type": "INSTANCE", + "parentID": "81:271", + "parentName": "Text Link List" + }, + { + "id": "I81:271;2153:7988", + "name": "Text Link List Item", + "type": "INSTANCE", + "parentID": "81:271", + "parentName": "Text Link List" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_InstanceNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 262, + "height": 276, + "tx": 32, + "ty": 32, + "x": 32, + "y": 32 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "VERTICAL", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 12, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "VERTICAL", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "itemSpacing": 12 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + }, + "variantMixin": { + "variantProperties": { + "Density": "Default" + } + }, + "button": false + } + }, + { + "id": "I81:271;2162:7479", + "name": "Title", + "type": "FRAME", + "parentID": "81:271", + "parentName": "Text Link List", + "childrenNames": [ + { + "id": "I81:271;2162:6389", + "name": "Text Strong", + "type": "INSTANCE", + "parentID": "I81:271;2162:7479", + "parentName": "Title" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_FrameNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 262, + "height": 38, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "VERTICAL", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 16, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 10, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "VERTICAL", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 16, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "itemSpacing": 10 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + } + } + }, + { + "id": "I81:271;2162:6389", + "name": "Text Strong", + "type": "INSTANCE", + "parentID": "I81:271;2162:7479", + "parentName": "Title", + "childrenNames": [ + { + "id": "I81:271;2162:6389;2087:8468", + "name": "Text Strong", + "type": "TEXT", + "parentID": "I81:271;2162:6389", + "parentName": "Text Strong" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_InstanceNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 262, + "height": 22, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "AUTO", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 0, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "AUTO", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "itemSpacing": 0 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + }, + "variantMixin": { + "variantProperties": null + }, + "button": false + } + }, + { + "id": "I81:271;2162:6389;2087:8468", + "name": "Text Strong", + "type": "TEXT", + "parentID": "I81:271;2162:6389", + "parentName": "Text Strong", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_TextNode": { + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 80, + "height": 22, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "nonResizableTextMixin": { + "paragraphIndent": 0, + "listSpacing": 0, + "hangingPunctuation": false, + "hangingList": false, + "fontSize": 16, + "fontName": { + "family": "Inter", + "style": "Semi Bold" + }, + "fontWeight": 600, + "textCase": "ORIGINAL", + "textDecoration": "NONE", + "textDecorationStyle": null, + "letterSpacing": { + "value": 0, + "unit": "PERCENT" + }, + "lineHeight": { + "value": 139.9999976158142, + "unit": "PERCENT" + }, + "characters": "Use cases" + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "textAlignHorizontal": "LEFT", + "textAlignVertical": "TOP", + "textAutoResize": "WIDTH_AND_HEIGHT", + "textTruncation": "DISABLED", + "maxLines": null, + "autoRename": true, + "textStyleId": "S:e21b16ffb31d9ee1ff2a4792765537ea77c7b80e,716:147" + } + }, + { + "id": "I81:271;2153:7976", + "name": "Text Link List Item", + "type": "INSTANCE", + "parentID": "81:271", + "parentName": "Text Link List", + "childrenNames": [ + { + "id": "I81:271;2153:7976;2153:7955", + "name": "List item", + "type": "TEXT", + "parentID": "I81:271;2153:7976", + "parentName": "Text Link List Item" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_InstanceNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 1, + "g": 1, + "b": 1 + }, + "visible": false, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 89, + "height": 22, + "tx": 0, + "ty": 50, + "x": 0, + "y": 50 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "NONE", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 0, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "MIN", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "paddingLeft": 0, + "paddingRight": 17, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "CENTER", + "itemSpacing": 0 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + }, + "variantMixin": { + "variantProperties": null + }, + "button": false + } + }, + { + "id": "I81:271;2153:7976;2153:7955", + "name": "List item", + "type": "TEXT", + "parentID": "I81:271;2153:7976", + "parentName": "Text Link List Item", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_TextNode": { + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 72, + "height": 22, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "SCALE", + "vertical": "SCALE" + }, + "nonResizableTextMixin": { + "paragraphIndent": 0, + "listSpacing": 0, + "hangingPunctuation": false, + "hangingList": false, + "fontSize": 16, + "fontName": { + "family": "Inter", + "style": "Regular" + }, + "fontWeight": 400, + "textCase": "ORIGINAL", + "textDecoration": "NONE", + "textDecorationStyle": null, + "letterSpacing": { + "value": 0, + "unit": "PERCENT" + }, + "lineHeight": { + "value": 139.9999976158142, + "unit": "PERCENT" + }, + "characters": "UI design" + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "textAlignHorizontal": "LEFT", + "textAlignVertical": "CENTER", + "textAutoResize": "WIDTH_AND_HEIGHT", + "textTruncation": "DISABLED", + "maxLines": null, + "autoRename": true, + "textStyleId": "S:cebee1b62ea594fa8f97b0b247fd163730736f2a,716:123" + } + }, + { + "id": "I81:271;2153:7978", + "name": "Text Link List Item", + "type": "INSTANCE", + "parentID": "81:271", + "parentName": "Text Link List", + "childrenNames": [ + { + "id": "I81:271;2153:7978;2153:7955", + "name": "List item", + "type": "TEXT", + "parentID": "I81:271;2153:7978", + "parentName": "Text Link List Item" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_InstanceNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 1, + "g": 1, + "b": 1 + }, + "visible": false, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 262, + "height": 22, + "tx": 0, + "ty": 84, + "x": 0, + "y": 84 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "NONE", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 0, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "MIN", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "paddingLeft": 0, + "paddingRight": 184, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "CENTER", + "itemSpacing": 0 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + }, + "variantMixin": { + "variantProperties": null + }, + "button": false + } + }, + { + "id": "I81:271;2153:7978;2153:7955", + "name": "List item", + "type": "TEXT", + "parentID": "I81:271;2153:7978", + "parentName": "Text Link List Item", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_TextNode": { + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 78, + "height": 22, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "SCALE", + "vertical": "SCALE" + }, + "nonResizableTextMixin": { + "paragraphIndent": 0, + "listSpacing": 0, + "hangingPunctuation": false, + "hangingList": false, + "fontSize": 16, + "fontName": { + "family": "Inter", + "style": "Regular" + }, + "fontWeight": 400, + "textCase": "ORIGINAL", + "textDecoration": "NONE", + "textDecorationStyle": null, + "letterSpacing": { + "value": 0, + "unit": "PERCENT" + }, + "lineHeight": { + "value": 139.9999976158142, + "unit": "PERCENT" + }, + "characters": "UX design" + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "textAlignHorizontal": "LEFT", + "textAlignVertical": "CENTER", + "textAutoResize": "WIDTH_AND_HEIGHT", + "textTruncation": "DISABLED", + "maxLines": null, + "autoRename": true, + "textStyleId": "S:cebee1b62ea594fa8f97b0b247fd163730736f2a,716:123" + } + }, + { + "id": "I81:271;2153:7980", + "name": "Text Link List Item", + "type": "INSTANCE", + "parentID": "81:271", + "parentName": "Text Link List", + "childrenNames": [ + { + "id": "I81:271;2153:7980;2153:7955", + "name": "List item", + "type": "TEXT", + "parentID": "I81:271;2153:7980", + "parentName": "Text Link List Item" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_InstanceNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 1, + "g": 1, + "b": 1 + }, + "visible": false, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 89, + "height": 22, + "tx": 0, + "ty": 118, + "x": 0, + "y": 118 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "NONE", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 0, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "MIN", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "CENTER", + "counterAxisAlignItems": "CENTER", + "itemSpacing": 0 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + }, + "variantMixin": { + "variantProperties": null + }, + "button": false + } + }, + { + "id": "I81:271;2153:7980;2153:7955", + "name": "List item", + "type": "TEXT", + "parentID": "I81:271;2153:7980", + "parentName": "Text Link List Item", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_TextNode": { + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 92, + "height": 22, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "SCALE", + "vertical": "SCALE" + }, + "nonResizableTextMixin": { + "paragraphIndent": 0, + "listSpacing": 0, + "hangingPunctuation": false, + "hangingList": false, + "fontSize": 16, + "fontName": { + "family": "Inter", + "style": "Regular" + }, + "fontWeight": 400, + "textCase": "ORIGINAL", + "textDecoration": "NONE", + "textDecorationStyle": null, + "letterSpacing": { + "value": 0, + "unit": "PERCENT" + }, + "lineHeight": { + "value": 139.9999976158142, + "unit": "PERCENT" + }, + "characters": "Wireframing" + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "textAlignHorizontal": "LEFT", + "textAlignVertical": "CENTER", + "textAutoResize": "WIDTH_AND_HEIGHT", + "textTruncation": "DISABLED", + "maxLines": null, + "autoRename": true, + "textStyleId": "S:cebee1b62ea594fa8f97b0b247fd163730736f2a,716:123" + } + }, + { + "id": "I81:271;2153:7982", + "name": "Text Link List Item", + "type": "INSTANCE", + "parentID": "81:271", + "parentName": "Text Link List", + "childrenNames": [ + { + "id": "I81:271;2153:7982;2153:7955", + "name": "List item", + "type": "TEXT", + "parentID": "I81:271;2153:7982", + "parentName": "Text Link List Item" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_InstanceNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 1, + "g": 1, + "b": 1 + }, + "visible": false, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 89, + "height": 22, + "tx": 0, + "ty": 152, + "x": 0, + "y": 152 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "NONE", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 0, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "MIN", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MAX", + "counterAxisAlignItems": "CENTER", + "itemSpacing": 0 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + }, + "variantMixin": { + "variantProperties": null + }, + "button": false + } + }, + { + "id": "I81:271;2153:7982;2153:7955", + "name": "List item", + "type": "TEXT", + "parentID": "I81:271;2153:7982", + "parentName": "Text Link List Item", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_TextNode": { + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 100, + "height": 22, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "SCALE", + "vertical": "SCALE" + }, + "nonResizableTextMixin": { + "paragraphIndent": 0, + "listSpacing": 0, + "hangingPunctuation": false, + "hangingList": false, + "fontSize": 16, + "fontName": { + "family": "Inter", + "style": "Regular" + }, + "fontWeight": 400, + "textCase": "ORIGINAL", + "textDecoration": "NONE", + "textDecorationStyle": null, + "letterSpacing": { + "value": 0, + "unit": "PERCENT" + }, + "lineHeight": { + "value": 139.9999976158142, + "unit": "PERCENT" + }, + "characters": "Diagramming" + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "textAlignHorizontal": "LEFT", + "textAlignVertical": "CENTER", + "textAutoResize": "WIDTH_AND_HEIGHT", + "textTruncation": "DISABLED", + "maxLines": null, + "autoRename": true, + "textStyleId": "S:cebee1b62ea594fa8f97b0b247fd163730736f2a,716:123" + } + }, + { + "id": "I81:271;2153:7984", + "name": "Text Link List Item", + "type": "INSTANCE", + "parentID": "81:271", + "parentName": "Text Link List", + "childrenNames": [ + { + "id": "I81:271;2153:7984;2153:7955", + "name": "List item", + "type": "TEXT", + "parentID": "I81:271;2153:7984", + "parentName": "Text Link List Item" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_InstanceNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 1, + "g": 1, + "b": 1 + }, + "visible": false, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 89, + "height": 22, + "tx": 0, + "ty": 186, + "x": 0, + "y": 186 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "NONE", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 0, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "MIN", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MAX", + "counterAxisAlignItems": "CENTER", + "itemSpacing": 0 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + }, + "variantMixin": { + "variantProperties": null + }, + "button": false + } + }, + { + "id": "I81:271;2153:7984;2153:7955", + "name": "List item", + "type": "TEXT", + "parentID": "I81:271;2153:7984", + "parentName": "Text Link List Item", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_TextNode": { + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 105, + "height": 22, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "SCALE", + "vertical": "SCALE" + }, + "nonResizableTextMixin": { + "paragraphIndent": 0, + "listSpacing": 0, + "hangingPunctuation": false, + "hangingList": false, + "fontSize": 16, + "fontName": { + "family": "Inter", + "style": "Regular" + }, + "fontWeight": 400, + "textCase": "ORIGINAL", + "textDecoration": "NONE", + "textDecorationStyle": null, + "letterSpacing": { + "value": 0, + "unit": "PERCENT" + }, + "lineHeight": { + "value": 139.9999976158142, + "unit": "PERCENT" + }, + "characters": "Brainstorming" + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "textAlignHorizontal": "LEFT", + "textAlignVertical": "CENTER", + "textAutoResize": "WIDTH_AND_HEIGHT", + "textTruncation": "DISABLED", + "maxLines": null, + "autoRename": true, + "textStyleId": "S:cebee1b62ea594fa8f97b0b247fd163730736f2a,716:123" + } + }, + { + "id": "I81:271;2153:7986", + "name": "Text Link List Item", + "type": "INSTANCE", + "parentID": "81:271", + "parentName": "Text Link List", + "childrenNames": [ + { + "id": "I81:271;2153:7986;2153:7955", + "name": "List item", + "type": "TEXT", + "parentID": "I81:271;2153:7986", + "parentName": "Text Link List Item" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_InstanceNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 1, + "g": 1, + "b": 1 + }, + "visible": false, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 89, + "height": 22, + "tx": 0, + "ty": 220, + "x": 0, + "y": 220 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "NONE", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 0, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "MIN", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MAX", + "counterAxisAlignItems": "CENTER", + "itemSpacing": 0 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + }, + "variantMixin": { + "variantProperties": null + }, + "button": false + } + }, + { + "id": "I81:271;2153:7986;2153:7955", + "name": "List item", + "type": "TEXT", + "parentID": "I81:271;2153:7986", + "parentName": "Text Link List Item", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_TextNode": { + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 138, + "height": 22, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "SCALE", + "vertical": "SCALE" + }, + "nonResizableTextMixin": { + "paragraphIndent": 0, + "listSpacing": 0, + "hangingPunctuation": false, + "hangingList": false, + "fontSize": 16, + "fontName": { + "family": "Inter", + "style": "Regular" + }, + "fontWeight": 400, + "textCase": "ORIGINAL", + "textDecoration": "NONE", + "textDecorationStyle": null, + "letterSpacing": { + "value": 0, + "unit": "PERCENT" + }, + "lineHeight": { + "value": 139.9999976158142, + "unit": "PERCENT" + }, + "characters": "Online whiteboard" + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "textAlignHorizontal": "LEFT", + "textAlignVertical": "CENTER", + "textAutoResize": "WIDTH_AND_HEIGHT", + "textTruncation": "DISABLED", + "maxLines": null, + "autoRename": true, + "textStyleId": "S:cebee1b62ea594fa8f97b0b247fd163730736f2a,716:123" + } + }, + { + "id": "I81:271;2153:7988", + "name": "Text Link List Item", + "type": "INSTANCE", + "parentID": "81:271", + "parentName": "Text Link List", + "childrenNames": [ + { + "id": "I81:271;2153:7988;2153:7955", + "name": "List item", + "type": "TEXT", + "parentID": "I81:271;2153:7988", + "parentName": "Text Link List Item" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_InstanceNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 1, + "g": 1, + "b": 1 + }, + "visible": false, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 89, + "height": 22, + "tx": 0, + "ty": 254, + "x": 0, + "y": 254 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "NONE", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 0, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "MIN", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MAX", + "counterAxisAlignItems": "CENTER", + "itemSpacing": 0 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + }, + "variantMixin": { + "variantProperties": null + }, + "button": false + } + }, + { + "id": "I81:271;2153:7988;2153:7955", + "name": "List item", + "type": "TEXT", + "parentID": "I81:271;2153:7988", + "parentName": "Text Link List Item", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_TextNode": { + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 144, + "height": 22, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "SCALE", + "vertical": "SCALE" + }, + "nonResizableTextMixin": { + "paragraphIndent": 0, + "listSpacing": 0, + "hangingPunctuation": false, + "hangingList": false, + "fontSize": 16, + "fontName": { + "family": "Inter", + "style": "Regular" + }, + "fontWeight": 400, + "textCase": "ORIGINAL", + "textDecoration": "NONE", + "textDecorationStyle": null, + "letterSpacing": { + "value": 0, + "unit": "PERCENT" + }, + "lineHeight": { + "value": 139.9999976158142, + "unit": "PERCENT" + }, + "characters": "Team collaboration" + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "textAlignHorizontal": "LEFT", + "textAlignVertical": "CENTER", + "textAutoResize": "WIDTH_AND_HEIGHT", + "textTruncation": "DISABLED", + "maxLines": null, + "autoRename": true, + "textStyleId": "S:cebee1b62ea594fa8f97b0b247fd163730736f2a,716:123" + } + }, + { + "id": "81:272", + "name": "Text Link List", + "type": "INSTANCE", + "parentID": "81:258", + "parentName": "Footer", + "childrenNames": [ + { + "id": "I81:272;2162:7479", + "name": "Title", + "type": "FRAME", + "parentID": "81:272", + "parentName": "Text Link List" + }, + { + "id": "I81:272;2153:7976", + "name": "Text Link List Item", + "type": "INSTANCE", + "parentID": "81:272", + "parentName": "Text Link List" + }, + { + "id": "I81:272;2153:7978", + "name": "Text Link List Item", + "type": "INSTANCE", + "parentID": "81:272", + "parentName": "Text Link List" + }, + { + "id": "I81:272;2153:7980", + "name": "Text Link List Item", + "type": "INSTANCE", + "parentID": "81:272", + "parentName": "Text Link List" + }, + { + "id": "I81:272;2153:7982", + "name": "Text Link List Item", + "type": "INSTANCE", + "parentID": "81:272", + "parentName": "Text Link List" + }, + { + "id": "I81:272;2153:7984", + "name": "Text Link List Item", + "type": "INSTANCE", + "parentID": "81:272", + "parentName": "Text Link List" + }, + { + "id": "I81:272;2153:7986", + "name": "Text Link List Item", + "type": "INSTANCE", + "parentID": "81:272", + "parentName": "Text Link List" + }, + { + "id": "I81:272;2153:7988", + "name": "Text Link List Item", + "type": "INSTANCE", + "parentID": "81:272", + "parentName": "Text Link List" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_InstanceNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 262, + "height": 242, + "tx": 310, + "ty": 32, + "x": 310, + "y": 32 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "VERTICAL", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 12, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "VERTICAL", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "itemSpacing": 12 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + }, + "variantMixin": { + "variantProperties": { + "Density": "Default" + } + }, + "button": false + } + }, + { + "id": "I81:272;2162:7479", + "name": "Title", + "type": "FRAME", + "parentID": "81:272", + "parentName": "Text Link List", + "childrenNames": [ + { + "id": "I81:272;2162:6389", + "name": "Text Strong", + "type": "INSTANCE", + "parentID": "I81:272;2162:7479", + "parentName": "Title" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_FrameNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 262, + "height": 38, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "VERTICAL", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 16, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 10, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "VERTICAL", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 16, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "itemSpacing": 10 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + } + } + }, + { + "id": "I81:272;2162:6389", + "name": "Text Strong", + "type": "INSTANCE", + "parentID": "I81:272;2162:7479", + "parentName": "Title", + "childrenNames": [ + { + "id": "I81:272;2162:6389;2087:8468", + "name": "Text Strong", + "type": "TEXT", + "parentID": "I81:272;2162:6389", + "parentName": "Text Strong" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_InstanceNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 262, + "height": 22, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "AUTO", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 0, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "AUTO", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "itemSpacing": 0 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + }, + "variantMixin": { + "variantProperties": null + }, + "button": false + } + }, + { + "id": "I81:272;2162:6389;2087:8468", + "name": "Text Strong", + "type": "TEXT", + "parentID": "I81:272;2162:6389", + "parentName": "Text Strong", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_TextNode": { + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 59, + "height": 22, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "nonResizableTextMixin": { + "paragraphIndent": 0, + "listSpacing": 0, + "hangingPunctuation": false, + "hangingList": false, + "fontSize": 16, + "fontName": { + "family": "Inter", + "style": "Semi Bold" + }, + "fontWeight": 600, + "textCase": "ORIGINAL", + "textDecoration": "NONE", + "textDecorationStyle": null, + "letterSpacing": { + "value": 0, + "unit": "PERCENT" + }, + "lineHeight": { + "value": 139.9999976158142, + "unit": "PERCENT" + }, + "characters": "Explore" + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "textAlignHorizontal": "LEFT", + "textAlignVertical": "TOP", + "textAutoResize": "WIDTH_AND_HEIGHT", + "textTruncation": "DISABLED", + "maxLines": null, + "autoRename": true, + "textStyleId": "S:e21b16ffb31d9ee1ff2a4792765537ea77c7b80e,716:147" + } + }, + { + "id": "I81:272;2153:7976", + "name": "Text Link List Item", + "type": "INSTANCE", + "parentID": "81:272", + "parentName": "Text Link List", + "childrenNames": [ + { + "id": "I81:272;2153:7976;2153:7955", + "name": "List item", + "type": "TEXT", + "parentID": "I81:272;2153:7976", + "parentName": "Text Link List Item" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_InstanceNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 1, + "g": 1, + "b": 1 + }, + "visible": false, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 89, + "height": 22, + "tx": 0, + "ty": 50, + "x": 0, + "y": 50 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "NONE", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 0, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "MIN", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "paddingLeft": 0, + "paddingRight": 36, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "CENTER", + "itemSpacing": 0 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + }, + "variantMixin": { + "variantProperties": null + }, + "button": false + } + }, + { + "id": "I81:272;2153:7976;2153:7955", + "name": "List item", + "type": "TEXT", + "parentID": "I81:272;2153:7976", + "parentName": "Text Link List Item", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_TextNode": { + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 53, + "height": 22, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "SCALE", + "vertical": "SCALE" + }, + "nonResizableTextMixin": { + "paragraphIndent": 0, + "listSpacing": 0, + "hangingPunctuation": false, + "hangingList": false, + "fontSize": 16, + "fontName": { + "family": "Inter", + "style": "Regular" + }, + "fontWeight": 400, + "textCase": "ORIGINAL", + "textDecoration": "NONE", + "textDecorationStyle": null, + "letterSpacing": { + "value": 0, + "unit": "PERCENT" + }, + "lineHeight": { + "value": 139.9999976158142, + "unit": "PERCENT" + }, + "characters": "Design" + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "textAlignHorizontal": "LEFT", + "textAlignVertical": "CENTER", + "textAutoResize": "WIDTH_AND_HEIGHT", + "textTruncation": "DISABLED", + "maxLines": null, + "autoRename": true, + "textStyleId": "S:cebee1b62ea594fa8f97b0b247fd163730736f2a,716:123" + } + }, + { + "id": "I81:272;2153:7978", + "name": "Text Link List Item", + "type": "INSTANCE", + "parentID": "81:272", + "parentName": "Text Link List", + "childrenNames": [ + { + "id": "I81:272;2153:7978;2153:7955", + "name": "List item", + "type": "TEXT", + "parentID": "I81:272;2153:7978", + "parentName": "Text Link List Item" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_InstanceNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 1, + "g": 1, + "b": 1 + }, + "visible": false, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 89, + "height": 22, + "tx": 0, + "ty": 84, + "x": 0, + "y": 84 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "NONE", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 0, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "MIN", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "CENTER", + "counterAxisAlignItems": "CENTER", + "itemSpacing": 0 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + }, + "variantMixin": { + "variantProperties": null + }, + "button": false + } + }, + { + "id": "I81:272;2153:7978;2153:7955", + "name": "List item", + "type": "TEXT", + "parentID": "I81:272;2153:7978", + "parentName": "Text Link List Item", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_TextNode": { + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 89, + "height": 22, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "SCALE", + "vertical": "SCALE" + }, + "nonResizableTextMixin": { + "paragraphIndent": 0, + "listSpacing": 0, + "hangingPunctuation": false, + "hangingList": false, + "fontSize": 16, + "fontName": { + "family": "Inter", + "style": "Regular" + }, + "fontWeight": 400, + "textCase": "ORIGINAL", + "textDecoration": "NONE", + "textDecorationStyle": null, + "letterSpacing": { + "value": 0, + "unit": "PERCENT" + }, + "lineHeight": { + "value": 139.9999976158142, + "unit": "PERCENT" + }, + "characters": "Prototyping" + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "textAlignHorizontal": "LEFT", + "textAlignVertical": "CENTER", + "textAutoResize": "WIDTH_AND_HEIGHT", + "textTruncation": "DISABLED", + "maxLines": null, + "autoRename": true, + "textStyleId": "S:cebee1b62ea594fa8f97b0b247fd163730736f2a,716:123" + } + }, + { + "id": "I81:272;2153:7980", + "name": "Text Link List Item", + "type": "INSTANCE", + "parentID": "81:272", + "parentName": "Text Link List", + "childrenNames": [ + { + "id": "I81:272;2153:7980;2153:7955", + "name": "List item", + "type": "TEXT", + "parentID": "I81:272;2153:7980", + "parentName": "Text Link List Item" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_InstanceNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 1, + "g": 1, + "b": 1 + }, + "visible": false, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 89, + "height": 22, + "tx": 0, + "ty": 118, + "x": 0, + "y": 118 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "NONE", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 0, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "MIN", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MAX", + "counterAxisAlignItems": "CENTER", + "itemSpacing": 0 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + }, + "variantMixin": { + "variantProperties": null + }, + "button": false + } + }, + { + "id": "I81:272;2153:7980;2153:7955", + "name": "List item", + "type": "TEXT", + "parentID": "I81:272;2153:7980", + "parentName": "Text Link List Item", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_TextNode": { + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 167, + "height": 22, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "SCALE", + "vertical": "SCALE" + }, + "nonResizableTextMixin": { + "paragraphIndent": 0, + "listSpacing": 0, + "hangingPunctuation": false, + "hangingList": false, + "fontSize": 16, + "fontName": { + "family": "Inter", + "style": "Regular" + }, + "fontWeight": 400, + "textCase": "ORIGINAL", + "textDecoration": "NONE", + "textDecorationStyle": null, + "letterSpacing": { + "value": 0, + "unit": "PERCENT" + }, + "lineHeight": { + "value": 139.9999976158142, + "unit": "PERCENT" + }, + "characters": "Development features" + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "textAlignHorizontal": "LEFT", + "textAlignVertical": "CENTER", + "textAutoResize": "WIDTH_AND_HEIGHT", + "textTruncation": "DISABLED", + "maxLines": null, + "autoRename": true, + "textStyleId": "S:cebee1b62ea594fa8f97b0b247fd163730736f2a,716:123" + } + }, + { + "id": "I81:272;2153:7982", + "name": "Text Link List Item", + "type": "INSTANCE", + "parentID": "81:272", + "parentName": "Text Link List", + "childrenNames": [ + { + "id": "I81:272;2153:7982;2153:7955", + "name": "List item", + "type": "TEXT", + "parentID": "I81:272;2153:7982", + "parentName": "Text Link List Item" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_InstanceNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 1, + "g": 1, + "b": 1 + }, + "visible": false, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 89, + "height": 22, + "tx": 0, + "ty": 152, + "x": 0, + "y": 152 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "NONE", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 0, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "MIN", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MAX", + "counterAxisAlignItems": "CENTER", + "itemSpacing": 0 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + }, + "variantMixin": { + "variantProperties": null + }, + "button": false + } + }, + { + "id": "I81:272;2153:7982;2153:7955", + "name": "List item", + "type": "TEXT", + "parentID": "I81:272;2153:7982", + "parentName": "Text Link List Item", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_TextNode": { + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 120, + "height": 22, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "SCALE", + "vertical": "SCALE" + }, + "nonResizableTextMixin": { + "paragraphIndent": 0, + "listSpacing": 0, + "hangingPunctuation": false, + "hangingList": false, + "fontSize": 16, + "fontName": { + "family": "Inter", + "style": "Regular" + }, + "fontWeight": 400, + "textCase": "ORIGINAL", + "textDecoration": "NONE", + "textDecorationStyle": null, + "letterSpacing": { + "value": 0, + "unit": "PERCENT" + }, + "lineHeight": { + "value": 139.9999976158142, + "unit": "PERCENT" + }, + "characters": "Design systems" + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "textAlignHorizontal": "LEFT", + "textAlignVertical": "CENTER", + "textAutoResize": "WIDTH_AND_HEIGHT", + "textTruncation": "DISABLED", + "maxLines": null, + "autoRename": true, + "textStyleId": "S:cebee1b62ea594fa8f97b0b247fd163730736f2a,716:123" + } + }, + { + "id": "I81:272;2153:7984", + "name": "Text Link List Item", + "type": "INSTANCE", + "parentID": "81:272", + "parentName": "Text Link List", + "childrenNames": [ + { + "id": "I81:272;2153:7984;2153:7955", + "name": "List item", + "type": "TEXT", + "parentID": "I81:272;2153:7984", + "parentName": "Text Link List Item" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_InstanceNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 1, + "g": 1, + "b": 1 + }, + "visible": false, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 89, + "height": 22, + "tx": 0, + "ty": 186, + "x": 0, + "y": 186 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "NONE", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 0, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "MIN", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MAX", + "counterAxisAlignItems": "CENTER", + "itemSpacing": 0 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + }, + "variantMixin": { + "variantProperties": null + }, + "button": false + } + }, + { + "id": "I81:272;2153:7984;2153:7955", + "name": "List item", + "type": "TEXT", + "parentID": "I81:272;2153:7984", + "parentName": "Text Link List Item", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_TextNode": { + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 168, + "height": 22, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "SCALE", + "vertical": "SCALE" + }, + "nonResizableTextMixin": { + "paragraphIndent": 0, + "listSpacing": 0, + "hangingPunctuation": false, + "hangingList": false, + "fontSize": 16, + "fontName": { + "family": "Inter", + "style": "Regular" + }, + "fontWeight": 400, + "textCase": "ORIGINAL", + "textDecoration": "NONE", + "textDecorationStyle": null, + "letterSpacing": { + "value": 0, + "unit": "PERCENT" + }, + "lineHeight": { + "value": 139.9999976158142, + "unit": "PERCENT" + }, + "characters": "Collaboration features" + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "textAlignHorizontal": "LEFT", + "textAlignVertical": "CENTER", + "textAutoResize": "WIDTH_AND_HEIGHT", + "textTruncation": "DISABLED", + "maxLines": null, + "autoRename": true, + "textStyleId": "S:cebee1b62ea594fa8f97b0b247fd163730736f2a,716:123" + } + }, + { + "id": "I81:272;2153:7986", + "name": "Text Link List Item", + "type": "INSTANCE", + "parentID": "81:272", + "parentName": "Text Link List", + "childrenNames": [ + { + "id": "I81:272;2153:7986;2153:7955", + "name": "List item", + "type": "TEXT", + "parentID": "I81:272;2153:7986", + "parentName": "Text Link List Item" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_InstanceNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 1, + "g": 1, + "b": 1 + }, + "visible": false, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 89, + "height": 22, + "tx": 0, + "ty": 220, + "x": 0, + "y": 220 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "NONE", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 0, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "MIN", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MAX", + "counterAxisAlignItems": "CENTER", + "itemSpacing": 0 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + }, + "variantMixin": { + "variantProperties": null + }, + "button": false + } + }, + { + "id": "I81:272;2153:7986;2153:7955", + "name": "List item", + "type": "TEXT", + "parentID": "I81:272;2153:7986", + "parentName": "Text Link List Item", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_TextNode": { + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 117, + "height": 22, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "SCALE", + "vertical": "SCALE" + }, + "nonResizableTextMixin": { + "paragraphIndent": 0, + "listSpacing": 0, + "hangingPunctuation": false, + "hangingList": false, + "fontSize": 16, + "fontName": { + "family": "Inter", + "style": "Regular" + }, + "fontWeight": 400, + "textCase": "ORIGINAL", + "textDecoration": "NONE", + "textDecorationStyle": null, + "letterSpacing": { + "value": 0, + "unit": "PERCENT" + }, + "lineHeight": { + "value": 139.9999976158142, + "unit": "PERCENT" + }, + "characters": "Design process" + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "textAlignHorizontal": "LEFT", + "textAlignVertical": "CENTER", + "textAutoResize": "WIDTH_AND_HEIGHT", + "textTruncation": "DISABLED", + "maxLines": null, + "autoRename": true, + "textStyleId": "S:cebee1b62ea594fa8f97b0b247fd163730736f2a,716:123" + } + }, + { + "id": "I81:272;2153:7988", + "name": "Text Link List Item", + "type": "INSTANCE", + "parentID": "81:272", + "parentName": "Text Link List", + "childrenNames": [ + { + "id": "I81:272;2153:7988;2153:7955", + "name": "List item", + "type": "TEXT", + "parentID": "I81:272;2153:7988", + "parentName": "Text Link List Item" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_InstanceNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": false, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 1, + "g": 1, + "b": 1 + }, + "visible": false, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 89, + "height": 22, + "tx": 0, + "ty": 254, + "x": 0, + "y": 254 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "NONE", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 0, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "MIN", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "paddingLeft": 0, + "paddingRight": 34, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "CENTER", + "itemSpacing": 0 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + }, + "variantMixin": { + "variantProperties": null + }, + "button": false + } + }, + { + "id": "I81:272;2153:7988;2153:7955", + "name": "List item", + "type": "TEXT", + "parentID": "I81:272;2153:7988", + "parentName": "Text Link List Item", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_TextNode": { + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 55, + "height": 22, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "SCALE", + "vertical": "SCALE" + }, + "nonResizableTextMixin": { + "paragraphIndent": 0, + "listSpacing": 0, + "hangingPunctuation": false, + "hangingList": false, + "fontSize": 16, + "fontName": { + "family": "Inter", + "style": "Regular" + }, + "fontWeight": 400, + "textCase": "ORIGINAL", + "textDecoration": "NONE", + "textDecorationStyle": null, + "letterSpacing": { + "value": 0, + "unit": "PERCENT" + }, + "lineHeight": { + "value": 139.9999976158142, + "unit": "PERCENT" + }, + "characters": "FigJam" + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "textAlignHorizontal": "LEFT", + "textAlignVertical": "CENTER", + "textAutoResize": "WIDTH_AND_HEIGHT", + "textTruncation": "DISABLED", + "maxLines": null, + "autoRename": true, + "textStyleId": "S:cebee1b62ea594fa8f97b0b247fd163730736f2a,716:123" + } + }, + { + "id": "81:273", + "name": "Text Link List", + "type": "INSTANCE", + "parentID": "81:258", + "parentName": "Footer", + "childrenNames": [ + { + "id": "I81:273;2162:7479", + "name": "Title", + "type": "FRAME", + "parentID": "81:273", + "parentName": "Text Link List" + }, + { + "id": "I81:273;2153:7976", + "name": "Text Link List Item", + "type": "INSTANCE", + "parentID": "81:273", + "parentName": "Text Link List" + }, + { + "id": "I81:273;2153:7978", + "name": "Text Link List Item", + "type": "INSTANCE", + "parentID": "81:273", + "parentName": "Text Link List" + }, + { + "id": "I81:273;2153:7980", + "name": "Text Link List Item", + "type": "INSTANCE", + "parentID": "81:273", + "parentName": "Text Link List" + }, + { + "id": "I81:273;2153:7982", + "name": "Text Link List Item", + "type": "INSTANCE", + "parentID": "81:273", + "parentName": "Text Link List" + }, + { + "id": "I81:273;2153:7984", + "name": "Text Link List Item", + "type": "INSTANCE", + "parentID": "81:273", + "parentName": "Text Link List" + }, + { + "id": "I81:273;2153:7986", + "name": "Text Link List Item", + "type": "INSTANCE", + "parentID": "81:273", + "parentName": "Text Link List" + }, + { + "id": "I81:273;2153:7988", + "name": "Text Link List Item", + "type": "INSTANCE", + "parentID": "81:273", + "parentName": "Text Link List" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_InstanceNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 262, + "height": 276, + "tx": 588, + "ty": 32, + "x": 588, + "y": 32 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "VERTICAL", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 12, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "VERTICAL", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "itemSpacing": 12 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + }, + "variantMixin": { + "variantProperties": { + "Density": "Default" + } + }, + "button": false + } + }, + { + "id": "I81:273;2162:7479", + "name": "Title", + "type": "FRAME", + "parentID": "81:273", + "parentName": "Text Link List", + "childrenNames": [ + { + "id": "I81:273;2162:6389", + "name": "Text Strong", + "type": "INSTANCE", + "parentID": "I81:273;2162:7479", + "parentName": "Title" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_FrameNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 262, + "height": 38, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "VERTICAL", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 16, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 10, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "VERTICAL", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 16, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "itemSpacing": 10 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + } + } + }, + { + "id": "I81:273;2162:6389", + "name": "Text Strong", + "type": "INSTANCE", + "parentID": "I81:273;2162:7479", + "parentName": "Title", + "childrenNames": [ + { + "id": "I81:273;2162:6389;2087:8468", + "name": "Text Strong", + "type": "TEXT", + "parentID": "I81:273;2162:6389", + "parentName": "Text Strong" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_InstanceNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 262, + "height": 22, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "AUTO", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 0, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "AUTO", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "itemSpacing": 0 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + }, + "variantMixin": { + "variantProperties": null + }, + "button": false + } + }, + { + "id": "I81:273;2162:6389;2087:8468", + "name": "Text Strong", + "type": "TEXT", + "parentID": "I81:273;2162:6389", + "parentName": "Text Strong", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_TextNode": { + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 82, + "height": 22, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "nonResizableTextMixin": { + "paragraphIndent": 0, + "listSpacing": 0, + "hangingPunctuation": false, + "hangingList": false, + "fontSize": 16, + "fontName": { + "family": "Inter", + "style": "Semi Bold" + }, + "fontWeight": 600, + "textCase": "ORIGINAL", + "textDecoration": "NONE", + "textDecorationStyle": null, + "letterSpacing": { + "value": 0, + "unit": "PERCENT" + }, + "lineHeight": { + "value": 139.9999976158142, + "unit": "PERCENT" + }, + "characters": "Resources" + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "textAlignHorizontal": "LEFT", + "textAlignVertical": "TOP", + "textAutoResize": "WIDTH_AND_HEIGHT", + "textTruncation": "DISABLED", + "maxLines": null, + "autoRename": true, + "textStyleId": "S:e21b16ffb31d9ee1ff2a4792765537ea77c7b80e,716:147" + } + }, + { + "id": "I81:273;2153:7976", + "name": "Text Link List Item", + "type": "INSTANCE", + "parentID": "81:273", + "parentName": "Text Link List", + "childrenNames": [ + { + "id": "I81:273;2153:7976;2153:7955", + "name": "List item", + "type": "TEXT", + "parentID": "I81:273;2153:7976", + "parentName": "Text Link List Item" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_InstanceNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 1, + "g": 1, + "b": 1 + }, + "visible": false, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 89, + "height": 22, + "tx": 0, + "ty": 50, + "x": 0, + "y": 50 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "NONE", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 0, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "MIN", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "paddingLeft": 0, + "paddingRight": 55, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "CENTER", + "itemSpacing": 0 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + }, + "variantMixin": { + "variantProperties": null + }, + "button": false + } + }, + { + "id": "I81:273;2153:7976;2153:7955", + "name": "List item", + "type": "TEXT", + "parentID": "I81:273;2153:7976", + "parentName": "Text Link List Item", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_TextNode": { + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 34, + "height": 22, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "SCALE", + "vertical": "SCALE" + }, + "nonResizableTextMixin": { + "paragraphIndent": 0, + "listSpacing": 0, + "hangingPunctuation": false, + "hangingList": false, + "fontSize": 16, + "fontName": { + "family": "Inter", + "style": "Regular" + }, + "fontWeight": 400, + "textCase": "ORIGINAL", + "textDecoration": "NONE", + "textDecorationStyle": null, + "letterSpacing": { + "value": 0, + "unit": "PERCENT" + }, + "lineHeight": { + "value": 139.9999976158142, + "unit": "PERCENT" + }, + "characters": "Blog" + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "textAlignHorizontal": "LEFT", + "textAlignVertical": "CENTER", + "textAutoResize": "WIDTH_AND_HEIGHT", + "textTruncation": "DISABLED", + "maxLines": null, + "autoRename": true, + "textStyleId": "S:cebee1b62ea594fa8f97b0b247fd163730736f2a,716:123" + } + }, + { + "id": "I81:273;2153:7978", + "name": "Text Link List Item", + "type": "INSTANCE", + "parentID": "81:273", + "parentName": "Text Link List", + "childrenNames": [ + { + "id": "I81:273;2153:7978;2153:7955", + "name": "List item", + "type": "TEXT", + "parentID": "I81:273;2153:7978", + "parentName": "Text Link List Item" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_InstanceNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 1, + "g": 1, + "b": 1 + }, + "visible": false, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 89, + "height": 22, + "tx": 0, + "ty": 84, + "x": 0, + "y": 84 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "NONE", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 0, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "MIN", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MAX", + "counterAxisAlignItems": "CENTER", + "itemSpacing": 0 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + }, + "variantMixin": { + "variantProperties": null + }, + "button": false + } + }, + { + "id": "I81:273;2153:7978;2153:7955", + "name": "List item", + "type": "TEXT", + "parentID": "I81:273;2153:7978", + "parentName": "Text Link List Item", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_TextNode": { + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 109, + "height": 22, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "SCALE", + "vertical": "SCALE" + }, + "nonResizableTextMixin": { + "paragraphIndent": 0, + "listSpacing": 0, + "hangingPunctuation": false, + "hangingList": false, + "fontSize": 16, + "fontName": { + "family": "Inter", + "style": "Regular" + }, + "fontWeight": 400, + "textCase": "ORIGINAL", + "textDecoration": "NONE", + "textDecorationStyle": null, + "letterSpacing": { + "value": 0, + "unit": "PERCENT" + }, + "lineHeight": { + "value": 139.9999976158142, + "unit": "PERCENT" + }, + "characters": "Best practices" + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "textAlignHorizontal": "LEFT", + "textAlignVertical": "CENTER", + "textAutoResize": "WIDTH_AND_HEIGHT", + "textTruncation": "DISABLED", + "maxLines": null, + "autoRename": true, + "textStyleId": "S:cebee1b62ea594fa8f97b0b247fd163730736f2a,716:123" + } + }, + { + "id": "I81:273;2153:7980", + "name": "Text Link List Item", + "type": "INSTANCE", + "parentID": "81:273", + "parentName": "Text Link List", + "childrenNames": [ + { + "id": "I81:273;2153:7980;2153:7955", + "name": "List item", + "type": "TEXT", + "parentID": "I81:273;2153:7980", + "parentName": "Text Link List Item" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_InstanceNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 1, + "g": 1, + "b": 1 + }, + "visible": false, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 89, + "height": 22, + "tx": 0, + "ty": 118, + "x": 0, + "y": 118 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "NONE", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 0, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "MIN", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "paddingLeft": 0, + "paddingRight": 40, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "CENTER", + "itemSpacing": 0 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + }, + "variantMixin": { + "variantProperties": null + }, + "button": false + } + }, + { + "id": "I81:273;2153:7980;2153:7955", + "name": "List item", + "type": "TEXT", + "parentID": "I81:273;2153:7980", + "parentName": "Text Link List Item", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_TextNode": { + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 49, + "height": 22, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "SCALE", + "vertical": "SCALE" + }, + "nonResizableTextMixin": { + "paragraphIndent": 0, + "listSpacing": 0, + "hangingPunctuation": false, + "hangingList": false, + "fontSize": 16, + "fontName": { + "family": "Inter", + "style": "Regular" + }, + "fontWeight": 400, + "textCase": "ORIGINAL", + "textDecoration": "NONE", + "textDecorationStyle": null, + "letterSpacing": { + "value": 0, + "unit": "PERCENT" + }, + "lineHeight": { + "value": 139.9999976158142, + "unit": "PERCENT" + }, + "characters": "Colors" + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "textAlignHorizontal": "LEFT", + "textAlignVertical": "CENTER", + "textAutoResize": "WIDTH_AND_HEIGHT", + "textTruncation": "DISABLED", + "maxLines": null, + "autoRename": true, + "textStyleId": "S:cebee1b62ea594fa8f97b0b247fd163730736f2a,716:123" + } + }, + { + "id": "I81:273;2153:7982", + "name": "Text Link List Item", + "type": "INSTANCE", + "parentID": "81:273", + "parentName": "Text Link List", + "childrenNames": [ + { + "id": "I81:273;2153:7982;2153:7955", + "name": "List item", + "type": "TEXT", + "parentID": "I81:273;2153:7982", + "parentName": "Text Link List Item" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_InstanceNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 1, + "g": 1, + "b": 1 + }, + "visible": false, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 89, + "height": 22, + "tx": 0, + "ty": 152, + "x": 0, + "y": 152 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "NONE", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 0, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "MIN", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "CENTER", + "counterAxisAlignItems": "CENTER", + "itemSpacing": 0 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + }, + "variantMixin": { + "variantProperties": null + }, + "button": false + } + }, + { + "id": "I81:273;2153:7982;2153:7955", + "name": "List item", + "type": "TEXT", + "parentID": "I81:273;2153:7982", + "parentName": "Text Link List Item", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_TextNode": { + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 90, + "height": 22, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "SCALE", + "vertical": "SCALE" + }, + "nonResizableTextMixin": { + "paragraphIndent": 0, + "listSpacing": 0, + "hangingPunctuation": false, + "hangingList": false, + "fontSize": 16, + "fontName": { + "family": "Inter", + "style": "Regular" + }, + "fontWeight": 400, + "textCase": "ORIGINAL", + "textDecoration": "NONE", + "textDecorationStyle": null, + "letterSpacing": { + "value": 0, + "unit": "PERCENT" + }, + "lineHeight": { + "value": 139.9999976158142, + "unit": "PERCENT" + }, + "characters": "Color wheel" + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "textAlignHorizontal": "LEFT", + "textAlignVertical": "CENTER", + "textAutoResize": "WIDTH_AND_HEIGHT", + "textTruncation": "DISABLED", + "maxLines": null, + "autoRename": true, + "textStyleId": "S:cebee1b62ea594fa8f97b0b247fd163730736f2a,716:123" + } + }, + { + "id": "I81:273;2153:7984", + "name": "Text Link List Item", + "type": "INSTANCE", + "parentID": "81:273", + "parentName": "Text Link List", + "childrenNames": [ + { + "id": "I81:273;2153:7984;2153:7955", + "name": "List item", + "type": "TEXT", + "parentID": "I81:273;2153:7984", + "parentName": "Text Link List Item" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_InstanceNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 1, + "g": 1, + "b": 1 + }, + "visible": false, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 89, + "height": 22, + "tx": 0, + "ty": 186, + "x": 0, + "y": 186 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "NONE", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 0, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "MIN", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "paddingLeft": 0, + "paddingRight": 28, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "CENTER", + "itemSpacing": 0 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + }, + "variantMixin": { + "variantProperties": null + }, + "button": false + } + }, + { + "id": "I81:273;2153:7984;2153:7955", + "name": "List item", + "type": "TEXT", + "parentID": "I81:273;2153:7984", + "parentName": "Text Link List Item", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_TextNode": { + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 61, + "height": 22, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "SCALE", + "vertical": "SCALE" + }, + "nonResizableTextMixin": { + "paragraphIndent": 0, + "listSpacing": 0, + "hangingPunctuation": false, + "hangingList": false, + "fontSize": 16, + "fontName": { + "family": "Inter", + "style": "Regular" + }, + "fontWeight": 400, + "textCase": "ORIGINAL", + "textDecoration": "NONE", + "textDecorationStyle": null, + "letterSpacing": { + "value": 0, + "unit": "PERCENT" + }, + "lineHeight": { + "value": 139.9999976158142, + "unit": "PERCENT" + }, + "characters": "Support" + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "textAlignHorizontal": "LEFT", + "textAlignVertical": "CENTER", + "textAutoResize": "WIDTH_AND_HEIGHT", + "textTruncation": "DISABLED", + "maxLines": null, + "autoRename": true, + "textStyleId": "S:cebee1b62ea594fa8f97b0b247fd163730736f2a,716:123" + } + }, + { + "id": "I81:273;2153:7986", + "name": "Text Link List Item", + "type": "INSTANCE", + "parentID": "81:273", + "parentName": "Text Link List", + "childrenNames": [ + { + "id": "I81:273;2153:7986;2153:7955", + "name": "List item", + "type": "TEXT", + "parentID": "I81:273;2153:7986", + "parentName": "Text Link List Item" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_InstanceNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 1, + "g": 1, + "b": 1 + }, + "visible": false, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 89, + "height": 22, + "tx": 0, + "ty": 220, + "x": 0, + "y": 220 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "NONE", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 0, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "MIN", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "paddingLeft": 0, + "paddingRight": 3, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "CENTER", + "counterAxisAlignItems": "CENTER", + "itemSpacing": 0 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + }, + "variantMixin": { + "variantProperties": null + }, + "button": false + } + }, + { + "id": "I81:273;2153:7986;2153:7955", + "name": "List item", + "type": "TEXT", + "parentID": "I81:273;2153:7986", + "parentName": "Text Link List Item", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_TextNode": { + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 86, + "height": 22, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "SCALE", + "vertical": "SCALE" + }, + "nonResizableTextMixin": { + "paragraphIndent": 0, + "listSpacing": 0, + "hangingPunctuation": false, + "hangingList": false, + "fontSize": 16, + "fontName": { + "family": "Inter", + "style": "Regular" + }, + "fontWeight": 400, + "textCase": "ORIGINAL", + "textDecoration": "NONE", + "textDecorationStyle": null, + "letterSpacing": { + "value": 0, + "unit": "PERCENT" + }, + "lineHeight": { + "value": 139.9999976158142, + "unit": "PERCENT" + }, + "characters": "Developers" + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "textAlignHorizontal": "LEFT", + "textAlignVertical": "CENTER", + "textAutoResize": "WIDTH_AND_HEIGHT", + "textTruncation": "DISABLED", + "maxLines": null, + "autoRename": true, + "textStyleId": "S:cebee1b62ea594fa8f97b0b247fd163730736f2a,716:123" + } + }, + { + "id": "I81:273;2153:7988", + "name": "Text Link List Item", + "type": "INSTANCE", + "parentID": "81:273", + "parentName": "Text Link List", + "childrenNames": [ + { + "id": "I81:273;2153:7988;2153:7955", + "name": "List item", + "type": "TEXT", + "parentID": "I81:273;2153:7988", + "parentName": "Text Link List Item" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_InstanceNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 1, + "g": 1, + "b": 1 + }, + "visible": false, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 89, + "height": 22, + "tx": 0, + "ty": 254, + "x": 0, + "y": 254 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "NONE", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 0, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "MIN", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MAX", + "counterAxisAlignItems": "CENTER", + "itemSpacing": 0 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + }, + "variantMixin": { + "variantProperties": null + }, + "button": false + } + }, + { + "id": "I81:273;2153:7988;2153:7955", + "name": "List item", + "type": "TEXT", + "parentID": "I81:273;2153:7988", + "parentName": "Text Link List Item", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_TextNode": { + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 123, + "height": 22, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "SCALE", + "vertical": "SCALE" + }, + "nonResizableTextMixin": { + "paragraphIndent": 0, + "listSpacing": 0, + "hangingPunctuation": false, + "hangingList": false, + "fontSize": 16, + "fontName": { + "family": "Inter", + "style": "Regular" + }, + "fontWeight": 400, + "textCase": "ORIGINAL", + "textDecoration": "NONE", + "textDecorationStyle": null, + "letterSpacing": { + "value": 0, + "unit": "PERCENT" + }, + "lineHeight": { + "value": 139.9999976158142, + "unit": "PERCENT" + }, + "characters": "Resource library" + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "textAlignHorizontal": "LEFT", + "textAlignVertical": "CENTER", + "textAutoResize": "WIDTH_AND_HEIGHT", + "textTruncation": "DISABLED", + "maxLines": null, + "autoRename": true, + "textStyleId": "S:cebee1b62ea594fa8f97b0b247fd163730736f2a,716:123" + } + }, + { + "id": "1:2820", + "name": "Panel Image Content Reverse", + "type": "INSTANCE", + "parentID": "1:3", + "parentName": "Section 1", + "childrenNames": [ + { + "id": "I1:2820;348:15124", + "name": "Text Content Flow", + "type": "FRAME", + "parentID": "1:2820", + "parentName": "Panel Image Content Reverse" + }, + { + "id": "I1:2820;348:15128", + "name": "Image", + "type": "FRAME", + "parentID": "1:2820", + "parentName": "Panel Image Content Reverse" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_InstanceNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 1, + "g": 1, + "b": 1 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 0.800000011920929, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 1200, + "height": 479, + "tx": 100, + "ty": 30, + "x": 100, + "y": 30 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "layoutWrap": "NO_WRAP", + "paddingLeft": 64, + "paddingRight": 64, + "paddingTop": 64, + "paddingBottom": 64, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "AUTO", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "CENTER", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 48, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "paddingLeft": 64, + "paddingRight": 64, + "paddingTop": 64, + "paddingBottom": 64, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "AUTO", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "CENTER", + "itemSpacing": 48 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + }, + "variantMixin": { + "variantProperties": { + "Platform": "Desktop" + } + }, + "button": false + } + }, + { + "id": "I1:2820;348:15124", + "name": "Text Content Flow", + "type": "FRAME", + "parentID": "1:2820", + "parentName": "Panel Image Content Reverse", + "childrenNames": [ + { + "id": "I1:2820;348:15125", + "name": "Text Content Heading", + "type": "INSTANCE", + "parentID": "I1:2820;348:15124", + "parentName": "Text Content Flow" + }, + { + "id": "I1:2820;348:15126", + "name": "Text", + "type": "INSTANCE", + "parentID": "I1:2820;348:15124", + "parentName": "Text Content Flow" + }, + { + "id": "I1:2820;348:15127", + "name": "Text", + "type": "INSTANCE", + "parentID": "I1:2820;348:15124", + "parentName": "Text Content Flow" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_FrameNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 484, + "height": 351, + "minWidth": 300, + "tx": 64, + "ty": 64, + "x": 64, + "y": 64 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "VERTICAL", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 24, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "VERTICAL", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "itemSpacing": 24 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + } + } + }, + { + "id": "I1:2820;348:15125", + "name": "Text Content Heading", + "type": "INSTANCE", + "parentID": "I1:2820;348:15124", + "parentName": "Text Content Flow", + "childrenNames": [ + { + "id": "I1:2820;348:15125;2144:3861", + "name": "Heading", + "type": "TEXT", + "parentID": "I1:2820;348:15125", + "parentName": "Text Content Heading" + }, + { + "id": "I1:2820;348:15125;2144:3862", + "name": "Subheading", + "type": "TEXT", + "parentID": "I1:2820;348:15125", + "parentName": "Text Content Heading" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_InstanceNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 484, + "height": 64, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "VERTICAL", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 8, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "VERTICAL", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "itemSpacing": 8 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + }, + "variantMixin": { + "variantProperties": { + "Align": "Start" + } + }, + "button": false + } + }, + { + "id": "I1:2820;348:15125;2144:3861", + "name": "Heading", + "type": "TEXT", + "parentID": "I1:2820;348:15125", + "parentName": "Text Content Heading", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_TextNode": { + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 484, + "height": 38, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "nonResizableTextMixin": { + "paragraphIndent": 0, + "listSpacing": 0, + "hangingPunctuation": false, + "hangingList": false, + "fontSize": 32, + "fontName": { + "family": "Inter", + "style": "Semi Bold" + }, + "fontWeight": 600, + "textCase": "ORIGINAL", + "textDecoration": "NONE", + "textDecorationStyle": null, + "letterSpacing": { + "value": -2, + "unit": "PERCENT" + }, + "lineHeight": { + "value": 120.00000476837158, + "unit": "PERCENT" + }, + "characters": "UX Importer for Unity UI Toolkit" + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "textAlignHorizontal": "LEFT", + "textAlignVertical": "TOP", + "textAutoResize": "HEIGHT", + "textTruncation": "DISABLED", + "maxLines": null, + "autoRename": true, + "textStyleId": "" + } + }, + { + "id": "I1:2820;348:15125;2144:3862", + "name": "Subheading", + "type": "TEXT", + "parentID": "I1:2820;348:15125", + "parentName": "Text Content Heading", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_TextNode": { + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.4588235318660736, + "g": 0.4588235318660736, + "b": 0.4588235318660736 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 484, + "height": 18, + "tx": 0, + "ty": 46, + "x": 0, + "y": 46 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "nonResizableTextMixin": { + "paragraphIndent": 0, + "listSpacing": 0, + "hangingPunctuation": false, + "hangingList": false, + "fontSize": 15, + "fontName": { + "family": "Inter", + "style": "Regular" + }, + "fontWeight": 400, + "textCase": "ORIGINAL", + "textDecoration": "NONE", + "textDecorationStyle": null, + "letterSpacing": { + "value": 0, + "unit": "PERCENT" + }, + "lineHeight": { + "value": 120.00000476837158, + "unit": "PERCENT" + }, + "characters": "Stop Recreating UIs. Start Development Immediately." + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "textAlignHorizontal": "LEFT", + "textAlignVertical": "CENTER", + "textAutoResize": "HEIGHT", + "textTruncation": "DISABLED", + "maxLines": null, + "autoRename": false, + "textStyleId": "" + } + }, + { + "id": "I1:2820;348:15126", + "name": "Text", + "type": "INSTANCE", + "parentID": "I1:2820;348:15124", + "parentName": "Text Content Flow", + "childrenNames": [ + { + "id": "I1:2820;348:15126;2087:8469", + "name": "Text", + "type": "TEXT", + "parentID": "I1:2820;348:15126", + "parentName": "Text" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_InstanceNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 484, + "height": 56, + "tx": 0, + "ty": 88, + "x": 0, + "y": 88 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "AUTO", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 0, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "AUTO", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "itemSpacing": 0 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + }, + "variantMixin": { + "variantProperties": null + }, + "button": false + } + }, + { + "id": "I1:2820;348:15126;2087:8469", + "name": "Text", + "type": "TEXT", + "parentID": "I1:2820;348:15126", + "parentName": "Text", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_TextNode": { + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 484, + "height": 56, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 1, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 1, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "nonResizableTextMixin": { + "paragraphIndent": 0, + "listSpacing": 0, + "hangingPunctuation": false, + "hangingList": false, + "fontSize": 20, + "fontName": { + "family": "Inter", + "style": "Regular" + }, + "fontWeight": 400, + "textCase": "ORIGINAL", + "textDecoration": "NONE", + "textDecorationStyle": null, + "letterSpacing": { + "value": 0, + "unit": "PERCENT" + }, + "lineHeight": { + "value": 139.9999976158142, + "unit": "PERCENT" + }, + "characters": "Seamlessly transfer your Figma designs to Unity in just a few simple steps." + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "textAlignHorizontal": "LEFT", + "textAlignVertical": "TOP", + "textAutoResize": "HEIGHT", + "textTruncation": "DISABLED", + "maxLines": null, + "autoRename": true, + "textStyleId": "" + } + }, + { + "id": "I1:2820;348:15127", + "name": "Text", + "type": "INSTANCE", + "parentID": "I1:2820;348:15124", + "parentName": "Text Content Flow", + "childrenNames": [ + { + "id": "I1:2820;348:15127;2087:8469", + "name": "Text", + "type": "TEXT", + "parentID": "I1:2820;348:15127", + "parentName": "Text" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_InstanceNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 484, + "height": 476, + "tx": 0, + "ty": 168, + "x": 0, + "y": 168 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "AUTO", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 0, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "AUTO", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "itemSpacing": 0 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + }, + "variantMixin": { + "variantProperties": null + }, + "button": false + } + }, + { + "id": "I1:2820;348:15127;2087:8469", + "name": "Text", + "type": "TEXT", + "parentID": "I1:2820;348:15127", + "parentName": "Text", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_TextNode": { + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 484, + "height": 476, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 1, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 1, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "nonResizableTextMixin": { + "paragraphIndent": 0, + "listSpacing": 0, + "hangingPunctuation": false, + "hangingList": false, + "fontSize": 20, + "fontWeight": 400, + "textCase": "ORIGINAL", + "textDecoration": "NONE", + "textDecorationStyle": null, + "letterSpacing": { + "value": 0, + "unit": "PERCENT" + }, + "lineHeight": { + "value": 139.9999976158142, + "unit": "PERCENT" + }, + "characters": "This tool serves as the “starting point” for developing UI designs created in web-based design tools using the Unity UI Toolkit.\n\nIt frees you from the inefficient task of manually assembling UI while “referencing” designs created by designers.\n\nIt recreates layouts with high precision, eliminating most tedious manual adjustments. It outputs data to reproduce designs —including rounded-corner images and masked images—to JSON, supporting complex visual elements.\n\nYou can focus on UI logic and feature implementation. Use it as your development foundation." + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "textAlignHorizontal": "LEFT", + "textAlignVertical": "TOP", + "textAutoResize": "HEIGHT", + "textTruncation": "DISABLED", + "maxLines": null, + "autoRename": true, + "textStyleId": "" + } + }, + { + "id": "I1:2820;348:15128", + "name": "Image", + "type": "FRAME", + "parentID": "1:2820", + "parentName": "Panel Image Content Reverse", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_FrameNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": false, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 484, + "height": 350, + "tx": 596, + "ty": 64.5, + "x": 596, + "y": 64.5 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 4, + "strokeBottomWeight": 4, + "strokeLeftWeight": 4, + "strokeRightWeight": 4 + }, + "autoLayoutMixin": { + "layoutMode": "VERTICAL", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "CENTER", + "counterAxisAlignItems": "CENTER", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 0, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "VERTICAL", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "CENTER", + "counterAxisAlignItems": "CENTER", + "itemSpacing": 0 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": true, + "guides": [] + } + } + } + }, + { + "id": "1:2838", + "name": "bamboo-shoots-7181496_1280 1", + "type": "RECTANGLE", + "parentID": "1:3", + "parentName": "Section 1", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": true, + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 745, + "height": 496, + "tx": 734, + "ty": 114, + "x": 734, + "y": 114 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "cornerMixin": { + "cornerRadius": 60 + }, + "rectangleCornerMixin": { + "topLeftRadius": 60, + "topRightRadius": 60, + "bottomLeftRadius": 60, + "bottomRightRadius": 60 + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "aspectRatioLockMixin": { + "targetAspectRatio": { + "x": 1280, + "y": 852 + } + } + } + }, + { + "id": "4:240", + "name": "Group 1", + "type": "GROUP", + "parentID": "1:3", + "parentName": "Section 1", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": true + }, + "nodeParameters_GroupNode": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 828, + "height": 460, + "tx": 886, + "ty": 434, + "x": 886, + "y": 434 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + } + } + }, + { + "id": "1:1330", + "name": "Menu", + "type": "INSTANCE", + "parentID": "1:3", + "parentName": "Section 1", + "childrenNames": [ + { + "id": "I1:1330;280:15938", + "name": "Menu Header", + "type": "FRAME", + "parentID": "1:1330", + "parentName": "Menu" + }, + { + "id": "I1:1330;9762:722", + "name": "Menu Separator", + "type": "INSTANCE", + "parentID": "1:1330", + "parentName": "Menu" + }, + { + "id": "I1:1330;83:33577", + "name": "Menu Section", + "type": "FRAME", + "parentID": "1:1330", + "parentName": "Menu" + }, + { + "id": "I1:1330;9762:724", + "name": "Menu Separator", + "type": "INSTANCE", + "parentID": "1:1330", + "parentName": "Menu" + }, + { + "id": "I1:1330;83:33611", + "name": "Menu Section", + "type": "FRAME", + "parentID": "1:1330", + "parentName": "Menu" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_InstanceNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 1, + "g": 1, + "b": 1 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": { + "stroke": { + "strokes": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.8509804010391235, + "g": 0.8509804010391235, + "b": 0.8509804010391235 + }, + "visible": true, + "opacity": 1 + } + ], + "strokeWeight": 1, + "strokeAlign": "INSIDE", + "strokeJoin": "MITER" + } + }, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 8 + }, + "rectangleCornerMixin": { + "topLeftRadius": 8, + "topRightRadius": 8, + "bottomLeftRadius": 8, + "bottomRightRadius": 8 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 301, + "height": 454, + "tx": 1478.3368209302425, + "ty": 124.83776313066483, + "x": 1385, + "y": 80 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": -30.00000044529205, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "VERTICAL", + "layoutWrap": "NO_WRAP", + "paddingLeft": 8, + "paddingRight": 8, + "paddingTop": 8, + "paddingBottom": 8, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 0, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "VERTICAL", + "paddingLeft": 8, + "paddingRight": 8, + "paddingTop": 8, + "paddingBottom": 8, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "itemSpacing": 0 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": true, + "guides": [] + } + }, + "variantMixin": { + "variantProperties": null + }, + "button": false + } + }, + { + "id": "I1:1330;280:15938", + "name": "Menu Header", + "type": "FRAME", + "parentID": "1:1330", + "parentName": "Menu", + "childrenNames": [ + { + "id": "I1:1330;280:15946", + "name": "Heading", + "type": "TEXT", + "parentID": "I1:1330;280:15938", + "parentName": "Menu Header" + }, + { + "id": "I1:1330;280:15944", + "name": "Heading", + "type": "TEXT", + "parentID": "I1:1330;280:15938", + "parentName": "Menu Header" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_FrameNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 285, + "height": 54, + "tx": 8, + "ty": 8, + "x": 8, + "y": 8 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "VERTICAL", + "layoutWrap": "NO_WRAP", + "paddingLeft": 16, + "paddingRight": 16, + "paddingTop": 8, + "paddingBottom": 4, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 0, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "VERTICAL", + "paddingLeft": 16, + "paddingRight": 16, + "paddingTop": 8, + "paddingBottom": 4, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "itemSpacing": 0 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": true, + "guides": [] + } + } + } + }, + { + "id": "I1:1330;280:15946", + "name": "Heading", + "type": "TEXT", + "parentID": "I1:1330;280:15938", + "parentName": "Menu Header", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_TextNode": { + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.4588235318660736, + "g": 0.4588235318660736, + "b": 0.4588235318660736 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 253, + "height": 20, + "tx": 16, + "ty": 8, + "x": 16, + "y": 8 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "nonResizableTextMixin": { + "paragraphIndent": 0, + "listSpacing": 0, + "hangingPunctuation": false, + "hangingList": false, + "fontSize": 14, + "fontName": { + "family": "Inter", + "style": "Regular" + }, + "fontWeight": 400, + "textCase": "ORIGINAL", + "textDecoration": "NONE", + "textDecorationStyle": null, + "letterSpacing": { + "value": 0, + "unit": "PERCENT" + }, + "lineHeight": { + "value": 139.9999976158142, + "unit": "PERCENT" + }, + "characters": "Heading" + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "textAlignHorizontal": "LEFT", + "textAlignVertical": "TOP", + "textAutoResize": "HEIGHT", + "textTruncation": "DISABLED", + "maxLines": null, + "autoRename": true, + "textStyleId": "S:dd16ffab542d022b9a2d78275ed222c2cb4646b4,3017:75" + } + }, + { + "id": "I1:1330;280:15944", + "name": "Heading", + "type": "TEXT", + "parentID": "I1:1330;280:15938", + "parentName": "Menu Header", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_TextNode": { + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 253, + "height": 22, + "tx": 16, + "ty": 28, + "x": 16, + "y": 28 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "nonResizableTextMixin": { + "paragraphIndent": 0, + "listSpacing": 0, + "hangingPunctuation": false, + "hangingList": false, + "fontSize": 16, + "fontName": { + "family": "Inter", + "style": "Semi Bold" + }, + "fontWeight": 600, + "textCase": "ORIGINAL", + "textDecoration": "NONE", + "textDecorationStyle": null, + "letterSpacing": { + "value": 0, + "unit": "PERCENT" + }, + "lineHeight": { + "value": 139.9999976158142, + "unit": "PERCENT" + }, + "characters": "Heading" + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "textAlignHorizontal": "LEFT", + "textAlignVertical": "TOP", + "textAutoResize": "HEIGHT", + "textTruncation": "DISABLED", + "maxLines": null, + "autoRename": true, + "textStyleId": "S:e21b16ffb31d9ee1ff2a4792765537ea77c7b80e,716:147" + } + }, + { + "id": "I1:1330;9762:722", + "name": "Menu Separator", + "type": "INSTANCE", + "parentID": "1:1330", + "parentName": "Menu", + "childrenNames": [ + { + "id": "I1:1330;9762:722;9762:732", + "name": "Rule", + "type": "RECTANGLE", + "parentID": "I1:1330;9762:722", + "parentName": "Menu Separator" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_InstanceNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 285, + "height": 17, + "tx": 8, + "ty": 62, + "x": 8, + "y": 62 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "VERTICAL", + "layoutWrap": "NO_WRAP", + "paddingLeft": 16, + "paddingRight": 16, + "paddingTop": 8, + "paddingBottom": 8, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "CENTER", + "counterAxisAlignItems": "CENTER", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 0, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "VERTICAL", + "paddingLeft": 16, + "paddingRight": 16, + "paddingTop": 8, + "paddingBottom": 8, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "CENTER", + "counterAxisAlignItems": "CENTER", + "itemSpacing": 0 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + }, + "variantMixin": { + "variantProperties": null + }, + "button": false + } + }, + { + "id": "I1:1330;9762:722;9762:732", + "name": "Rule", + "type": "RECTANGLE", + "parentID": "I1:1330;9762:722", + "parentName": "Menu Separator", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": true, + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.8509804010391235, + "g": 0.8509804010391235, + "b": 0.8509804010391235 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 253, + "height": 1, + "tx": 16, + "ty": 8, + "x": 16, + "y": 8 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + } + } + }, + { + "id": "I1:1330;83:33577", + "name": "Menu Section", + "type": "FRAME", + "parentID": "1:1330", + "parentName": "Menu", + "childrenNames": [ + { + "id": "I1:1330;83:33578", + "name": "Menu Item", + "type": "INSTANCE", + "parentID": "I1:1330;83:33577", + "parentName": "Menu Section" + }, + { + "id": "I1:1330;83:33579", + "name": "Menu Item", + "type": "INSTANCE", + "parentID": "I1:1330;83:33577", + "parentName": "Menu Section" + }, + { + "id": "I1:1330;83:33580", + "name": "Menu Item", + "type": "INSTANCE", + "parentID": "I1:1330;83:33577", + "parentName": "Menu Section" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_FrameNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 8 + }, + "rectangleCornerMixin": { + "topLeftRadius": 8, + "topRightRadius": 8, + "bottomLeftRadius": 8, + "bottomRightRadius": 8 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 285, + "height": 210, + "tx": 8, + "ty": 79, + "x": 8, + "y": 79 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "VERTICAL", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 0, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "VERTICAL", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "itemSpacing": 0 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": true, + "guides": [] + } + } + } + }, + { + "id": "I1:1330;83:33578", + "name": "Menu Item", + "type": "INSTANCE", + "parentID": "I1:1330;83:33577", + "parentName": "Menu Section", + "childrenNames": [ + { + "id": "I1:1330;83:33578;9762:746", + "name": "Star", + "type": "INSTANCE", + "parentID": "I1:1330;83:33578", + "parentName": "Menu Item" + }, + { + "id": "I1:1330;83:33578;321:1231", + "name": "Body", + "type": "FRAME", + "parentID": "I1:1330;83:33578", + "parentName": "Menu Item" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_InstanceNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": {}, + "strokeCap": "ROUND", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 8 + }, + "rectangleCornerMixin": { + "topLeftRadius": 8, + "topRightRadius": 8, + "bottomLeftRadius": 8, + "bottomRightRadius": 8 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 285, + "height": 70, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "layoutWrap": "NO_WRAP", + "paddingLeft": 16, + "paddingRight": 16, + "paddingTop": 12, + "paddingBottom": 12, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "AUTO", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 12, + "counterAxisSpacing": 12, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "paddingLeft": 16, + "paddingRight": 16, + "paddingTop": 12, + "paddingBottom": 12, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "AUTO", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "itemSpacing": 12 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": true, + "guides": [] + } + }, + "variantMixin": { + "variantProperties": { + "State": "Default" + } + }, + "button": false + } + }, + { + "id": "I1:1330;83:33578;9762:746", + "name": "Star", + "type": "INSTANCE", + "parentID": "I1:1330;83:33578", + "parentName": "Menu Item", + "childrenNames": [ + { + "id": "I1:1330;83:33578;9762:746;7758:12316", + "name": "Icon", + "type": "VECTOR", + "parentID": "I1:1330;83:33578;9762:746", + "parentName": "Star" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_InstanceNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 1, + "g": 1, + "b": 1 + }, + "visible": false, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 20, + "height": 20, + "tx": 16, + "ty": 12, + "x": 16, + "y": 12 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "NONE", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 0, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "MIN", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "paddingLeft": 1.666666865348816, + "paddingRight": 1.666667103767395, + "paddingTop": 1.666666865348816, + "paddingBottom": 2.483332633972168, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "CENTER", + "counterAxisAlignItems": "CENTER", + "itemSpacing": 0 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": true, + "guides": [] + } + }, + "variantMixin": { + "variantProperties": { + "Size": "20" + } + }, + "button": false + } + }, + { + "id": "I1:1330;83:33578;9762:746;7758:12316", + "name": "Icon", + "type": "VECTOR", + "parentID": "I1:1330;83:33578;9762:746", + "parentName": "Star", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": true, + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": { + "stroke": { + "strokes": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "visible": true, + "opacity": 1 + } + ], + "strokeWeight": 2, + "strokeAlign": "CENTER", + "strokeJoin": "ROUND" + } + }, + "strokeCap": "ROUND", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 16.66666603088379, + "height": 15.850000381469727, + "tx": 1.666666865348816, + "ty": 1.666666865348816, + "x": 1.666666865348816, + "y": 1.666666865348816 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "SCALE", + "vertical": "SCALE" + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + } + } + }, + { + "id": "I1:1330;83:33578;321:1231", + "name": "Body", + "type": "FRAME", + "parentID": "I1:1330;83:33578", + "parentName": "Menu Item", + "childrenNames": [ + { + "id": "I1:1330;83:33578;321:1232", + "name": "Row", + "type": "FRAME", + "parentID": "I1:1330;83:33578;321:1231", + "parentName": "Body" + }, + { + "id": "I1:1330;83:33578;321:1235", + "name": "Description", + "type": "TEXT", + "parentID": "I1:1330;83:33578;321:1231", + "parentName": "Body" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_FrameNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 221, + "height": 46, + "tx": 48, + "ty": 12, + "x": 48, + "y": 12 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 1, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 1, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "VERTICAL", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 4, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 1, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "VERTICAL", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "itemSpacing": 4 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + } + } + }, + { + "id": "I1:1330;83:33578;321:1232", + "name": "Row", + "type": "FRAME", + "parentID": "I1:1330;83:33578;321:1231", + "parentName": "Body", + "childrenNames": [ + { + "id": "I1:1330;83:33578;321:1233", + "name": "Label", + "type": "TEXT", + "parentID": "I1:1330;83:33578;321:1232", + "parentName": "Row" + }, + { + "id": "I1:1330;83:33578;321:1234", + "name": "Menu Shortcut", + "type": "INSTANCE", + "parentID": "I1:1330;83:33578;321:1232", + "parentName": "Row" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_FrameNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 221, + "height": 22, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "AUTO", + "primaryAxisAlignItems": "SPACE_BETWEEN", + "counterAxisAlignItems": "CENTER", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 4, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "AUTO", + "primaryAxisAlignItems": "SPACE_BETWEEN", + "counterAxisAlignItems": "CENTER", + "itemSpacing": 4 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + } + } + }, + { + "id": "I1:1330;83:33578;321:1233", + "name": "Label", + "type": "TEXT", + "parentID": "I1:1330;83:33578;321:1232", + "parentName": "Row", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_TextNode": { + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "ROUND", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 193, + "height": 22, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 1, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 1, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "nonResizableTextMixin": { + "paragraphIndent": 0, + "listSpacing": 0, + "hangingPunctuation": false, + "hangingList": false, + "fontSize": 16, + "fontName": { + "family": "Inter", + "style": "Regular" + }, + "fontWeight": 400, + "textCase": "ORIGINAL", + "textDecoration": "NONE", + "textDecorationStyle": null, + "letterSpacing": { + "value": 0, + "unit": "PERCENT" + }, + "lineHeight": { + "value": 139.9999976158142, + "unit": "PERCENT" + }, + "characters": "Menu Label" + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "textAlignHorizontal": "LEFT", + "textAlignVertical": "TOP", + "textAutoResize": "HEIGHT", + "textTruncation": "DISABLED", + "maxLines": null, + "autoRename": false, + "textStyleId": "S:cebee1b62ea594fa8f97b0b247fd163730736f2a,716:123" + } + }, + { + "id": "I1:1330;83:33578;321:1234", + "name": "Menu Shortcut", + "type": "INSTANCE", + "parentID": "I1:1330;83:33578;321:1232", + "parentName": "Row", + "childrenNames": [ + { + "id": "I1:1330;83:33578;321:1234;321:1466", + "name": "⇧A", + "type": "TEXT", + "parentID": "I1:1330;83:33578;321:1234", + "parentName": "Menu Shortcut" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_InstanceNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": {}, + "strokeCap": "ROUND", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 8 + }, + "rectangleCornerMixin": { + "topLeftRadius": 8, + "topRightRadius": 8, + "bottomLeftRadius": 8, + "bottomRightRadius": 8 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 28, + "height": 16, + "tx": 193, + "ty": 3, + "x": 193, + "y": 3 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "AUTO", + "primaryAxisAlignItems": "MAX", + "counterAxisAlignItems": "CENTER", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 0, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "AUTO", + "primaryAxisAlignItems": "MAX", + "counterAxisAlignItems": "CENTER", + "itemSpacing": 0 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + }, + "variantMixin": { + "variantProperties": null + }, + "button": false + } + }, + { + "id": "I1:1330;83:33578;321:1234;321:1466", + "name": "⇧A", + "type": "TEXT", + "parentID": "I1:1330;83:33578;321:1234", + "parentName": "Menu Shortcut", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_TextNode": { + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 28, + "height": 16, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "nonResizableTextMixin": { + "paragraphIndent": 0, + "listSpacing": 0, + "hangingPunctuation": false, + "hangingList": false, + "fontSize": 16, + "fontName": { + "family": "Inter", + "style": "Regular" + }, + "fontWeight": 400, + "textCase": "ORIGINAL", + "textDecoration": "NONE", + "textDecorationStyle": null, + "letterSpacing": { + "value": 0, + "unit": "PERCENT" + }, + "lineHeight": { + "value": 100, + "unit": "PERCENT" + }, + "characters": "⇧A" + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "textAlignHorizontal": "LEFT", + "textAlignVertical": "TOP", + "textAutoResize": "WIDTH_AND_HEIGHT", + "textTruncation": "DISABLED", + "maxLines": null, + "autoRename": true, + "textStyleId": "S:cd8fb7890d02bb365020e6d4d9dc37dd932bbf3b,715:129" + } + }, + { + "id": "I1:1330;83:33578;321:1235", + "name": "Description", + "type": "TEXT", + "parentID": "I1:1330;83:33578;321:1231", + "parentName": "Body", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_TextNode": { + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.4588235318660736, + "g": 0.4588235318660736, + "b": 0.4588235318660736 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "ROUND", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 221, + "height": 20, + "tx": 0, + "ty": 26, + "x": 0, + "y": 26 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "nonResizableTextMixin": { + "paragraphIndent": 0, + "listSpacing": 0, + "hangingPunctuation": false, + "hangingList": false, + "fontSize": 14, + "fontName": { + "family": "Inter", + "style": "Regular" + }, + "fontWeight": 400, + "textCase": "ORIGINAL", + "textDecoration": "NONE", + "textDecorationStyle": null, + "letterSpacing": { + "value": 0, + "unit": "PERCENT" + }, + "lineHeight": { + "value": 139.9999976158142, + "unit": "PERCENT" + }, + "characters": "Menu description." + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "textAlignHorizontal": "LEFT", + "textAlignVertical": "TOP", + "textAutoResize": "HEIGHT", + "textTruncation": "DISABLED", + "maxLines": null, + "autoRename": false, + "textStyleId": "S:dd16ffab542d022b9a2d78275ed222c2cb4646b4,3017:75" + } + }, + { + "id": "I1:1330;83:33579", + "name": "Menu Item", + "type": "INSTANCE", + "parentID": "I1:1330;83:33577", + "parentName": "Menu Section", + "childrenNames": [ + { + "id": "I1:1330;83:33579;9762:746", + "name": "Star", + "type": "INSTANCE", + "parentID": "I1:1330;83:33579", + "parentName": "Menu Item" + }, + { + "id": "I1:1330;83:33579;321:1231", + "name": "Body", + "type": "FRAME", + "parentID": "I1:1330;83:33579", + "parentName": "Menu Item" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_InstanceNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": {}, + "strokeCap": "ROUND", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 8 + }, + "rectangleCornerMixin": { + "topLeftRadius": 8, + "topRightRadius": 8, + "bottomLeftRadius": 8, + "bottomRightRadius": 8 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 285, + "height": 70, + "tx": 0, + "ty": 70, + "x": 0, + "y": 70 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "layoutWrap": "NO_WRAP", + "paddingLeft": 16, + "paddingRight": 16, + "paddingTop": 12, + "paddingBottom": 12, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "AUTO", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 12, + "counterAxisSpacing": 12, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "paddingLeft": 16, + "paddingRight": 16, + "paddingTop": 12, + "paddingBottom": 12, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "AUTO", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "itemSpacing": 12 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": true, + "guides": [] + } + }, + "variantMixin": { + "variantProperties": { + "State": "Default" + } + }, + "button": false + } + }, + { + "id": "I1:1330;83:33579;9762:746", + "name": "Star", + "type": "INSTANCE", + "parentID": "I1:1330;83:33579", + "parentName": "Menu Item", + "childrenNames": [ + { + "id": "I1:1330;83:33579;9762:746;7758:12316", + "name": "Icon", + "type": "VECTOR", + "parentID": "I1:1330;83:33579;9762:746", + "parentName": "Star" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_InstanceNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 1, + "g": 1, + "b": 1 + }, + "visible": false, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 20, + "height": 20, + "tx": 16, + "ty": 12, + "x": 16, + "y": 12 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "NONE", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 0, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "MIN", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "paddingLeft": 1.666666865348816, + "paddingRight": 1.666667103767395, + "paddingTop": 1.666666865348816, + "paddingBottom": 2.483332633972168, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "CENTER", + "counterAxisAlignItems": "CENTER", + "itemSpacing": 0 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": true, + "guides": [] + } + }, + "variantMixin": { + "variantProperties": { + "Size": "20" + } + }, + "button": false + } + }, + { + "id": "I1:1330;83:33579;9762:746;7758:12316", + "name": "Icon", + "type": "VECTOR", + "parentID": "I1:1330;83:33579;9762:746", + "parentName": "Star", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": true, + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": { + "stroke": { + "strokes": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "visible": true, + "opacity": 1 + } + ], + "strokeWeight": 2, + "strokeAlign": "CENTER", + "strokeJoin": "ROUND" + } + }, + "strokeCap": "ROUND", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 16.66666603088379, + "height": 15.850000381469727, + "tx": 1.666666865348816, + "ty": 1.666666865348816, + "x": 1.666666865348816, + "y": 1.666666865348816 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "SCALE", + "vertical": "SCALE" + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + } + } + }, + { + "id": "I1:1330;83:33579;321:1231", + "name": "Body", + "type": "FRAME", + "parentID": "I1:1330;83:33579", + "parentName": "Menu Item", + "childrenNames": [ + { + "id": "I1:1330;83:33579;321:1232", + "name": "Row", + "type": "FRAME", + "parentID": "I1:1330;83:33579;321:1231", + "parentName": "Body" + }, + { + "id": "I1:1330;83:33579;321:1235", + "name": "Description", + "type": "TEXT", + "parentID": "I1:1330;83:33579;321:1231", + "parentName": "Body" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_FrameNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 221, + "height": 46, + "tx": 48, + "ty": 12, + "x": 48, + "y": 12 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 1, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 1, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "VERTICAL", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 4, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 1, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "VERTICAL", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "itemSpacing": 4 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + } + } + }, + { + "id": "I1:1330;83:33579;321:1232", + "name": "Row", + "type": "FRAME", + "parentID": "I1:1330;83:33579;321:1231", + "parentName": "Body", + "childrenNames": [ + { + "id": "I1:1330;83:33579;321:1233", + "name": "Label", + "type": "TEXT", + "parentID": "I1:1330;83:33579;321:1232", + "parentName": "Row" + }, + { + "id": "I1:1330;83:33579;321:1234", + "name": "Menu Shortcut", + "type": "INSTANCE", + "parentID": "I1:1330;83:33579;321:1232", + "parentName": "Row" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_FrameNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 221, + "height": 22, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "AUTO", + "primaryAxisAlignItems": "SPACE_BETWEEN", + "counterAxisAlignItems": "CENTER", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 4, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "AUTO", + "primaryAxisAlignItems": "SPACE_BETWEEN", + "counterAxisAlignItems": "CENTER", + "itemSpacing": 4 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + } + } + }, + { + "id": "I1:1330;83:33579;321:1233", + "name": "Label", + "type": "TEXT", + "parentID": "I1:1330;83:33579;321:1232", + "parentName": "Row", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_TextNode": { + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "ROUND", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 193, + "height": 22, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 1, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 1, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "nonResizableTextMixin": { + "paragraphIndent": 0, + "listSpacing": 0, + "hangingPunctuation": false, + "hangingList": false, + "fontSize": 16, + "fontName": { + "family": "Inter", + "style": "Regular" + }, + "fontWeight": 400, + "textCase": "ORIGINAL", + "textDecoration": "NONE", + "textDecorationStyle": null, + "letterSpacing": { + "value": 0, + "unit": "PERCENT" + }, + "lineHeight": { + "value": 139.9999976158142, + "unit": "PERCENT" + }, + "characters": "Menu Label" + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "textAlignHorizontal": "LEFT", + "textAlignVertical": "TOP", + "textAutoResize": "HEIGHT", + "textTruncation": "DISABLED", + "maxLines": null, + "autoRename": false, + "textStyleId": "S:cebee1b62ea594fa8f97b0b247fd163730736f2a,716:123" + } + }, + { + "id": "I1:1330;83:33579;321:1234", + "name": "Menu Shortcut", + "type": "INSTANCE", + "parentID": "I1:1330;83:33579;321:1232", + "parentName": "Row", + "childrenNames": [ + { + "id": "I1:1330;83:33579;321:1234;321:1466", + "name": "⇧A", + "type": "TEXT", + "parentID": "I1:1330;83:33579;321:1234", + "parentName": "Menu Shortcut" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_InstanceNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": {}, + "strokeCap": "ROUND", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 8 + }, + "rectangleCornerMixin": { + "topLeftRadius": 8, + "topRightRadius": 8, + "bottomLeftRadius": 8, + "bottomRightRadius": 8 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 28, + "height": 16, + "tx": 193, + "ty": 3, + "x": 193, + "y": 3 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "AUTO", + "primaryAxisAlignItems": "MAX", + "counterAxisAlignItems": "CENTER", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 0, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "AUTO", + "primaryAxisAlignItems": "MAX", + "counterAxisAlignItems": "CENTER", + "itemSpacing": 0 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + }, + "variantMixin": { + "variantProperties": null + }, + "button": false + } + }, + { + "id": "I1:1330;83:33579;321:1234;321:1466", + "name": "⇧A", + "type": "TEXT", + "parentID": "I1:1330;83:33579;321:1234", + "parentName": "Menu Shortcut", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_TextNode": { + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 28, + "height": 16, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "nonResizableTextMixin": { + "paragraphIndent": 0, + "listSpacing": 0, + "hangingPunctuation": false, + "hangingList": false, + "fontSize": 16, + "fontName": { + "family": "Inter", + "style": "Regular" + }, + "fontWeight": 400, + "textCase": "ORIGINAL", + "textDecoration": "NONE", + "textDecorationStyle": null, + "letterSpacing": { + "value": 0, + "unit": "PERCENT" + }, + "lineHeight": { + "value": 100, + "unit": "PERCENT" + }, + "characters": "⇧A" + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "textAlignHorizontal": "LEFT", + "textAlignVertical": "TOP", + "textAutoResize": "WIDTH_AND_HEIGHT", + "textTruncation": "DISABLED", + "maxLines": null, + "autoRename": true, + "textStyleId": "S:cd8fb7890d02bb365020e6d4d9dc37dd932bbf3b,715:129" + } + }, + { + "id": "I1:1330;83:33579;321:1235", + "name": "Description", + "type": "TEXT", + "parentID": "I1:1330;83:33579;321:1231", + "parentName": "Body", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_TextNode": { + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.4588235318660736, + "g": 0.4588235318660736, + "b": 0.4588235318660736 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "ROUND", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 221, + "height": 20, + "tx": 0, + "ty": 26, + "x": 0, + "y": 26 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "nonResizableTextMixin": { + "paragraphIndent": 0, + "listSpacing": 0, + "hangingPunctuation": false, + "hangingList": false, + "fontSize": 14, + "fontName": { + "family": "Inter", + "style": "Regular" + }, + "fontWeight": 400, + "textCase": "ORIGINAL", + "textDecoration": "NONE", + "textDecorationStyle": null, + "letterSpacing": { + "value": 0, + "unit": "PERCENT" + }, + "lineHeight": { + "value": 139.9999976158142, + "unit": "PERCENT" + }, + "characters": "Menu description." + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "textAlignHorizontal": "LEFT", + "textAlignVertical": "TOP", + "textAutoResize": "HEIGHT", + "textTruncation": "DISABLED", + "maxLines": null, + "autoRename": false, + "textStyleId": "S:dd16ffab542d022b9a2d78275ed222c2cb4646b4,3017:75" + } + }, + { + "id": "I1:1330;83:33580", + "name": "Menu Item", + "type": "INSTANCE", + "parentID": "I1:1330;83:33577", + "parentName": "Menu Section", + "childrenNames": [ + { + "id": "I1:1330;83:33580;9762:746", + "name": "Star", + "type": "INSTANCE", + "parentID": "I1:1330;83:33580", + "parentName": "Menu Item" + }, + { + "id": "I1:1330;83:33580;321:1231", + "name": "Body", + "type": "FRAME", + "parentID": "I1:1330;83:33580", + "parentName": "Menu Item" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_InstanceNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": {}, + "strokeCap": "ROUND", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 8 + }, + "rectangleCornerMixin": { + "topLeftRadius": 8, + "topRightRadius": 8, + "bottomLeftRadius": 8, + "bottomRightRadius": 8 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 285, + "height": 70, + "tx": 0, + "ty": 140, + "x": 0, + "y": 140 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "layoutWrap": "NO_WRAP", + "paddingLeft": 16, + "paddingRight": 16, + "paddingTop": 12, + "paddingBottom": 12, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "AUTO", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 12, + "counterAxisSpacing": 12, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "paddingLeft": 16, + "paddingRight": 16, + "paddingTop": 12, + "paddingBottom": 12, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "AUTO", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "itemSpacing": 12 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": true, + "guides": [] + } + }, + "variantMixin": { + "variantProperties": { + "State": "Default" + } + }, + "button": false + } + }, + { + "id": "I1:1330;83:33580;9762:746", + "name": "Star", + "type": "INSTANCE", + "parentID": "I1:1330;83:33580", + "parentName": "Menu Item", + "childrenNames": [ + { + "id": "I1:1330;83:33580;9762:746;7758:12316", + "name": "Icon", + "type": "VECTOR", + "parentID": "I1:1330;83:33580;9762:746", + "parentName": "Star" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_InstanceNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 1, + "g": 1, + "b": 1 + }, + "visible": false, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 20, + "height": 20, + "tx": 16, + "ty": 12, + "x": 16, + "y": 12 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "NONE", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 0, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "MIN", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "paddingLeft": 1.666666865348816, + "paddingRight": 1.666667103767395, + "paddingTop": 1.666666865348816, + "paddingBottom": 2.483332633972168, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "CENTER", + "counterAxisAlignItems": "CENTER", + "itemSpacing": 0 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": true, + "guides": [] + } + }, + "variantMixin": { + "variantProperties": { + "Size": "20" + } + }, + "button": false + } + }, + { + "id": "I1:1330;83:33580;9762:746;7758:12316", + "name": "Icon", + "type": "VECTOR", + "parentID": "I1:1330;83:33580;9762:746", + "parentName": "Star", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": true, + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": { + "stroke": { + "strokes": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "visible": true, + "opacity": 1 + } + ], + "strokeWeight": 2, + "strokeAlign": "CENTER", + "strokeJoin": "ROUND" + } + }, + "strokeCap": "ROUND", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 16.66666603088379, + "height": 15.850000381469727, + "tx": 1.666666865348816, + "ty": 1.666666865348816, + "x": 1.666666865348816, + "y": 1.666666865348816 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "SCALE", + "vertical": "SCALE" + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + } + } + }, + { + "id": "I1:1330;83:33580;321:1231", + "name": "Body", + "type": "FRAME", + "parentID": "I1:1330;83:33580", + "parentName": "Menu Item", + "childrenNames": [ + { + "id": "I1:1330;83:33580;321:1232", + "name": "Row", + "type": "FRAME", + "parentID": "I1:1330;83:33580;321:1231", + "parentName": "Body" + }, + { + "id": "I1:1330;83:33580;321:1235", + "name": "Description", + "type": "TEXT", + "parentID": "I1:1330;83:33580;321:1231", + "parentName": "Body" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_FrameNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 221, + "height": 46, + "tx": 48, + "ty": 12, + "x": 48, + "y": 12 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 1, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 1, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "VERTICAL", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 4, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 1, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "VERTICAL", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "itemSpacing": 4 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + } + } + }, + { + "id": "I1:1330;83:33580;321:1232", + "name": "Row", + "type": "FRAME", + "parentID": "I1:1330;83:33580;321:1231", + "parentName": "Body", + "childrenNames": [ + { + "id": "I1:1330;83:33580;321:1233", + "name": "Label", + "type": "TEXT", + "parentID": "I1:1330;83:33580;321:1232", + "parentName": "Row" + }, + { + "id": "I1:1330;83:33580;321:1234", + "name": "Menu Shortcut", + "type": "INSTANCE", + "parentID": "I1:1330;83:33580;321:1232", + "parentName": "Row" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_FrameNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 221, + "height": 22, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "AUTO", + "primaryAxisAlignItems": "SPACE_BETWEEN", + "counterAxisAlignItems": "CENTER", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 4, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "AUTO", + "primaryAxisAlignItems": "SPACE_BETWEEN", + "counterAxisAlignItems": "CENTER", + "itemSpacing": 4 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + } + } + }, + { + "id": "I1:1330;83:33580;321:1233", + "name": "Label", + "type": "TEXT", + "parentID": "I1:1330;83:33580;321:1232", + "parentName": "Row", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_TextNode": { + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "ROUND", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 193, + "height": 22, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 1, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 1, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "nonResizableTextMixin": { + "paragraphIndent": 0, + "listSpacing": 0, + "hangingPunctuation": false, + "hangingList": false, + "fontSize": 16, + "fontName": { + "family": "Inter", + "style": "Regular" + }, + "fontWeight": 400, + "textCase": "ORIGINAL", + "textDecoration": "NONE", + "textDecorationStyle": null, + "letterSpacing": { + "value": 0, + "unit": "PERCENT" + }, + "lineHeight": { + "value": 139.9999976158142, + "unit": "PERCENT" + }, + "characters": "Menu Label" + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "textAlignHorizontal": "LEFT", + "textAlignVertical": "TOP", + "textAutoResize": "HEIGHT", + "textTruncation": "DISABLED", + "maxLines": null, + "autoRename": false, + "textStyleId": "S:cebee1b62ea594fa8f97b0b247fd163730736f2a,716:123" + } + }, + { + "id": "I1:1330;83:33580;321:1234", + "name": "Menu Shortcut", + "type": "INSTANCE", + "parentID": "I1:1330;83:33580;321:1232", + "parentName": "Row", + "childrenNames": [ + { + "id": "I1:1330;83:33580;321:1234;321:1466", + "name": "⇧A", + "type": "TEXT", + "parentID": "I1:1330;83:33580;321:1234", + "parentName": "Menu Shortcut" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_InstanceNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": {}, + "strokeCap": "ROUND", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 8 + }, + "rectangleCornerMixin": { + "topLeftRadius": 8, + "topRightRadius": 8, + "bottomLeftRadius": 8, + "bottomRightRadius": 8 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 28, + "height": 16, + "tx": 193, + "ty": 3, + "x": 193, + "y": 3 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "AUTO", + "primaryAxisAlignItems": "MAX", + "counterAxisAlignItems": "CENTER", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 0, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "AUTO", + "primaryAxisAlignItems": "MAX", + "counterAxisAlignItems": "CENTER", + "itemSpacing": 0 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + }, + "variantMixin": { + "variantProperties": null + }, + "button": false + } + }, + { + "id": "I1:1330;83:33580;321:1234;321:1466", + "name": "⇧A", + "type": "TEXT", + "parentID": "I1:1330;83:33580;321:1234", + "parentName": "Menu Shortcut", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_TextNode": { + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 28, + "height": 16, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "nonResizableTextMixin": { + "paragraphIndent": 0, + "listSpacing": 0, + "hangingPunctuation": false, + "hangingList": false, + "fontSize": 16, + "fontName": { + "family": "Inter", + "style": "Regular" + }, + "fontWeight": 400, + "textCase": "ORIGINAL", + "textDecoration": "NONE", + "textDecorationStyle": null, + "letterSpacing": { + "value": 0, + "unit": "PERCENT" + }, + "lineHeight": { + "value": 100, + "unit": "PERCENT" + }, + "characters": "⇧A" + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "textAlignHorizontal": "LEFT", + "textAlignVertical": "TOP", + "textAutoResize": "WIDTH_AND_HEIGHT", + "textTruncation": "DISABLED", + "maxLines": null, + "autoRename": true, + "textStyleId": "S:cd8fb7890d02bb365020e6d4d9dc37dd932bbf3b,715:129" + } + }, + { + "id": "I1:1330;83:33580;321:1235", + "name": "Description", + "type": "TEXT", + "parentID": "I1:1330;83:33580;321:1231", + "parentName": "Body", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_TextNode": { + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.4588235318660736, + "g": 0.4588235318660736, + "b": 0.4588235318660736 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "ROUND", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 221, + "height": 20, + "tx": 0, + "ty": 26, + "x": 0, + "y": 26 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "nonResizableTextMixin": { + "paragraphIndent": 0, + "listSpacing": 0, + "hangingPunctuation": false, + "hangingList": false, + "fontSize": 14, + "fontName": { + "family": "Inter", + "style": "Regular" + }, + "fontWeight": 400, + "textCase": "ORIGINAL", + "textDecoration": "NONE", + "textDecorationStyle": null, + "letterSpacing": { + "value": 0, + "unit": "PERCENT" + }, + "lineHeight": { + "value": 139.9999976158142, + "unit": "PERCENT" + }, + "characters": "Menu description." + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "textAlignHorizontal": "LEFT", + "textAlignVertical": "TOP", + "textAutoResize": "HEIGHT", + "textTruncation": "DISABLED", + "maxLines": null, + "autoRename": false, + "textStyleId": "S:dd16ffab542d022b9a2d78275ed222c2cb4646b4,3017:75" + } + }, + { + "id": "I1:1330;9762:724", + "name": "Menu Separator", + "type": "INSTANCE", + "parentID": "1:1330", + "parentName": "Menu", + "childrenNames": [ + { + "id": "I1:1330;9762:724;9762:732", + "name": "Rule", + "type": "RECTANGLE", + "parentID": "I1:1330;9762:724", + "parentName": "Menu Separator" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_InstanceNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 8 + }, + "rectangleCornerMixin": { + "topLeftRadius": 8, + "topRightRadius": 8, + "bottomLeftRadius": 8, + "bottomRightRadius": 8 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 285, + "height": 17, + "tx": 8, + "ty": 289, + "x": 8, + "y": 289 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "VERTICAL", + "layoutWrap": "NO_WRAP", + "paddingLeft": 16, + "paddingRight": 16, + "paddingTop": 8, + "paddingBottom": 8, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "CENTER", + "counterAxisAlignItems": "CENTER", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 0, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "VERTICAL", + "paddingLeft": 16, + "paddingRight": 16, + "paddingTop": 8, + "paddingBottom": 8, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "CENTER", + "counterAxisAlignItems": "CENTER", + "itemSpacing": 0 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + }, + "variantMixin": { + "variantProperties": null + }, + "button": false + } + }, + { + "id": "I1:1330;9762:724;9762:732", + "name": "Rule", + "type": "RECTANGLE", + "parentID": "I1:1330;9762:724", + "parentName": "Menu Separator", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": true, + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.8509804010391235, + "g": 0.8509804010391235, + "b": 0.8509804010391235 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 253, + "height": 1, + "tx": 16, + "ty": 8, + "x": 16, + "y": 8 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + } + } + }, + { + "id": "I1:1330;83:33611", + "name": "Menu Section", + "type": "FRAME", + "parentID": "1:1330", + "parentName": "Menu", + "childrenNames": [ + { + "id": "I1:1330;9762:726", + "name": "Menu Item", + "type": "INSTANCE", + "parentID": "I1:1330;83:33611", + "parentName": "Menu Section" + }, + { + "id": "I1:1330;9762:727", + "name": "Menu Item", + "type": "INSTANCE", + "parentID": "I1:1330;83:33611", + "parentName": "Menu Section" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_FrameNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 285, + "height": 140, + "tx": 8, + "ty": 306, + "x": 8, + "y": 306 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "VERTICAL", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 0, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "VERTICAL", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "itemSpacing": 0 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + } + } + }, + { + "id": "I1:1330;9762:726", + "name": "Menu Item", + "type": "INSTANCE", + "parentID": "I1:1330;83:33611", + "parentName": "Menu Section", + "childrenNames": [ + { + "id": "I1:1330;9762:726;9762:746", + "name": "Star", + "type": "INSTANCE", + "parentID": "I1:1330;9762:726", + "parentName": "Menu Item" + }, + { + "id": "I1:1330;9762:726;321:1231", + "name": "Body", + "type": "FRAME", + "parentID": "I1:1330;9762:726", + "parentName": "Menu Item" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_InstanceNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": {}, + "strokeCap": "ROUND", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 8 + }, + "rectangleCornerMixin": { + "topLeftRadius": 8, + "topRightRadius": 8, + "bottomLeftRadius": 8, + "bottomRightRadius": 8 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 285, + "height": 70, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "layoutWrap": "NO_WRAP", + "paddingLeft": 16, + "paddingRight": 16, + "paddingTop": 12, + "paddingBottom": 12, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "AUTO", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 12, + "counterAxisSpacing": 12, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "paddingLeft": 16, + "paddingRight": 16, + "paddingTop": 12, + "paddingBottom": 12, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "AUTO", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "itemSpacing": 12 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": true, + "guides": [] + } + }, + "variantMixin": { + "variantProperties": { + "State": "Default" + } + }, + "button": false + } + }, + { + "id": "I1:1330;9762:726;9762:746", + "name": "Star", + "type": "INSTANCE", + "parentID": "I1:1330;9762:726", + "parentName": "Menu Item", + "childrenNames": [ + { + "id": "I1:1330;9762:726;9762:746;7758:12316", + "name": "Icon", + "type": "VECTOR", + "parentID": "I1:1330;9762:726;9762:746", + "parentName": "Star" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_InstanceNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 1, + "g": 1, + "b": 1 + }, + "visible": false, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 20, + "height": 20, + "tx": 16, + "ty": 12, + "x": 16, + "y": 12 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "NONE", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 0, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "MIN", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "paddingLeft": 1.666666865348816, + "paddingRight": 1.666667103767395, + "paddingTop": 1.666666865348816, + "paddingBottom": 2.483332633972168, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "CENTER", + "counterAxisAlignItems": "CENTER", + "itemSpacing": 0 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": true, + "guides": [] + } + }, + "variantMixin": { + "variantProperties": { + "Size": "20" + } + }, + "button": false + } + }, + { + "id": "I1:1330;9762:726;9762:746;7758:12316", + "name": "Icon", + "type": "VECTOR", + "parentID": "I1:1330;9762:726;9762:746", + "parentName": "Star", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": true, + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": { + "stroke": { + "strokes": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "visible": true, + "opacity": 1 + } + ], + "strokeWeight": 2, + "strokeAlign": "CENTER", + "strokeJoin": "ROUND" + } + }, + "strokeCap": "ROUND", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 16.66666603088379, + "height": 15.850000381469727, + "tx": 1.666666865348816, + "ty": 1.666666865348816, + "x": 1.666666865348816, + "y": 1.666666865348816 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "SCALE", + "vertical": "SCALE" + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + } + } + }, + { + "id": "I1:1330;9762:726;321:1231", + "name": "Body", + "type": "FRAME", + "parentID": "I1:1330;9762:726", + "parentName": "Menu Item", + "childrenNames": [ + { + "id": "I1:1330;9762:726;321:1232", + "name": "Row", + "type": "FRAME", + "parentID": "I1:1330;9762:726;321:1231", + "parentName": "Body" + }, + { + "id": "I1:1330;9762:726;321:1235", + "name": "Description", + "type": "TEXT", + "parentID": "I1:1330;9762:726;321:1231", + "parentName": "Body" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_FrameNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 221, + "height": 46, + "tx": 48, + "ty": 12, + "x": 48, + "y": 12 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 1, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 1, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "VERTICAL", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 4, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 1, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "VERTICAL", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "itemSpacing": 4 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + } + } + }, + { + "id": "I1:1330;9762:726;321:1232", + "name": "Row", + "type": "FRAME", + "parentID": "I1:1330;9762:726;321:1231", + "parentName": "Body", + "childrenNames": [ + { + "id": "I1:1330;9762:726;321:1233", + "name": "Label", + "type": "TEXT", + "parentID": "I1:1330;9762:726;321:1232", + "parentName": "Row" + }, + { + "id": "I1:1330;9762:726;321:1234", + "name": "Menu Shortcut", + "type": "INSTANCE", + "parentID": "I1:1330;9762:726;321:1232", + "parentName": "Row" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_FrameNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 221, + "height": 22, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "AUTO", + "primaryAxisAlignItems": "SPACE_BETWEEN", + "counterAxisAlignItems": "CENTER", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 4, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "AUTO", + "primaryAxisAlignItems": "SPACE_BETWEEN", + "counterAxisAlignItems": "CENTER", + "itemSpacing": 4 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + } + } + }, + { + "id": "I1:1330;9762:726;321:1233", + "name": "Label", + "type": "TEXT", + "parentID": "I1:1330;9762:726;321:1232", + "parentName": "Row", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_TextNode": { + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "ROUND", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 193, + "height": 22, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 1, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 1, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "nonResizableTextMixin": { + "paragraphIndent": 0, + "listSpacing": 0, + "hangingPunctuation": false, + "hangingList": false, + "fontSize": 16, + "fontName": { + "family": "Inter", + "style": "Regular" + }, + "fontWeight": 400, + "textCase": "ORIGINAL", + "textDecoration": "NONE", + "textDecorationStyle": null, + "letterSpacing": { + "value": 0, + "unit": "PERCENT" + }, + "lineHeight": { + "value": 139.9999976158142, + "unit": "PERCENT" + }, + "characters": "Menu Label" + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "textAlignHorizontal": "LEFT", + "textAlignVertical": "TOP", + "textAutoResize": "HEIGHT", + "textTruncation": "DISABLED", + "maxLines": null, + "autoRename": false, + "textStyleId": "S:cebee1b62ea594fa8f97b0b247fd163730736f2a,716:123" + } + }, + { + "id": "I1:1330;9762:726;321:1234", + "name": "Menu Shortcut", + "type": "INSTANCE", + "parentID": "I1:1330;9762:726;321:1232", + "parentName": "Row", + "childrenNames": [ + { + "id": "I1:1330;9762:726;321:1234;321:1466", + "name": "⇧A", + "type": "TEXT", + "parentID": "I1:1330;9762:726;321:1234", + "parentName": "Menu Shortcut" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_InstanceNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": {}, + "strokeCap": "ROUND", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 8 + }, + "rectangleCornerMixin": { + "topLeftRadius": 8, + "topRightRadius": 8, + "bottomLeftRadius": 8, + "bottomRightRadius": 8 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 28, + "height": 16, + "tx": 193, + "ty": 3, + "x": 193, + "y": 3 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "AUTO", + "primaryAxisAlignItems": "MAX", + "counterAxisAlignItems": "CENTER", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 0, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "AUTO", + "primaryAxisAlignItems": "MAX", + "counterAxisAlignItems": "CENTER", + "itemSpacing": 0 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + }, + "variantMixin": { + "variantProperties": null + }, + "button": false + } + }, + { + "id": "I1:1330;9762:726;321:1234;321:1466", + "name": "⇧A", + "type": "TEXT", + "parentID": "I1:1330;9762:726;321:1234", + "parentName": "Menu Shortcut", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_TextNode": { + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 28, + "height": 16, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "nonResizableTextMixin": { + "paragraphIndent": 0, + "listSpacing": 0, + "hangingPunctuation": false, + "hangingList": false, + "fontSize": 16, + "fontName": { + "family": "Inter", + "style": "Regular" + }, + "fontWeight": 400, + "textCase": "ORIGINAL", + "textDecoration": "NONE", + "textDecorationStyle": null, + "letterSpacing": { + "value": 0, + "unit": "PERCENT" + }, + "lineHeight": { + "value": 100, + "unit": "PERCENT" + }, + "characters": "⇧A" + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "textAlignHorizontal": "LEFT", + "textAlignVertical": "TOP", + "textAutoResize": "WIDTH_AND_HEIGHT", + "textTruncation": "DISABLED", + "maxLines": null, + "autoRename": true, + "textStyleId": "S:cd8fb7890d02bb365020e6d4d9dc37dd932bbf3b,715:129" + } + }, + { + "id": "I1:1330;9762:726;321:1235", + "name": "Description", + "type": "TEXT", + "parentID": "I1:1330;9762:726;321:1231", + "parentName": "Body", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_TextNode": { + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.4588235318660736, + "g": 0.4588235318660736, + "b": 0.4588235318660736 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "ROUND", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 221, + "height": 20, + "tx": 0, + "ty": 26, + "x": 0, + "y": 26 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "nonResizableTextMixin": { + "paragraphIndent": 0, + "listSpacing": 0, + "hangingPunctuation": false, + "hangingList": false, + "fontSize": 14, + "fontName": { + "family": "Inter", + "style": "Regular" + }, + "fontWeight": 400, + "textCase": "ORIGINAL", + "textDecoration": "NONE", + "textDecorationStyle": null, + "letterSpacing": { + "value": 0, + "unit": "PERCENT" + }, + "lineHeight": { + "value": 139.9999976158142, + "unit": "PERCENT" + }, + "characters": "Menu description." + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "textAlignHorizontal": "LEFT", + "textAlignVertical": "TOP", + "textAutoResize": "HEIGHT", + "textTruncation": "DISABLED", + "maxLines": null, + "autoRename": false, + "textStyleId": "S:dd16ffab542d022b9a2d78275ed222c2cb4646b4,3017:75" + } + }, + { + "id": "I1:1330;9762:727", + "name": "Menu Item", + "type": "INSTANCE", + "parentID": "I1:1330;83:33611", + "parentName": "Menu Section", + "childrenNames": [ + { + "id": "I1:1330;9762:727;9762:746", + "name": "Star", + "type": "INSTANCE", + "parentID": "I1:1330;9762:727", + "parentName": "Menu Item" + }, + { + "id": "I1:1330;9762:727;321:1231", + "name": "Body", + "type": "FRAME", + "parentID": "I1:1330;9762:727", + "parentName": "Menu Item" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_InstanceNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": {}, + "strokeCap": "ROUND", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 8 + }, + "rectangleCornerMixin": { + "topLeftRadius": 8, + "topRightRadius": 8, + "bottomLeftRadius": 8, + "bottomRightRadius": 8 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 285, + "height": 70, + "tx": 0, + "ty": 70, + "x": 0, + "y": 70 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "layoutWrap": "NO_WRAP", + "paddingLeft": 16, + "paddingRight": 16, + "paddingTop": 12, + "paddingBottom": 12, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "AUTO", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 12, + "counterAxisSpacing": 12, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "paddingLeft": 16, + "paddingRight": 16, + "paddingTop": 12, + "paddingBottom": 12, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "AUTO", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "itemSpacing": 12 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": true, + "guides": [] + } + }, + "variantMixin": { + "variantProperties": { + "State": "Default" + } + }, + "button": false + } + }, + { + "id": "I1:1330;9762:727;9762:746", + "name": "Star", + "type": "INSTANCE", + "parentID": "I1:1330;9762:727", + "parentName": "Menu Item", + "childrenNames": [ + { + "id": "I1:1330;9762:727;9762:746;7758:12316", + "name": "Icon", + "type": "VECTOR", + "parentID": "I1:1330;9762:727;9762:746", + "parentName": "Star" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_InstanceNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 1, + "g": 1, + "b": 1 + }, + "visible": false, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 20, + "height": 20, + "tx": 16, + "ty": 12, + "x": 16, + "y": 12 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "NONE", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 0, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "MIN", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "paddingLeft": 1.666666865348816, + "paddingRight": 1.666667103767395, + "paddingTop": 1.666666865348816, + "paddingBottom": 2.483332633972168, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "CENTER", + "counterAxisAlignItems": "CENTER", + "itemSpacing": 0 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": true, + "guides": [] + } + }, + "variantMixin": { + "variantProperties": { + "Size": "20" + } + }, + "button": false + } + }, + { + "id": "I1:1330;9762:727;9762:746;7758:12316", + "name": "Icon", + "type": "VECTOR", + "parentID": "I1:1330;9762:727;9762:746", + "parentName": "Star", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": true, + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": { + "stroke": { + "strokes": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "visible": true, + "opacity": 1 + } + ], + "strokeWeight": 2, + "strokeAlign": "CENTER", + "strokeJoin": "ROUND" + } + }, + "strokeCap": "ROUND", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 16.66666603088379, + "height": 15.850000381469727, + "tx": 1.666666865348816, + "ty": 1.666666865348816, + "x": 1.666666865348816, + "y": 1.666666865348816 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "SCALE", + "vertical": "SCALE" + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + } + } + }, + { + "id": "I1:1330;9762:727;321:1231", + "name": "Body", + "type": "FRAME", + "parentID": "I1:1330;9762:727", + "parentName": "Menu Item", + "childrenNames": [ + { + "id": "I1:1330;9762:727;321:1232", + "name": "Row", + "type": "FRAME", + "parentID": "I1:1330;9762:727;321:1231", + "parentName": "Body" + }, + { + "id": "I1:1330;9762:727;321:1235", + "name": "Description", + "type": "TEXT", + "parentID": "I1:1330;9762:727;321:1231", + "parentName": "Body" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_FrameNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 221, + "height": 46, + "tx": 48, + "ty": 12, + "x": 48, + "y": 12 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 1, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 1, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "VERTICAL", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 4, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 1, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "VERTICAL", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "FIXED", + "primaryAxisAlignItems": "MIN", + "counterAxisAlignItems": "MIN", + "itemSpacing": 4 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + } + } + }, + { + "id": "I1:1330;9762:727;321:1232", + "name": "Row", + "type": "FRAME", + "parentID": "I1:1330;9762:727;321:1231", + "parentName": "Body", + "childrenNames": [ + { + "id": "I1:1330;9762:727;321:1233", + "name": "Label", + "type": "TEXT", + "parentID": "I1:1330;9762:727;321:1232", + "parentName": "Row" + }, + { + "id": "I1:1330;9762:727;321:1234", + "name": "Menu Shortcut", + "type": "INSTANCE", + "parentID": "I1:1330;9762:727;321:1232", + "parentName": "Row" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_FrameNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 221, + "height": 22, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "AUTO", + "primaryAxisAlignItems": "SPACE_BETWEEN", + "counterAxisAlignItems": "CENTER", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 4, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "FIXED", + "counterAxisSizingMode": "AUTO", + "primaryAxisAlignItems": "SPACE_BETWEEN", + "counterAxisAlignItems": "CENTER", + "itemSpacing": 4 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + } + } + }, + { + "id": "I1:1330;9762:727;321:1233", + "name": "Label", + "type": "TEXT", + "parentID": "I1:1330;9762:727;321:1232", + "parentName": "Row", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_TextNode": { + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "ROUND", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 193, + "height": 22, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 1, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 1, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "nonResizableTextMixin": { + "paragraphIndent": 0, + "listSpacing": 0, + "hangingPunctuation": false, + "hangingList": false, + "fontSize": 16, + "fontName": { + "family": "Inter", + "style": "Regular" + }, + "fontWeight": 400, + "textCase": "ORIGINAL", + "textDecoration": "NONE", + "textDecorationStyle": null, + "letterSpacing": { + "value": 0, + "unit": "PERCENT" + }, + "lineHeight": { + "value": 139.9999976158142, + "unit": "PERCENT" + }, + "characters": "Menu Label" + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "textAlignHorizontal": "LEFT", + "textAlignVertical": "TOP", + "textAutoResize": "HEIGHT", + "textTruncation": "DISABLED", + "maxLines": null, + "autoRename": false, + "textStyleId": "S:cebee1b62ea594fa8f97b0b247fd163730736f2a,716:123" + } + }, + { + "id": "I1:1330;9762:727;321:1234", + "name": "Menu Shortcut", + "type": "INSTANCE", + "parentID": "I1:1330;9762:727;321:1232", + "parentName": "Row", + "childrenNames": [ + { + "id": "I1:1330;9762:727;321:1234;321:1466", + "name": "⇧A", + "type": "TEXT", + "parentID": "I1:1330;9762:727;321:1234", + "parentName": "Menu Shortcut" + } + ], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_InstanceNode": { + "defaultFrameMixin": { + "baseFrameMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": {}, + "strokeCap": "ROUND", + "strokeMiterLimit": 4 + }, + "cornerMixin": { + "cornerRadius": 8 + }, + "rectangleCornerMixin": { + "topLeftRadius": 8, + "topRightRadius": 8, + "bottomLeftRadius": 8, + "bottomRightRadius": 8 + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 28, + "height": 16, + "tx": 193, + "ty": 3, + "x": 193, + "y": 3 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "layoutWrap": "NO_WRAP", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "AUTO", + "primaryAxisAlignItems": "MAX", + "counterAxisAlignItems": "CENTER", + "counterAxisAlignContent": "AUTO", + "itemSpacing": 0, + "counterAxisSpacing": 0, + "itemReverseZIndex": false, + "strokesIncludedInLayout": false + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "inferredAutoLayout": { + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "autoLayoutMixin": { + "layoutMode": "HORIZONTAL", + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + "paddingBottom": 0, + "primaryAxisSizingMode": "AUTO", + "counterAxisSizingMode": "AUTO", + "primaryAxisAlignItems": "MAX", + "counterAxisAlignItems": "CENTER", + "itemSpacing": 0 + } + }, + "layoutGrids": [], + "gridStyleId": "", + "clipsContent": false, + "guides": [] + } + }, + "variantMixin": { + "variantProperties": null + }, + "button": false + } + }, + { + "id": "I1:1330;9762:727;321:1234;321:1466", + "name": "⇧A", + "type": "TEXT", + "parentID": "I1:1330;9762:727;321:1234", + "parentName": "Menu Shortcut", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_TextNode": { + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 28, + "height": 16, + "tx": 0, + "ty": 0, + "x": 0, + "y": 0 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "nonResizableTextMixin": { + "paragraphIndent": 0, + "listSpacing": 0, + "hangingPunctuation": false, + "hangingList": false, + "fontSize": 16, + "fontName": { + "family": "Inter", + "style": "Regular" + }, + "fontWeight": 400, + "textCase": "ORIGINAL", + "textDecoration": "NONE", + "textDecorationStyle": null, + "letterSpacing": { + "value": 0, + "unit": "PERCENT" + }, + "lineHeight": { + "value": 100, + "unit": "PERCENT" + }, + "characters": "⇧A" + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "textAlignHorizontal": "LEFT", + "textAlignVertical": "TOP", + "textAutoResize": "WIDTH_AND_HEIGHT", + "textTruncation": "DISABLED", + "maxLines": null, + "autoRename": true, + "textStyleId": "S:cd8fb7890d02bb365020e6d4d9dc37dd932bbf3b,715:129" + } + }, + { + "id": "I1:1330;9762:727;321:1235", + "name": "Description", + "type": "TEXT", + "parentID": "I1:1330;9762:727;321:1231", + "parentName": "Body", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": false + }, + "nodeParameters_TextNode": { + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.4588235318660736, + "g": 0.4588235318660736, + "b": 0.4588235318660736 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "ROUND", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 221, + "height": 20, + "tx": 0, + "ty": 26, + "x": 0, + "y": 26 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "nonResizableTextMixin": { + "paragraphIndent": 0, + "listSpacing": 0, + "hangingPunctuation": false, + "hangingList": false, + "fontSize": 14, + "fontName": { + "family": "Inter", + "style": "Regular" + }, + "fontWeight": 400, + "textCase": "ORIGINAL", + "textDecoration": "NONE", + "textDecorationStyle": null, + "letterSpacing": { + "value": 0, + "unit": "PERCENT" + }, + "lineHeight": { + "value": 139.9999976158142, + "unit": "PERCENT" + }, + "characters": "Menu description." + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + }, + "textAlignHorizontal": "LEFT", + "textAlignVertical": "TOP", + "textAutoResize": "HEIGHT", + "textTruncation": "DISABLED", + "maxLines": null, + "autoRename": false, + "textStyleId": "S:dd16ffab542d022b9a2d78275ed222c2cb4646b4,3017:75" + } + } + ], + "visualNode": [ + { + "id": "1:4", + "name": "logo_all 1", + "type": "RECTANGLE", + "parentID": "1:3", + "parentName": "Section 1", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": true, + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 412.69921875, + "height": 117, + "tx": 1423, + "ty": 894, + "x": 1423, + "y": 894 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "MAX", + "vertical": "MAX" + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "aspectRatioLockMixin": { + "targetAspectRatio": { + "x": 1806, + "y": 512 + } + } + } + }, + { + "id": "1:2838", + "name": "bamboo-shoots-7181496_1280 1", + "type": "RECTANGLE", + "parentID": "1:3", + "parentName": "Section 1", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": true, + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 745, + "height": 496, + "tx": 734, + "ty": 114, + "x": 734, + "y": 114 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "cornerMixin": { + "cornerRadius": 60 + }, + "rectangleCornerMixin": { + "topLeftRadius": 60, + "topRightRadius": 60, + "bottomLeftRadius": 60, + "bottomRightRadius": 60 + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "aspectRatioLockMixin": { + "targetAspectRatio": { + "x": 1280, + "y": 852 + } + } + } + }, + { + "id": "4:240", + "name": "Group 1", + "type": "GROUP", + "parentID": "1:3", + "parentName": "Section 1", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": true + }, + "nodeParameters_GroupNode": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 828, + "height": 460, + "tx": 886, + "ty": 434, + "x": 886, + "y": 434 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + } + } + }, + { + "id": "I1:1330;9762:722;9762:732", + "name": "Rule", + "type": "RECTANGLE", + "parentID": "I1:1330;9762:722", + "parentName": "Menu Separator", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": true, + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.8509804010391235, + "g": 0.8509804010391235, + "b": 0.8509804010391235 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 253, + "height": 1, + "tx": 16, + "ty": 8, + "x": 16, + "y": 8 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + } + } + }, + { + "id": "I1:1330;83:33578;9762:746;7758:12316", + "name": "Icon", + "type": "VECTOR", + "parentID": "I1:1330;83:33578;9762:746", + "parentName": "Star", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": true, + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": { + "stroke": { + "strokes": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "visible": true, + "opacity": 1 + } + ], + "strokeWeight": 2, + "strokeAlign": "CENTER", + "strokeJoin": "ROUND" + } + }, + "strokeCap": "ROUND", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 16.66666603088379, + "height": 15.850000381469727, + "tx": 1.666666865348816, + "ty": 1.666666865348816, + "x": 1.666666865348816, + "y": 1.666666865348816 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "SCALE", + "vertical": "SCALE" + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + } + } + }, + { + "id": "I1:1330;83:33579;9762:746;7758:12316", + "name": "Icon", + "type": "VECTOR", + "parentID": "I1:1330;83:33579;9762:746", + "parentName": "Star", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": true, + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": { + "stroke": { + "strokes": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "visible": true, + "opacity": 1 + } + ], + "strokeWeight": 2, + "strokeAlign": "CENTER", + "strokeJoin": "ROUND" + } + }, + "strokeCap": "ROUND", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 16.66666603088379, + "height": 15.850000381469727, + "tx": 1.666666865348816, + "ty": 1.666666865348816, + "x": 1.666666865348816, + "y": 1.666666865348816 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "SCALE", + "vertical": "SCALE" + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + } + } + }, + { + "id": "I1:1330;83:33580;9762:746;7758:12316", + "name": "Icon", + "type": "VECTOR", + "parentID": "I1:1330;83:33580;9762:746", + "parentName": "Star", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": true, + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": { + "stroke": { + "strokes": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "visible": true, + "opacity": 1 + } + ], + "strokeWeight": 2, + "strokeAlign": "CENTER", + "strokeJoin": "ROUND" + } + }, + "strokeCap": "ROUND", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 16.66666603088379, + "height": 15.850000381469727, + "tx": 1.666666865348816, + "ty": 1.666666865348816, + "x": 1.666666865348816, + "y": 1.666666865348816 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "SCALE", + "vertical": "SCALE" + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + } + } + }, + { + "id": "I1:1330;9762:724;9762:732", + "name": "Rule", + "type": "RECTANGLE", + "parentID": "I1:1330;9762:724", + "parentName": "Menu Separator", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": true, + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": { + "fills": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.8509804010391235, + "g": 0.8509804010391235, + "b": 0.8509804010391235 + }, + "visible": true, + "opacity": 1 + } + ] + }, + "minimalStrokesMixin": {}, + "strokeCap": "NONE", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 253, + "height": 1, + "tx": 16, + "ty": 8, + "x": 16, + "y": 8 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "STRETCH", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "rectangleCornerMixin": { + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0 + }, + "individualStrokesMixin": { + "strokeTopWeight": 1, + "strokeBottomWeight": 1, + "strokeLeftWeight": 1, + "strokeRightWeight": 1 + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + } + } + }, + { + "id": "I1:1330;9762:726;9762:746;7758:12316", + "name": "Icon", + "type": "VECTOR", + "parentID": "I1:1330;9762:726;9762:746", + "parentName": "Star", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": true, + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": { + "stroke": { + "strokes": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "visible": true, + "opacity": 1 + } + ], + "strokeWeight": 2, + "strokeAlign": "CENTER", + "strokeJoin": "ROUND" + } + }, + "strokeCap": "ROUND", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 16.66666603088379, + "height": 15.850000381469727, + "tx": 1.666666865348816, + "ty": 1.666666865348816, + "x": 1.666666865348816, + "y": 1.666666865348816 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "SCALE", + "vertical": "SCALE" + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + } + } + }, + { + "id": "I1:1330;9762:727;9762:746;7758:12316", + "name": "Icon", + "type": "VECTOR", + "parentID": "I1:1330;9762:727;9762:746", + "parentName": "Star", + "childrenNames": [], + "nodeParameters_VisualNode": { + "isVisualNode": true, + "defaultShapeMixin": { + "sceneNodeMixin": { + "visible": true, + "locked": false + }, + "blendMixin": { + "minimalBlendMixin": { + "opacity": 1, + "blendMode": "PASS_THROUGH" + }, + "isMask": false + }, + "geometryMixin": { + "minimalFillsMixin": {}, + "minimalStrokesMixin": { + "stroke": { + "strokes": [ + { + "type": "SOLID", + "indexInFigma": 0, + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "visible": true, + "opacity": 1 + } + ], + "strokeWeight": 2, + "strokeAlign": "CENTER", + "strokeJoin": "ROUND" + } + }, + "strokeCap": "ROUND", + "strokeMiterLimit": 4 + }, + "layoutMixin": { + "dimensionAndPositionMixin": { + "width": 16.66666603088379, + "height": 15.850000381469727, + "tx": 1.666666865348816, + "ty": 1.666666865348816, + "x": 1.666666865348816, + "y": 1.666666865348816 + }, + "autoLayoutChildrenMixin": { + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "layoutGrow": 0, + "layoutPositioning": "AUTO" + } + }, + "constraintMixin": { + "horizontal": "SCALE", + "vertical": "SCALE" + }, + "cornerMixin": { + "cornerRadius": 0 + }, + "aspectRatioLockMixin": { + "targetAspectRatio": null + } + } + } + ] +} \ No newline at end of file diff --git a/Assets/UXImporterUnityUiToolKit/Samples~/Section_1.json.meta b/Assets/UXImporterUnityUiToolKit/Samples~/Section_1.json.meta new file mode 100644 index 00000000..bf73cdd1 --- /dev/null +++ b/Assets/UXImporterUnityUiToolKit/Samples~/Section_1.json.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 9144bda9da4042e46b218021a2cb1fc6 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 337438 + packageName: UX Importer for UI Toolkit + packageVersion: 0.1.6 + assetPath: Assets/UXImporterUnityUiToolKit/Samples~/Section_1.json + uploadId: 840350 diff --git a/Assets/UXImporterUnityUiToolKit/Samples~/images.meta b/Assets/UXImporterUnityUiToolKit/Samples~/images.meta new file mode 100644 index 00000000..90a64b82 --- /dev/null +++ b/Assets/UXImporterUnityUiToolKit/Samples~/images.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0c31d5a1c107d84449b8cdf9df232c74 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/UXImporterUnityUiToolKit/Samples~/images/1_2838.png b/Assets/UXImporterUnityUiToolKit/Samples~/images/1_2838.png new file mode 100644 index 00000000..989195cf Binary files /dev/null and b/Assets/UXImporterUnityUiToolKit/Samples~/images/1_2838.png differ diff --git a/Assets/UXImporterUnityUiToolKit/Samples~/images/1_2838.png.meta b/Assets/UXImporterUnityUiToolKit/Samples~/images/1_2838.png.meta new file mode 100644 index 00000000..4dd82a42 --- /dev/null +++ b/Assets/UXImporterUnityUiToolKit/Samples~/images/1_2838.png.meta @@ -0,0 +1,176 @@ +fileFormatVersion: 2 +guid: 73df4b0258a57fb4b855b1c40d10f007 +TextureImporter: + internalIDToNameTable: + - first: + 213: 8296603484774243167 + second: 1_2838_0 + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + 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: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 4 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: iOS + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: 1_2838_0 + rect: + serializedVersion: 2 + x: 0 + y: 0 + width: 745 + height: 496 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: f5b9c3089e4732370800000000000000 + internalID: 8296603484774243167 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: + 1_2838_0: 8296603484774243167 + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 337438 + packageName: UX Importer for UI Toolkit + packageVersion: 0.1.6 + assetPath: Assets/UXImporterUnityUiToolKit/Samples~/images/1_2838.png + uploadId: 840350 diff --git a/Assets/UXImporterUnityUiToolKit/Samples~/images/1_4.png b/Assets/UXImporterUnityUiToolKit/Samples~/images/1_4.png new file mode 100644 index 00000000..38822ee3 Binary files /dev/null and b/Assets/UXImporterUnityUiToolKit/Samples~/images/1_4.png differ diff --git a/Assets/UXImporterUnityUiToolKit/Samples~/images/1_4.png.meta b/Assets/UXImporterUnityUiToolKit/Samples~/images/1_4.png.meta new file mode 100644 index 00000000..35ffd9a4 --- /dev/null +++ b/Assets/UXImporterUnityUiToolKit/Samples~/images/1_4.png.meta @@ -0,0 +1,566 @@ +fileFormatVersion: 2 +guid: 07a2ddb3d22d81941933030cb6104e84 +TextureImporter: + internalIDToNameTable: + - first: + 213: 8701536793483841217 + second: 1_4_0 + - first: + 213: 4028147025107103418 + second: 1_4_1 + - first: + 213: 1696690814626827625 + second: 1_4_2 + - first: + 213: -9177709588812855905 + second: 1_4_3 + - first: + 213: -4406997876285760549 + second: 1_4_4 + - first: + 213: 769531209855814171 + second: 1_4_5 + - first: + 213: 1721244276369096483 + second: 1_4_6 + - first: + 213: -764220898350697420 + second: 1_4_7 + - first: + 213: -1995208836754739062 + second: 1_4_8 + - first: + 213: -919976197542032215 + second: 1_4_9 + - first: + 213: -2493183070980483332 + second: 1_4_10 + - first: + 213: 3001159265717173800 + second: 1_4_11 + - first: + 213: 8503814912390575643 + second: 1_4_12 + - first: + 213: 4375764953586769622 + second: 1_4_13 + - first: + 213: -5658511782964457158 + second: 1_4_14 + - first: + 213: 7118892559982389784 + second: 1_4_15 + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + 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: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 4 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: iOS + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: 1_4_0 + rect: + serializedVersion: 2 + x: 0 + y: 0 + width: 102 + height: 117 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 1ce88976c9112c870800000000000000 + internalID: 8701536793483841217 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: 1_4_1 + rect: + serializedVersion: 2 + x: 120 + y: 45 + width: 33 + height: 44 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: abe2e86906ad6e730800000000000000 + internalID: 4028147025107103418 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: 1_4_2 + rect: + serializedVersion: 2 + x: 240 + y: 44 + width: 33 + height: 45 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 96d00837e4bdb8710800000000000000 + internalID: 1696690814626827625 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: 1_4_3 + rect: + serializedVersion: 2 + x: 342 + y: 45 + width: 34 + height: 44 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: f950d1b21c932a080800000000000000 + internalID: -9177709588812855905 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: 1_4_4 + rect: + serializedVersion: 2 + x: 363 + y: 85 + width: 28 + height: 25 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: bdb1612e7c237d2c0800000000000000 + internalID: -4406997876285760549 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: 1_4_5 + rect: + serializedVersion: 2 + x: 154 + y: 45 + width: 30 + height: 33 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: b1a4807ee8cedaa00800000000000000 + internalID: 769531209855814171 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: 1_4_6 + rect: + serializedVersion: 2 + x: 189 + y: 46 + width: 48 + height: 32 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 32f77a0cc8613e710800000000000000 + internalID: 1721244276369096483 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: 1_4_7 + rect: + serializedVersion: 2 + x: 276 + y: 45 + width: 28 + height: 33 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 43470e75421f465f0800000000000000 + internalID: -764220898350697420 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: 1_4_8 + rect: + serializedVersion: 2 + x: 307 + y: 44 + width: 31 + height: 35 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: a80738052289f44e0800000000000000 + internalID: -1995208836754739062 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: 1_4_9 + rect: + serializedVersion: 2 + x: 379 + y: 34 + width: 34 + height: 47 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 9ac41b7c5869b33f0800000000000000 + internalID: -919976197542032215 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: 1_4_10 + rect: + serializedVersion: 2 + x: 228 + y: 22 + width: 10 + height: 14 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: cf6d036d43f666dd0800000000000000 + internalID: -2493183070980483332 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: 1_4_11 + rect: + serializedVersion: 2 + x: 239 + y: 22 + width: 11 + height: 14 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 82eb17b837246a920800000000000000 + internalID: 3001159265717173800 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: 1_4_12 + rect: + serializedVersion: 2 + x: 252 + y: 22 + width: 12 + height: 14 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: b16b5b09b9e930670800000000000000 + internalID: 8503814912390575643 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: 1_4_13 + rect: + serializedVersion: 2 + x: 267 + y: 22 + width: 13 + height: 14 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 6de942f9a07d9bc30800000000000000 + internalID: 4375764953586769622 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: 1_4_14 + rect: + serializedVersion: 2 + x: 281 + y: 22 + width: 6 + height: 14 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: a319a03738de871b0800000000000000 + internalID: -5658511782964457158 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: 1_4_15 + rect: + serializedVersion: 2 + x: 289 + y: 21 + width: 14 + height: 15 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 81aebe7d0136bc260800000000000000 + internalID: 7118892559982389784 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: + 1_4_0: 8701536793483841217 + 1_4_1: 4028147025107103418 + 1_4_10: -2493183070980483332 + 1_4_11: 3001159265717173800 + 1_4_12: 8503814912390575643 + 1_4_13: 4375764953586769622 + 1_4_14: -5658511782964457158 + 1_4_15: 7118892559982389784 + 1_4_2: 1696690814626827625 + 1_4_3: -9177709588812855905 + 1_4_4: -4406997876285760549 + 1_4_5: 769531209855814171 + 1_4_6: 1721244276369096483 + 1_4_7: -764220898350697420 + 1_4_8: -1995208836754739062 + 1_4_9: -919976197542032215 + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 337438 + packageName: UX Importer for UI Toolkit + packageVersion: 0.1.6 + assetPath: Assets/UXImporterUnityUiToolKit/Samples~/images/1_4.png + uploadId: 840350 diff --git a/Assets/UXImporterUnityUiToolKit/Samples~/images/4_240.png b/Assets/UXImporterUnityUiToolKit/Samples~/images/4_240.png new file mode 100644 index 00000000..3fc28a90 Binary files /dev/null and b/Assets/UXImporterUnityUiToolKit/Samples~/images/4_240.png differ diff --git a/Assets/UXImporterUnityUiToolKit/Samples~/images/4_240.png.meta b/Assets/UXImporterUnityUiToolKit/Samples~/images/4_240.png.meta new file mode 100644 index 00000000..e3686acc --- /dev/null +++ b/Assets/UXImporterUnityUiToolKit/Samples~/images/4_240.png.meta @@ -0,0 +1,176 @@ +fileFormatVersion: 2 +guid: 726af7a59cc5da648b0c0a2e9400116a +TextureImporter: + internalIDToNameTable: + - first: + 213: 484115968324611160 + second: 4_240_0 + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + 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: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 4 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: iOS + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: 4_240_0 + rect: + serializedVersion: 2 + x: 37 + y: 0 + width: 764 + height: 460 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 85c251288ece7b600800000000000000 + internalID: 484115968324611160 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: + 4_240_0: 484115968324611160 + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 337438 + packageName: UX Importer for UI Toolkit + packageVersion: 0.1.6 + assetPath: Assets/UXImporterUnityUiToolKit/Samples~/images/4_240.png + uploadId: 840350 diff --git a/Assets/UXImporterUnityUiToolKit/Samples~/images/I1_1330__83_33578__9762_746__7758_12316.png b/Assets/UXImporterUnityUiToolKit/Samples~/images/I1_1330__83_33578__9762_746__7758_12316.png new file mode 100644 index 00000000..d0682dbd Binary files /dev/null and b/Assets/UXImporterUnityUiToolKit/Samples~/images/I1_1330__83_33578__9762_746__7758_12316.png differ diff --git a/Assets/UXImporterUnityUiToolKit/Samples~/images/I1_1330__83_33578__9762_746__7758_12316.png.meta b/Assets/UXImporterUnityUiToolKit/Samples~/images/I1_1330__83_33578__9762_746__7758_12316.png.meta new file mode 100644 index 00000000..8d4694bf --- /dev/null +++ b/Assets/UXImporterUnityUiToolKit/Samples~/images/I1_1330__83_33578__9762_746__7758_12316.png.meta @@ -0,0 +1,176 @@ +fileFormatVersion: 2 +guid: 09b8e72e7c2b7f04796fb6dea00d3356 +TextureImporter: + internalIDToNameTable: + - first: + 213: 704234606320403687 + second: I1_1330__83_33578__9762_746__7758_12316_0 + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + 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: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 4 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: iOS + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: I1_1330__83_33578__9762_746__7758_12316_0 + rect: + serializedVersion: 2 + x: 0 + y: 0 + width: 19 + height: 18 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 7e4c34ca4a1f5c900800000000000000 + internalID: 704234606320403687 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: + I1_1330__83_33578__9762_746__7758_12316_0: 704234606320403687 + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 337438 + packageName: UX Importer for UI Toolkit + packageVersion: 0.1.6 + assetPath: Assets/UXImporterUnityUiToolKit/Samples~/images/I1_1330__83_33578__9762_746__7758_12316.png + uploadId: 840350 diff --git a/Assets/UXImporterUnityUiToolKit/Samples~/images/I1_1330__83_33579__9762_746__7758_12316.png b/Assets/UXImporterUnityUiToolKit/Samples~/images/I1_1330__83_33579__9762_746__7758_12316.png new file mode 100644 index 00000000..d0682dbd Binary files /dev/null and b/Assets/UXImporterUnityUiToolKit/Samples~/images/I1_1330__83_33579__9762_746__7758_12316.png differ diff --git a/Assets/UXImporterUnityUiToolKit/Samples~/images/I1_1330__83_33579__9762_746__7758_12316.png.meta b/Assets/UXImporterUnityUiToolKit/Samples~/images/I1_1330__83_33579__9762_746__7758_12316.png.meta new file mode 100644 index 00000000..2171075b --- /dev/null +++ b/Assets/UXImporterUnityUiToolKit/Samples~/images/I1_1330__83_33579__9762_746__7758_12316.png.meta @@ -0,0 +1,176 @@ +fileFormatVersion: 2 +guid: 271ce3adde56b234e86c262cd7e2aed0 +TextureImporter: + internalIDToNameTable: + - first: + 213: -3760533499996953978 + second: I1_1330__83_33579__9762_746__7758_12316_0 + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + 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: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 4 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: iOS + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: I1_1330__83_33579__9762_746__7758_12316_0 + rect: + serializedVersion: 2 + x: 0 + y: 0 + width: 19 + height: 18 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 682a9b6b4b6efcbc0800000000000000 + internalID: -3760533499996953978 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: + I1_1330__83_33579__9762_746__7758_12316_0: -3760533499996953978 + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 337438 + packageName: UX Importer for UI Toolkit + packageVersion: 0.1.6 + assetPath: Assets/UXImporterUnityUiToolKit/Samples~/images/I1_1330__83_33579__9762_746__7758_12316.png + uploadId: 840350 diff --git a/Assets/UXImporterUnityUiToolKit/Samples~/images/I1_1330__83_33580__9762_746__7758_12316.png b/Assets/UXImporterUnityUiToolKit/Samples~/images/I1_1330__83_33580__9762_746__7758_12316.png new file mode 100644 index 00000000..d0682dbd Binary files /dev/null and b/Assets/UXImporterUnityUiToolKit/Samples~/images/I1_1330__83_33580__9762_746__7758_12316.png differ diff --git a/Assets/UXImporterUnityUiToolKit/Samples~/images/I1_1330__83_33580__9762_746__7758_12316.png.meta b/Assets/UXImporterUnityUiToolKit/Samples~/images/I1_1330__83_33580__9762_746__7758_12316.png.meta new file mode 100644 index 00000000..44b17821 --- /dev/null +++ b/Assets/UXImporterUnityUiToolKit/Samples~/images/I1_1330__83_33580__9762_746__7758_12316.png.meta @@ -0,0 +1,176 @@ +fileFormatVersion: 2 +guid: 8b7299ebe46957f409013901e5c7a85e +TextureImporter: + internalIDToNameTable: + - first: + 213: 2947235425828576907 + second: I1_1330__83_33580__9762_746__7758_12316_0 + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + 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: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 4 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: iOS + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: I1_1330__83_33580__9762_746__7758_12316_0 + rect: + serializedVersion: 2 + x: 0 + y: 0 + width: 19 + height: 18 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: b8e95f1310fa6e820800000000000000 + internalID: 2947235425828576907 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: + I1_1330__83_33580__9762_746__7758_12316_0: 2947235425828576907 + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 337438 + packageName: UX Importer for UI Toolkit + packageVersion: 0.1.6 + assetPath: Assets/UXImporterUnityUiToolKit/Samples~/images/I1_1330__83_33580__9762_746__7758_12316.png + uploadId: 840350 diff --git a/Assets/UXImporterUnityUiToolKit/Samples~/images/I1_1330__9762_722__9762_732.png b/Assets/UXImporterUnityUiToolKit/Samples~/images/I1_1330__9762_722__9762_732.png new file mode 100644 index 00000000..53b10f0e Binary files /dev/null and b/Assets/UXImporterUnityUiToolKit/Samples~/images/I1_1330__9762_722__9762_732.png differ diff --git a/Assets/UXImporterUnityUiToolKit/Samples~/images/I1_1330__9762_722__9762_732.png.meta b/Assets/UXImporterUnityUiToolKit/Samples~/images/I1_1330__9762_722__9762_732.png.meta new file mode 100644 index 00000000..19d86a9c --- /dev/null +++ b/Assets/UXImporterUnityUiToolKit/Samples~/images/I1_1330__9762_722__9762_732.png.meta @@ -0,0 +1,176 @@ +fileFormatVersion: 2 +guid: 05a53a2351583654d8950b6b0c27e910 +TextureImporter: + internalIDToNameTable: + - first: + 213: 4274827260775113426 + second: I1_1330__9762_722__9762_732_0 + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + 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: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 4 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: iOS + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: I1_1330__9762_722__9762_732_0 + rect: + serializedVersion: 2 + x: 0 + y: 0 + width: 253 + height: 1 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 2d228a2aebc335b30800000000000000 + internalID: 4274827260775113426 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: + I1_1330__9762_722__9762_732_0: 4274827260775113426 + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 337438 + packageName: UX Importer for UI Toolkit + packageVersion: 0.1.6 + assetPath: Assets/UXImporterUnityUiToolKit/Samples~/images/I1_1330__9762_722__9762_732.png + uploadId: 840350 diff --git a/Assets/UXImporterUnityUiToolKit/Samples~/images/I1_1330__9762_724__9762_732.png b/Assets/UXImporterUnityUiToolKit/Samples~/images/I1_1330__9762_724__9762_732.png new file mode 100644 index 00000000..53b10f0e Binary files /dev/null and b/Assets/UXImporterUnityUiToolKit/Samples~/images/I1_1330__9762_724__9762_732.png differ diff --git a/Assets/UXImporterUnityUiToolKit/Samples~/images/I1_1330__9762_724__9762_732.png.meta b/Assets/UXImporterUnityUiToolKit/Samples~/images/I1_1330__9762_724__9762_732.png.meta new file mode 100644 index 00000000..d10b8217 --- /dev/null +++ b/Assets/UXImporterUnityUiToolKit/Samples~/images/I1_1330__9762_724__9762_732.png.meta @@ -0,0 +1,176 @@ +fileFormatVersion: 2 +guid: 82eb76f6bec1e0440a1b8e30f261a7e2 +TextureImporter: + internalIDToNameTable: + - first: + 213: -3417417015144878424 + second: I1_1330__9762_724__9762_732_0 + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + 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: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 4 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: iOS + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: I1_1330__9762_724__9762_732_0 + rect: + serializedVersion: 2 + x: 0 + y: 0 + width: 253 + height: 1 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 8aee9eab455e290d0800000000000000 + internalID: -3417417015144878424 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: + I1_1330__9762_724__9762_732_0: -3417417015144878424 + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 337438 + packageName: UX Importer for UI Toolkit + packageVersion: 0.1.6 + assetPath: Assets/UXImporterUnityUiToolKit/Samples~/images/I1_1330__9762_724__9762_732.png + uploadId: 840350 diff --git a/Assets/UXImporterUnityUiToolKit/Samples~/images/I1_1330__9762_726__9762_746__7758_12316.png b/Assets/UXImporterUnityUiToolKit/Samples~/images/I1_1330__9762_726__9762_746__7758_12316.png new file mode 100644 index 00000000..d0682dbd Binary files /dev/null and b/Assets/UXImporterUnityUiToolKit/Samples~/images/I1_1330__9762_726__9762_746__7758_12316.png differ diff --git a/Assets/UXImporterUnityUiToolKit/Samples~/images/I1_1330__9762_726__9762_746__7758_12316.png.meta b/Assets/UXImporterUnityUiToolKit/Samples~/images/I1_1330__9762_726__9762_746__7758_12316.png.meta new file mode 100644 index 00000000..7ac3db10 --- /dev/null +++ b/Assets/UXImporterUnityUiToolKit/Samples~/images/I1_1330__9762_726__9762_746__7758_12316.png.meta @@ -0,0 +1,176 @@ +fileFormatVersion: 2 +guid: c235b3f6e154e6747a1a0759aea9dc1d +TextureImporter: + internalIDToNameTable: + - first: + 213: -3182997598918515724 + second: I1_1330__9762_726__9762_746__7758_12316_0 + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + 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: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 4 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: iOS + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: I1_1330__9762_726__9762_746__7758_12316_0 + rect: + serializedVersion: 2 + x: 0 + y: 0 + width: 19 + height: 18 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 4f36a8b4c88b3d3d0800000000000000 + internalID: -3182997598918515724 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: + I1_1330__9762_726__9762_746__7758_12316_0: -3182997598918515724 + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 337438 + packageName: UX Importer for UI Toolkit + packageVersion: 0.1.6 + assetPath: Assets/UXImporterUnityUiToolKit/Samples~/images/I1_1330__9762_726__9762_746__7758_12316.png + uploadId: 840350 diff --git a/Assets/UXImporterUnityUiToolKit/Samples~/images/I1_1330__9762_727__9762_746__7758_12316.png b/Assets/UXImporterUnityUiToolKit/Samples~/images/I1_1330__9762_727__9762_746__7758_12316.png new file mode 100644 index 00000000..d0682dbd Binary files /dev/null and b/Assets/UXImporterUnityUiToolKit/Samples~/images/I1_1330__9762_727__9762_746__7758_12316.png differ diff --git a/Assets/UXImporterUnityUiToolKit/Samples~/images/I1_1330__9762_727__9762_746__7758_12316.png.meta b/Assets/UXImporterUnityUiToolKit/Samples~/images/I1_1330__9762_727__9762_746__7758_12316.png.meta new file mode 100644 index 00000000..bca93ba5 --- /dev/null +++ b/Assets/UXImporterUnityUiToolKit/Samples~/images/I1_1330__9762_727__9762_746__7758_12316.png.meta @@ -0,0 +1,176 @@ +fileFormatVersion: 2 +guid: 23e35d2cae0fb9343969156ae3486fee +TextureImporter: + internalIDToNameTable: + - first: + 213: -7639577035823877502 + second: I1_1330__9762_727__9762_746__7758_12316_0 + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + 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: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 4 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: iOS + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: I1_1330__9762_727__9762_746__7758_12316_0 + rect: + serializedVersion: 2 + x: 0 + y: 0 + width: 19 + height: 18 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 2827c718925caf590800000000000000 + internalID: -7639577035823877502 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: + I1_1330__9762_727__9762_746__7758_12316_0: -7639577035823877502 + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 337438 + packageName: UX Importer for UI Toolkit + packageVersion: 0.1.6 + assetPath: Assets/UXImporterUnityUiToolKit/Samples~/images/I1_1330__9762_727__9762_746__7758_12316.png + uploadId: 840350 diff --git a/Assets/UXImporterUnityUiToolKit/Third Party Notices.md b/Assets/UXImporterUnityUiToolKit/Third Party Notices.md new file mode 100644 index 00000000..539e9883 --- /dev/null +++ b/Assets/UXImporterUnityUiToolKit/Third Party Notices.md @@ -0,0 +1,17 @@ +This package contains third-party software components governed by the license(s) indicated below: + +--- + +Component(s): Newtonsoft.Json, JsonDiffPatch.NET +License: MIT License + +MIT License Text: + +Copyright (c) 2007 James Newton-King (for Newtonsoft.Json) +Copyright (c) 2016 William Bishop (for JsonDiffPatch.NET) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Assets/UXImporterUnityUiToolKit/Third Party Notices.md.meta b/Assets/UXImporterUnityUiToolKit/Third Party Notices.md.meta new file mode 100644 index 00000000..5a54bbb0 --- /dev/null +++ b/Assets/UXImporterUnityUiToolKit/Third Party Notices.md.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 0c7110fc190671e48967d4a9ee98e397 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 337438 + packageName: UX Importer for UI Toolkit + packageVersion: 0.1.6 + assetPath: Assets/UXImporterUnityUiToolKit/Third Party Notices.md + uploadId: 840350 diff --git a/Assets/UXImporterUnityUiToolKit/package.json b/Assets/UXImporterUnityUiToolKit/package.json new file mode 100644 index 00000000..b79291af --- /dev/null +++ b/Assets/UXImporterUnityUiToolKit/package.json @@ -0,0 +1,27 @@ +{ + "name": "app.bamboo-up.uximporterforuitoolkit", + "version": "0.1.6", + "displayName": "UX Importer for UI Toolkit", + "description": "Import UX into the Unity UI Toolkit to establish your UI development starting point. Directly loading exported JSON design data streamlines the manual UI construction process.", + "unity": "6000.2", + "unityRelease": "7f1", + "dependencies": { + "com.unity.localization": "1.5.8", + "com.unity.addressables": "2.7.3" + }, + "keywords": [ + "UI Toolkit", + "Unity", + "Editor", + "UX", + "Importer", + "Design", + "Workflow" + ], + "author": { + "name": "BambooUp studio", + "email": "support@bamboo-up.app", + "url": "https://bamboo-up.app/" + }, + "documentationUrl": "https://bamboo-up.app/" +} \ No newline at end of file diff --git a/Assets/UXImporterUnityUiToolKit/package.json.meta b/Assets/UXImporterUnityUiToolKit/package.json.meta new file mode 100644 index 00000000..d2e09c19 --- /dev/null +++ b/Assets/UXImporterUnityUiToolKit/package.json.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 38dddf94641f3ca4bab21ebe510b4be7 +PackageManifestImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 337438 + packageName: UX Importer for UI Toolkit + packageVersion: 0.1.6 + assetPath: Assets/UXImporterUnityUiToolKit/package.json + uploadId: 840350 diff --git a/Packages/app.rive.rive-unity/Demo.meta b/Packages/app.rive.rive-unity/Demo.meta new file mode 100644 index 00000000..4381f4ec --- /dev/null +++ b/Packages/app.rive.rive-unity/Demo.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 34c8d14f407404c2780aed613bcf201b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Demo/RiveFiles.meta b/Packages/app.rive.rive-unity/Demo/RiveFiles.meta new file mode 100644 index 00000000..7dc42553 --- /dev/null +++ b/Packages/app.rive.rive-unity/Demo/RiveFiles.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f0a21ae66d8a641dcb38c6131b9158a4 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Demo/RiveFiles/quick_start_health_bar.riv b/Packages/app.rive.rive-unity/Demo/RiveFiles/quick_start_health_bar.riv new file mode 100644 index 00000000..4eecefdd Binary files /dev/null and b/Packages/app.rive.rive-unity/Demo/RiveFiles/quick_start_health_bar.riv differ diff --git a/Packages/app.rive.rive-unity/Demo/RiveFiles/quick_start_health_bar.riv.meta b/Packages/app.rive.rive-unity/Demo/RiveFiles/quick_start_health_bar.riv.meta new file mode 100644 index 00000000..7ef8ab1a --- /dev/null +++ b/Packages/app.rive.rive-unity/Demo/RiveFiles/quick_start_health_bar.riv.meta @@ -0,0 +1,17 @@ +fileFormatVersion: 2 +guid: 0232d39243ce848a8bc545f81d0bef78 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: 043c4b240e8f94f828b8b81fa436f7f0, type: 3} +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Demo/RiveFiles/quick_start_health_bar.riv + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Editor.meta b/Packages/app.rive.rive-unity/Editor.meta new file mode 100644 index 00000000..e793805d --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 90a80d7fd4f5a41eda0b319cbf0dd947 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Editor/AssetEditor.cs b/Packages/app.rive.rive-unity/Editor/AssetEditor.cs new file mode 100644 index 00000000..ffd275f4 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/AssetEditor.cs @@ -0,0 +1,632 @@ +using UnityEngine; +using UnityEngine.Rendering; +using UnityEditor; +using UnityEngine.UIElements; +using UnityEditor.UIElements; +using System.Linq; +using Rive.EditorTools; +using System; + +namespace Rive +{ + [CustomEditor(typeof(Asset))] + public class AssetEditor : Editor + { + File m_file; + private Artboard m_artboard; + private StateMachine m_stateMachine; + private double m_lastTime = 0.0; + public override bool HasPreviewGUI() => true; + + public override bool RequiresConstantRepaint() + { + return true; + } + + private enum AssetReferenceType + { + Embedded = 0, + Referenced = 1 + } + + + + public override VisualElement CreateInspectorGUI() + { + var root = new VisualElement(); + var riveAsset = (Asset)target; + + // File Assets Section + var embeddedFoldout = new Foldout { text = "File Assets", value = false }; + root.Add(embeddedFoldout); + + foreach (var embeddedAsset in riveAsset.EmbeddedAssets) + { + var assetContainer = new VisualElement(); + assetContainer.style.paddingBottom = 30; + + embeddedFoldout.Add(assetContainer); + + // Asset Type + var enumField = new EnumField("Type:", embeddedAsset.AssetType); + enumField.SetEnabled(false); + assetContainer.Add(enumField); + + // Asset Name + var nameField = new TextField("Name:") { value = embeddedAsset.Name }; + // For text fields, make them readonly instead of using SetEnabled(false) to allow for copying the text + StyleAsReadonly(nameField); + nameField.isReadOnly = true; + assetContainer.Add(nameField); + + // Asset ID + var idField = new TextField("ID:") { value = embeddedAsset.Id.ToString() }; + StyleAsReadonly(idField); + idField.isReadOnly = true; + assetContainer.Add(idField); + + // Asset Reference Type + var referenceType = embeddedAsset.InBandBytesSize > 0 ? AssetReferenceType.Embedded : AssetReferenceType.Referenced; + var referenceTypeField = new EnumField("Reference Type:", referenceType); + referenceTypeField.SetEnabled(false); + assetContainer.Add(referenceTypeField); + + // Asset Data + if (referenceType == AssetReferenceType.Embedded) + { + var embeddedField = new TextField("Embedded Size:") + { + value = FormatBytes(embeddedAsset.InBandBytesSize), + tooltip = "The size of the asset data embedded in the Rive file." + }; + StyleAsReadonly(embeddedField); + embeddedField.isReadOnly = true; + assetContainer.Add(embeddedField); + } + else + { + var assetField = new ObjectField("Referenced Asset") + { + objectType = GetAssetType(embeddedAsset.AssetType), + value = embeddedAsset.OutOfBandAsset, + }; + + // Allow referenced assets to be updated in the editor + assetField.RegisterValueChangedCallback(evt => + { + + var newValue = evt.newValue as OutOfBandAsset; + + Asset asset = target as Asset; + + if (asset == null) + { + return; + } + + Undo.RecordObject(this, "Updated Referenced Asset"); + + AssetImporter.SetOobAssetReference((Asset)target, embeddedAsset.Id, newValue); + + }); + assetContainer.Add(assetField); + } + } + + + // Artboard Metadata + if (riveAsset.EditorOnlyMetadata != null && riveAsset.EditorOnlyMetadata.Artboards.Count > 0) + { + var contentsFoldout = new Foldout { text = "Artboard Metadata", value = false }; + root.Add(contentsFoldout); + + for (int i = 0; i < riveAsset.EditorOnlyMetadata.Artboards.Count; i++) + { + bool isDefaultArtboard = i == 0; + var artboard = riveAsset.EditorOnlyMetadata.Artboards[i]; + + // Create a foldout for each artboard + string artboardLabel = artboard.Name + (isDefaultArtboard ? " (Default)" : ""); + var artboardFoldout = new Foldout { text = artboardLabel, value = false }; + artboardFoldout.style.paddingLeft = 8; + artboardFoldout.style.paddingRight = 8; + contentsFoldout.Add(artboardFoldout); + + var artboardContainer = new VisualElement(); + artboardFoldout.Add(artboardContainer); + + + AddCopyToClipboardMenu(artboardFoldout, artboard.Name, "Copy Artboard Name"); + + + // Artboard Size + var sizeContainer = new VisualElement(); + sizeContainer.style.flexDirection = FlexDirection.Row; + sizeContainer.style.marginLeft = 15; + sizeContainer.style.marginTop = 5; + artboardContainer.Add(sizeContainer); + + var sizeLabel = new Label("Size:"); + sizeLabel.style.marginRight = 8; + sizeContainer.Add(sizeLabel); + + var sizeValueLabel = new Label($"{artboard.Width} x {artboard.Height}"); + sizeContainer.Add(sizeValueLabel); + + + + // State Machines Container + var stateMachinesContainer = new VisualElement(); + stateMachinesContainer.style.marginLeft = 15; + stateMachinesContainer.style.marginTop = 10; + artboardContainer.Add(stateMachinesContainer); + + foreach (var stateMachine in artboard.StateMachines) + { + var smContainer = new VisualElement(); + smContainer.style.marginBottom = 10; + + // State Machine Header + var smHeader = new VisualElement(); + smHeader.style.flexDirection = FlexDirection.Row; + smHeader.style.alignItems = Align.Center; + smContainer.Add(smHeader); + + var smLabel = new Label("State Machine:"); + smLabel.style.marginRight = 8; + smHeader.Add(smLabel); + + var smNameField = new TextField(); + smNameField.value = stateMachine.Name; + StyleAsReadonly(smNameField); + smNameField.isReadOnly = true; + smNameField.SetEnabled(true); + smNameField.style.flexGrow = 1; + smHeader.Add(smNameField); + + // Inputs + if (stateMachine.Inputs.Count > 0) + { + var inputsContainer = new VisualElement(); + inputsContainer.style.marginLeft = 15; + inputsContainer.style.marginTop = 5; + smContainer.Add(inputsContainer); + + var inputsLabel = new Label("Inputs:"); + inputsLabel.style.unityFontStyleAndWeight = FontStyle.Bold; + inputsLabel.style.marginBottom = 5; + inputsContainer.Add(inputsLabel); + + foreach (var input in stateMachine.Inputs) + { + var inputContainer = new VisualElement(); + inputContainer.style.flexDirection = FlexDirection.Row; + inputContainer.style.alignItems = Align.Center; + inputContainer.style.marginBottom = 2; + + var typeLabel = new Label(input.Type); + typeLabel.style.marginRight = 8; + typeLabel.style.width = 60; + + var nameField = new TextField(); + nameField.value = input.Name; + StyleAsReadonly(nameField); + nameField.isReadOnly = true; + nameField.SetEnabled(true); + nameField.style.flexGrow = 1; + + inputContainer.Add(typeLabel); + inputContainer.Add(nameField); + inputsContainer.Add(inputContainer); + } + } + + stateMachinesContainer.Add(smContainer); + } + + if (artboard.DefaultViewModel != null && !String.IsNullOrEmpty(artboard.DefaultViewModel.Name)) + { + var defaultVMContainer = new VisualElement(); + defaultVMContainer.style.flexDirection = FlexDirection.Row; + defaultVMContainer.style.alignItems = Align.Center; + + defaultVMContainer.style.marginLeft = 15; + defaultVMContainer.style.marginBottom = 5; + artboardContainer.Add(defaultVMContainer); + + var defaultVMLabel = new Label("Default View Model:"); + defaultVMLabel.style.marginRight = 8; + defaultVMContainer.Add(defaultVMLabel); + + var defaultVMNameField = new TextField(); + defaultVMNameField.value = artboard.DefaultViewModel.Name; + StyleAsReadonly(defaultVMNameField); + defaultVMNameField.isReadOnly = true; + defaultVMNameField.SetEnabled(true); + defaultVMNameField.style.flexGrow = 1; + defaultVMContainer.Add(defaultVMNameField); + } + } + } + + // View Models Section + + if (riveAsset.EditorOnlyMetadata != null && riveAsset.EditorOnlyMetadata.ViewModels.Count > 0) + { + var viewModelsFoldout = new Foldout { text = "View Models", value = false }; + + root.Add(viewModelsFoldout); + + foreach (var viewModel in riveAsset.EditorOnlyMetadata.ViewModels) + { + var viewModelFoldout = new Foldout { text = viewModel.Name, value = false }; + viewModelFoldout.style.paddingLeft = 8; + viewModelFoldout.style.paddingRight = 8; + viewModelsFoldout.Add(viewModelFoldout); + AddCopyToClipboardMenu(viewModelFoldout, viewModel.Name, "Copy View Model Name"); + + // Properties + if (viewModel.Properties.Count > 0) + { + var propertiesContainer = new VisualElement(); + propertiesContainer.style.marginLeft = 15; + propertiesContainer.style.marginTop = 5; + viewModelFoldout.Add(propertiesContainer); + + var propertiesLabel = new Label("Properties:"); + propertiesLabel.style.unityFontStyleAndWeight = FontStyle.Bold; + propertiesLabel.style.marginBottom = 5; + propertiesContainer.Add(propertiesLabel); + + foreach (var property in viewModel.Properties) + { + var propertyContainer = new VisualElement(); + propertyContainer.style.flexDirection = FlexDirection.Row; + propertyContainer.style.alignItems = Align.Center; + propertyContainer.style.marginBottom = 2; + + var typeLabel = new Label(GetViewModelPropertyTypeLabel(property)); + typeLabel.style.marginRight = 8; + typeLabel.style.minWidth = 60; + + var nameField = new TextField(); + nameField.value = property.Name; + StyleAsReadonly(nameField); + nameField.isReadOnly = true; + nameField.SetEnabled(true); + nameField.style.flexGrow = 1; + + propertyContainer.Add(typeLabel); + propertyContainer.Add(nameField); + propertiesContainer.Add(propertyContainer); + } + } + + // Instance Names + if (viewModel.InstanceNames.Count > 0) + { + var instancesContainer = new VisualElement(); + instancesContainer.style.marginLeft = 15; + instancesContainer.style.marginTop = 10; + instancesContainer.style.marginBottom = 10; + viewModelFoldout.Add(instancesContainer); + + var instancesLabel = new Label("Instances:"); + instancesLabel.style.unityFontStyleAndWeight = FontStyle.Bold; + instancesLabel.style.marginBottom = 5; + instancesContainer.Add(instancesLabel); + + foreach (var instanceName in viewModel.InstanceNames) + { + var instanceField = new TextField(); + instanceField.value = instanceName; + StyleAsReadonly(instanceField); + instanceField.isReadOnly = true; + instanceField.SetEnabled(true); + instancesContainer.Add(instanceField); + } + } + } + } + + + // Enums Section + + if (riveAsset.EditorOnlyMetadata.Enums.Count > 0) + { + var enumsFoldout = new Foldout { text = "Enums", value = false }; + root.Add(enumsFoldout); + + foreach (var enumData in riveAsset.EditorOnlyMetadata.Enums) + { + // Create a foldout for each enum type + var enumFoldout = new Foldout { text = enumData.Name, value = false }; + enumFoldout.style.paddingLeft = 8; + enumFoldout.style.paddingRight = 8; + enumsFoldout.Add(enumFoldout); + AddCopyToClipboardMenu(enumFoldout, enumData.Name, "Copy Enum Name"); + + // Values + var valuesContainer = new VisualElement(); + valuesContainer.style.marginLeft = 15; + valuesContainer.style.marginTop = 5; + valuesContainer.style.marginBottom = 10; + enumFoldout.Add(valuesContainer); + + var valuesLabel = new Label("Values:"); + valuesLabel.style.unityFontStyleAndWeight = FontStyle.Bold; + valuesLabel.style.marginBottom = 5; + valuesContainer.Add(valuesLabel); + + foreach (var value in enumData.Values) + { + var valueField = new TextField(); + valueField.value = value; + StyleAsReadonly(valueField); + valueField.isReadOnly = true; + valueField.SetEnabled(true); + valuesContainer.Add(valueField); + } + } + } + + + + return root; + } + + + private void AddCopyToClipboardMenu(Foldout foldout, string textToCopy, string itemLabel = null) + { + if (string.IsNullOrEmpty(textToCopy)) + { + return; + } + + itemLabel = itemLabel ?? $"Copy \"{foldout.text}\""; + + foldout.AddManipulator(new ContextualMenuManipulator((ContextualMenuPopulateEvent evt) => + { + evt.menu.AppendAction(itemLabel, (action) => + { + GUIUtility.systemCopyBuffer = textToCopy; + }); + })); + + } + + + + private string GetViewModelPropertyTypeLabel(FileMetadata.ViewModelPropertyMetadata property) + { + // We want to display the type of the property, and if it's a ViewModel type, we also want to display the nested ViewModel name. + if (property.Type == ViewModelDataType.ViewModel) + { + return $"{property.Type.ToString()} ({property.NestedViewModelName})"; + } + else if (property.Type == ViewModelDataType.Enum && !string.IsNullOrEmpty(property.EnumTypeName)) + { + return $"{property.Type.ToString()} ({property.EnumTypeName})"; + } + + return $"{property.Type.ToString()}"; + } + + private void StyleAsReadonly(VisualElement element) + { + element.style.opacity = 0.5f; + } + + private System.Type GetAssetType(EmbeddedAssetType assetType) + { + switch (assetType) + { + case EmbeddedAssetType.Font: + return typeof(FontOutOfBandAsset); + case EmbeddedAssetType.Image: + return typeof(ImageOutOfBandAsset); + case EmbeddedAssetType.Audio: + return typeof(AudioOutOfBandAsset); + default: + return typeof(System.Object); + } + } + + + public override Texture2D RenderStaticPreview( + string assetPath, + UnityEngine.Object[] subAssets, + int width, + int height + ) + { + RenderTexture prev = RenderTexture.active; + var rect = new Rect(0, 0, width, height); + RenderTexture rt = Render(rect, true); + + if (rt != null) + { + RenderTexture sourceForRead = rt; + RenderTexture temp = null; + + // Static preview: use the runtime decode material (Rive/UI/Default) in Linear color space. + // This decodes gamma to linear, which works correctly with ReadPixels→Texture2D path. + // We DON'T use the pass-through shader here because the blit+ReadPixels seems to cause issues, and leads to nothing rendering for the static preview. + // TODO: Remove this once we have a proper way to display the texture in Linear color space. + if (Rive.TextureHelper.ProjectNeedsColorSpaceFix) + { + var mat = Rive.TextureHelper.GammaToLinearUIMaterial; + if (mat != null) + { + temp = RenderTexture.GetTemporary(rt.width, rt.height, 0, RenderTextureFormat.ARGB32); + Graphics.Blit(rt, temp, mat); + sourceForRead = temp; + } + } + + RenderTexture.active = sourceForRead; + + Texture2D tex = new Texture2D(width, height); + tex.ReadPixels(rect, 0, 0); + tex.Apply(true); + + RenderTexture.active = prev; + if (temp != null) + { + RenderTexture.ReleaseTemporary(temp); + } + RenderTexture.ReleaseTemporary(rt); + return tex; + } + return null; + } + + RenderTexture Render(Rect rect, bool isStatic = false) + { + int width = (int)rect.width; + int height = (int)rect.height; + + var descriptor = Rive.TextureHelper.Descriptor(width, height); + RenderTexture rt = RenderTexture.GetTemporary(descriptor); + + var cmb = new CommandBuffer(); + + cmb.SetRenderTarget(rt); + + if (m_file == null) + { + var riveAsset = (Rive.Asset)target; + m_file = Rive.File.Load(riveAsset); + m_artboard = m_file?.Artboard(0); + m_stateMachine = m_artboard?.StateMachine(); + } + + if (m_artboard != null) + { + var rq = new RenderQueue( + UnityEngine.SystemInfo.graphicsDeviceType == GraphicsDeviceType.Metal + ? null + : rt + ); + var renderer = rq.Renderer(); + renderer.Align(Fit.Contain, Alignment.Center, m_artboard); + renderer.Draw(m_artboard); + renderer.AddToCommandBuffer(cmb); + if (!isStatic) + { + var now = EditorApplication.timeSinceStartup; + double time = now - m_lastTime; + m_stateMachine?.Advance((float)(now - m_lastTime)); + m_lastTime = now; + } + else + { + m_stateMachine?.Advance(0.0f); + } + } + var prev = RenderTexture.active; + Graphics.ExecuteCommandBuffer(cmb); + GL.InvalidateState(); + cmb.Clear(); + + if (isStatic && FlipY()) + { + RenderTexture temp = RenderTexture.GetTemporary( + width, + height, + 0, + RenderTextureFormat.Default, + RenderTextureReadWrite.Default + ); + temp.Create(); + + Graphics.Blit(rt, temp, new Vector2(1, -1), new Vector2(0, 1)); + RenderTexture.ReleaseTemporary(rt); + rt = temp; + } + + // Caller releases the temporary RT + return rt; + } + + public override void OnPreviewGUI(Rect rect, GUIStyle background) + { + if (Event.current.type == EventType.Repaint) + { + RenderTexture rt = Render(rect); + + var drawRect = FlipY() + ? new Rect(rect.x, rect.y + rect.height, rect.width, -rect.height) + : rect; + + // Live preview: use a simple pass-through shader in Linear color space. + // Rive outputs gamma values, and it looks like EditorGUI.DrawPreviewTexture expects sRGB input. + // We DON'T use the decode material here because it would decode to linear, causing burnt/dark colors. + // The pass-through shader (Hidden/Rive/Editor/SRGBEncodePreview) just returns the texture unchanged. + // TODO: Remove this once we have a proper way to display the texture in Linear color space. + var mat = (Rive.TextureHelper.ProjectNeedsColorSpaceFix ? GetEncodePreviewMaterial() : null); + UnityEditor.EditorGUI.DrawPreviewTexture(drawRect, rt, mat); + RenderTexture.ReleaseTemporary(rt); + } + } + + private static Material s_encodePreviewMaterial; + private static Material GetEncodePreviewMaterial() + { + if (s_encodePreviewMaterial != null) return s_encodePreviewMaterial; + var shader = Shader.Find("Hidden/Rive/Editor/SRGBEncodePreview"); + if (shader == null) return null; + s_encodePreviewMaterial = new Material(shader) + { + name = "Rive_Editor_SRGBEncodePreview", + hideFlags = HideFlags.HideAndDontSave + }; + return s_encodePreviewMaterial; + } + + private void UnloadPreview() + { + m_stateMachine = null; + m_artboard = null; + if (m_file != null) + { + m_file.Dispose(); + m_file = null; + } + } + + public void OnDisable() + { + var riveAsset = (Rive.Asset)target; + UnloadPreview(); + } + + private static bool FlipY() + { + switch (UnityEngine.SystemInfo.graphicsDeviceType) + { + case GraphicsDeviceType.Metal: + case GraphicsDeviceType.Vulkan: + case GraphicsDeviceType.Direct3D11: + return true; + default: + return false; + } + } + + static string FormatBytes(uint byteCount) + { + string[] sizes = { "B", "KB", "MB", "GB", "TB" }; + int order = 0; + while (byteCount >= 1024 && order < sizes.Length - 1) + { + order++; + byteCount /= 1024; + } + + // Adjust the format string to your preferences. For example "{0:0.#}{1}" would + // show a single decimal place, and no space. + return string.Format("{0:0.##} {1}", byteCount, sizes[order]); + } + } +} diff --git a/Packages/app.rive.rive-unity/Editor/AssetEditor.cs.meta b/Packages/app.rive.rive-unity/Editor/AssetEditor.cs.meta new file mode 100644 index 00000000..ba44cbdf --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/AssetEditor.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: c0c0086d5bb044ad3ad1fd3d80d1a5e4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Editor/AssetEditor.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Editor/AssetImporter.cs b/Packages/app.rive.rive-unity/Editor/AssetImporter.cs new file mode 100644 index 00000000..a6c7a963 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/AssetImporter.cs @@ -0,0 +1,308 @@ +using UnityEngine; +using System.Collections.Generic; +using UnityEditor.AssetImporters; +using UnityEditor; +using System; +using System.Linq; +using Rive.Utils; + +namespace Rive +{ + [ScriptedImporter(version: 2, ext: "riv")] + public class AssetImporter : ScriptedImporter + { + + [System.Serializable] + private class OobReferenceData + { + /// + /// ID of the referenced asset in Rive + /// + public uint assetIdInRiv; + + /// + /// GUID of the referenced asset in Unity + /// + public string assetGuid; + } + + [System.Serializable] + private class UserDataContainer + { + /// + /// List of stored OOB references to override OutOfBandAsset references on the generated Asset + /// + public List oobReferences = new List(); + + + /// + /// Remove a stored OOB reference from the list + /// + /// ID of the referenced asset in Rive + public void RemoveOobReference(uint assetId) + { + oobReferences.RemoveAll(r => r.assetIdInRiv == assetId); + } + + /// + /// Add a new OOB reference to the list + /// + /// ID of the referenced asset in Rive + /// GUID of the referenced asset in Unity + public void AddOobReference(uint assetId, string assetGuid) + { + + // Remove any existing reference with the same ID + RemoveOobReference(assetId); + + oobReferences.Add(new OobReferenceData + { + assetIdInRiv = assetId, + assetGuid = assetGuid + }); + } + } + + delegate void Callback(); + + void AfterUpdate(Callback call) + { + void callback() + { + if (!EditorApplication.isCompiling && !EditorApplication.isUpdating) + { + call(); + EditorApplication.update -= callback; + } + } + + EditorApplication.update += callback; + } + + public static string[] fontExtensions = FontOobAssetExtensions.FontExtensions; + public static string[] imageExtensions = ImageOobAssetExtensions.ImageExtensions; + public static string[] audioExtensions = AudioOobAssetExtensions.AudioExtensions; + + private EmbeddedAssetDataLoader embeddedAssetDataLoader = new EmbeddedAssetDataLoader(); + + + + public override void OnImportAsset(AssetImportContext ctx) + { + bool isFirstImport = importSettingsMissing; + var assetPath = ctx.assetPath; + byte[] bytes = System.IO.File.ReadAllBytes(assetPath); + + // Deserialize stored references from userData + // The Asset class is recreated on every import, so changes made to the Asset class will be lost on reimport. To get around this, we store reference information about oob asset overrides in the importer userData to keep them between imports. + // This lets us keep track of the custom assets provided by the user. The userData is stored in the meta file. + var userDataContainer = string.IsNullOrEmpty(userData) + ? new UserDataContainer() + : JsonUtility.FromJson(userData); + + int oobAssetCount = 0; + + List assets = new List(); + + foreach (var embeddedAsset in embeddedAssetDataLoader.LoadEmbeddedAssetDataFromRiveFileBytes(bytes)) + { + // Check if we have a stored reference + var storedReference = userDataContainer.oobReferences + .FirstOrDefault(r => r.assetIdInRiv == embeddedAsset.Id); + + // If the asset at the index is not a referenced asset, then we clear the stored reference as we only want to store references to oob assets set to `Referenced` + if (embeddedAsset.InBandBytesSize > 0) + { + userDataContainer.RemoveOobReference(embeddedAsset.Id); + + storedReference = null; + } + + if (storedReference != null) + { + var oobAssetPath = AssetDatabase.GUIDToAssetPath(storedReference.assetGuid); + if (!string.IsNullOrEmpty(assetPath)) + { + var referencedAsset = AssetDatabase.LoadAssetAtPath(oobAssetPath); + if (referencedAsset != null) + { + embeddedAsset.OutOfBandAsset = referencedAsset; + ctx.DependsOnArtifact(oobAssetPath); + } + } + } + else + { + var basePath = System.IO.Path.GetDirectoryName(assetPath); + + switch (embeddedAsset.AssetType) + { + case EmbeddedAssetType.Font: + HandleAsset(embeddedAsset, basePath, fontExtensions, typeof(FontOutOfBandAsset), ctx, ref oobAssetCount); + break; + case EmbeddedAssetType.Image: + HandleAsset(embeddedAsset, basePath, imageExtensions, typeof(ImageOutOfBandAsset), ctx, ref oobAssetCount); + break; + case EmbeddedAssetType.Audio: + HandleAsset(embeddedAsset, basePath, audioExtensions, typeof(AudioOutOfBandAsset), ctx, ref oobAssetCount); + break; + } + } + + assets.Add(embeddedAsset); + } + + var file = Asset.Create(bytes, assets.ToArray()); + + ctx.AddObjectToAsset("rive", file); + + if (oobAssetCount != 0 && isFirstImport) + { + // The file seems to have out of band assets, try to resolve + // them. We only do this on first import so the user can go + // manually change auto-detected OOB assets to use a different + // importer if they want. + AfterUpdate(() => + { + ImportOutOfBandAssets(assetPath); + }); + } + ctx.SetMainObject(file); + + } + + internal static void SetOobAssetReference(Asset targetRiveAsset, uint assetId, OutOfBandAsset oobAsset) + { + var importer = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(targetRiveAsset)) as AssetImporter; + + if (importer == null) + { + DebugLogger.Instance.LogError("Could not get AssetImporter for target Rive asset"); + return; + } + + string userDataToApply = importer.userData; + + + var container = string.IsNullOrEmpty(userDataToApply) + ? new UserDataContainer() + : JsonUtility.FromJson(userDataToApply); + + container.RemoveOobReference(assetId); + + // If the asset is null, we still want to store the reference as the user might have set it to null on purpose. + // If we don't store it, the importer will try to auto-detect a matching asset in the directory on the next import. + var path = oobAsset != null ? AssetDatabase.GetAssetPath(oobAsset) : null; + var guid = path != null ? AssetDatabase.AssetPathToGUID(path) : null; + + container.AddOobReference(assetId, guid); + + // Clear out any items in the list that are no longer valid (e.g assetIdInRiv is no longer in the file) + container.oobReferences.RemoveAll(r => targetRiveAsset.EmbeddedAssets.All(e => e.Id != r.assetIdInRiv)); + + userDataToApply = JsonUtility.ToJson(container); + + importer.userData = userDataToApply; + + importer.SaveAndReimport(); + } + + + private void HandleAsset(EmbeddedAssetData embeddedAsset, string basePath, string[] extensions, Type assetType, AssetImportContext ctx, ref int oobAssetCount) + { + // If this is a reimport and the asset already has a valid OutOfBandAsset, keep it + if (embeddedAsset.OutOfBandAsset != null) + { + ctx.DependsOnArtifact(AssetDatabase.GetAssetPath(embeddedAsset.OutOfBandAsset)); + oobAssetCount++; + return; + } + + // Only try to auto-detect assets if there isn't one already assigned + foreach (var path in AssetPaths(basePath, embeddedAsset.Name, embeddedAsset.Id, extensions)) + { + if (System.IO.File.Exists(path)) + { + oobAssetCount++; + ctx.DependsOnArtifact(path); + if (!String.IsNullOrEmpty(AssetDatabase.AssetPathToGUID(path))) + { + var referencedAsset = AssetDatabase.LoadAssetAtPath(path, assetType); + if (referencedAsset != null) + { + embeddedAsset.OutOfBandAsset = referencedAsset as OutOfBandAsset; + } + } + break; + } + } + } + + + // Pre-import any out of band assets. + + private void ImportOutOfBandAssets(string assetPath) + { + var bytes = System.IO.File.ReadAllBytes(assetPath); + var basePath = System.IO.Path.GetDirectoryName(assetPath); + + + foreach (var embeddedAsset in embeddedAssetDataLoader.LoadEmbeddedAssetDataFromRiveFileBytes(bytes)) + { + + switch (embeddedAsset.AssetType) + { + case EmbeddedAssetType.Font: + ImportAssetGeneric(embeddedAsset, basePath, fontExtensions); + break; + case EmbeddedAssetType.Image: + ImportAssetGeneric(embeddedAsset, basePath, imageExtensions); + break; + case EmbeddedAssetType.Audio: + ImportAssetGeneric(embeddedAsset, basePath, audioExtensions); + break; + } + } + + + } + + private void ImportAssetGeneric(EmbeddedAssetData embeddedAsset, string basePath, string[] extensions) where T : ScriptedImporter + { + foreach (var path in AssetPaths(basePath, embeddedAsset.Name, embeddedAsset.Id, extensions)) + { + if (System.IO.File.Exists(path) && AssetDatabase.GetImporterOverride(path) == null) + { + AssetDatabase.SetImporterOverride(path); + AssetDatabase.ImportAsset(path); + break; + } + } + } + + string[] AssetPaths(string basePath, string name, uint id, string[] extensions) + { + List paths = new List(); + foreach (var extension in extensions) + { + paths.Add( + basePath + + System.IO.Path.DirectorySeparatorChar + + System.IO.Path.GetFileNameWithoutExtension(name) + + "-" + + id + + "." + + extension + ); + paths.Add( + basePath + + System.IO.Path.DirectorySeparatorChar + + System.IO.Path.GetFileNameWithoutExtension(name) + + "." + + extension + ); + } + return paths.ToArray(); + } + } +} diff --git a/Packages/app.rive.rive-unity/Editor/AssetImporter.cs.meta b/Packages/app.rive.rive-unity/Editor/AssetImporter.cs.meta new file mode 100644 index 00000000..5bfdd9d0 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/AssetImporter.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 043c4b240e8f94f828b8b81fa436f7f0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: df0df084c4eaa4149a9c988c71b85313, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Editor/AssetImporter.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Editor/AudioAssetImporter.cs b/Packages/app.rive.rive-unity/Editor/AudioAssetImporter.cs new file mode 100644 index 00000000..4d18c1dc --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/AudioAssetImporter.cs @@ -0,0 +1,28 @@ +using UnityEngine; +using UnityEditor.AssetImporters; + +namespace Rive +{ + + internal static class AudioOobAssetExtensions + { + public const string WAV = "wav"; + public const string MP3 = "mp3"; + public const string FLAC = "flac"; + + public static readonly string[] AudioExtensions = new[] { WAV, MP3, FLAC }; + } + + [ScriptedImporter(1, null, new string[] { AudioOobAssetExtensions.WAV, AudioOobAssetExtensions.MP3, AudioOobAssetExtensions.FLAC })] + public class AudioAssetImporter : ScriptedImporter + { + public override void OnImportAsset(AssetImportContext ctx) + { + byte[] bytesToAssign = System.IO.File.ReadAllBytes(ctx.assetPath); + AudioOutOfBandAsset file = OutOfBandAsset.Create(bytesToAssign); + + ctx.AddObjectToAsset("rive-audio", file); + ctx.SetMainObject(file); + } + } +} diff --git a/Packages/app.rive.rive-unity/Editor/AudioAssetImporter.cs.meta b/Packages/app.rive.rive-unity/Editor/AudioAssetImporter.cs.meta new file mode 100644 index 00000000..086ff20b --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/AudioAssetImporter.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 20badb765cb0b4f4dadbcd748172bc88 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Editor/AudioAssetImporter.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Editor/Components.meta b/Packages/app.rive.rive-unity/Editor/Components.meta new file mode 100644 index 00000000..3eee6f87 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Components.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f4f0a0d3cb1c74b528f162c21da5d57b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Editor/Components/AtlasRenderTextureStrategyInspector.cs b/Packages/app.rive.rive-unity/Editor/Components/AtlasRenderTextureStrategyInspector.cs new file mode 100644 index 00000000..675f5bc2 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Components/AtlasRenderTextureStrategyInspector.cs @@ -0,0 +1,10 @@ +using Rive.Components; +using UnityEditor; + +namespace Rive.EditorTools +{ + [CustomEditor(typeof(AtlasRenderTargetStrategy), true)] + internal class AtlasRenderTextureStrategyInspector : RiveBaseEditor + { + } +} diff --git a/Packages/app.rive.rive-unity/Editor/Components/AtlasRenderTextureStrategyInspector.cs.meta b/Packages/app.rive.rive-unity/Editor/Components/AtlasRenderTextureStrategyInspector.cs.meta new file mode 100644 index 00000000..1a94cc7f --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Components/AtlasRenderTextureStrategyInspector.cs.meta @@ -0,0 +1,20 @@ +fileFormatVersion: 2 +guid: b0622d49537654134954a8e5d3817d74 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: + - m_styleSheet: {fileID: 7433441132597879392, guid: cc66ac87f8ecb4e3c91384370163ee7b, + type: 3} + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Editor/Components/AtlasRenderTextureStrategyInspector.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Editor/Components/CanvasPanelRendererEditor.cs b/Packages/app.rive.rive-unity/Editor/Components/CanvasPanelRendererEditor.cs new file mode 100644 index 00000000..ce9d34da --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Components/CanvasPanelRendererEditor.cs @@ -0,0 +1,25 @@ +using Rive.Components; +using UnityEditor; + +namespace Rive.EditorTools +{ + [CustomEditor(typeof(RiveCanvasRenderer), true)] + internal class CanvasPanelRendererEditor : PanelRendererInspector + { + protected override void OnEnable() + { + base.OnEnable(); + + if (PanelRenderer.RivePanel == null) + { + RivePanel existingPanel = PanelRenderer.GetComponent(); + + if (existingPanel != null) + { + PanelRenderer.RivePanel = existingPanel; + } + } + } + + } +} diff --git a/Packages/app.rive.rive-unity/Editor/Components/CanvasPanelRendererEditor.cs.meta b/Packages/app.rive.rive-unity/Editor/Components/CanvasPanelRendererEditor.cs.meta new file mode 100644 index 00000000..af29b05b --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Components/CanvasPanelRendererEditor.cs.meta @@ -0,0 +1,20 @@ +fileFormatVersion: 2 +guid: 6cf302e24face493783124060035fb4c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: + - m_styleSheet: {fileID: 7433441132597879392, guid: cc66ac87f8ecb4e3c91384370163ee7b, + type: 3} + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Editor/Components/CanvasPanelRendererEditor.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Editor/Components/CustomElements.meta b/Packages/app.rive.rive-unity/Editor/Components/CustomElements.meta new file mode 100644 index 00000000..a1dde2c4 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Components/CustomElements.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 43b94ffc302e04258ab481523df9abaa +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Editor/Components/CustomElements/AlignmentPropertyDrawer.cs b/Packages/app.rive.rive-unity/Editor/Components/CustomElements/AlignmentPropertyDrawer.cs new file mode 100644 index 00000000..379d4de0 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Components/CustomElements/AlignmentPropertyDrawer.cs @@ -0,0 +1,83 @@ +using System; +using System.Linq; +using UnityEditor; +using UnityEngine; + +#if !UNITY_2022_1_OR_NEWER +using UnityEditor.UIElements; // Required for Unity 2021 +#endif +using UnityEngine.UIElements; + +namespace Rive.EditorTools +{ + /// + /// We don't directly use the property drawer for the Alignment class, but we keep it as a way to create the dropdown field in the inspector for RiveBaseEditor. + /// We do this because the RiveBaseEditor class supports a bunch of the custom attributes we've created and having multiple drawers for the same class can cause conflicts so we do it all in the RiveBaseEditor class. + /// + //[CustomPropertyDrawer(typeof(Alignment))] + internal class AlignmentPropertyDrawer : PropertyDrawer + { + private static readonly (string display, Alignment value)[] OPTIONS = new[] + { + ("Top Left", Alignment.TopLeft), + ("Top Center", Alignment.TopCenter), + ("Top Right", Alignment.TopRight), + ("Center Left", Alignment.CenterLeft), + ("Center", Alignment.Center), + ("Center Right", Alignment.CenterRight), + ("Bottom Left", Alignment.BottomLeft), + ("Bottom Center", Alignment.BottomCenter), + ("Bottom Right", Alignment.BottomRight) + }; + + + + public override VisualElement CreatePropertyGUI(SerializedProperty property) + { + var container = new VisualElement(); + + var xProp = property.FindPropertyRelative(Alignment.BindingPath_Xfield); + var yProp = property.FindPropertyRelative(Alignment.BindingPath_Yfield); + + // Default to Center if we can't get the values + var centerIndex = Array.FindIndex(OPTIONS, o => o.value.Equals(Alignment.Center)); + var currentIndex = centerIndex; + + if (xProp != null && yProp != null) + { + var currentAlignment = new Alignment(xProp.floatValue, yProp.floatValue); + currentIndex = Array.FindIndex(OPTIONS, o => o.value.Equals(currentAlignment)); + if (currentIndex < 0) currentIndex = centerIndex; + } + + var choices = OPTIONS.Select(o => o.display).ToList(); + + var dropdown = new PopupField( + property.displayName, + choices, + currentIndex + ); + + dropdown.RegisterValueChangedCallback(evt => + { + var index = choices.IndexOf(evt.newValue); + if (index >= 0 && xProp != null && yProp != null) + { + var selectedAlignment = OPTIONS[index].value; + xProp.floatValue = selectedAlignment.X; + yProp.floatValue = selectedAlignment.Y; + property.serializedObject.ApplyModifiedProperties(); + } + }); + + dropdown.AddToClassList(StyleHelper.CLASS_FIELD); + + // This ensures that the dropdown is aligned with other fields in the inspector + dropdown.AddToClassList(BaseField.alignedFieldUssClassName); + container.Add(dropdown); + return container; + } + + + } +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Editor/Components/CustomElements/AlignmentPropertyDrawer.cs.meta b/Packages/app.rive.rive-unity/Editor/Components/CustomElements/AlignmentPropertyDrawer.cs.meta new file mode 100644 index 00000000..614cf0ab --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Components/CustomElements/AlignmentPropertyDrawer.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 114c8e3b6a625400a8497c76cf6af315 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Editor/Components/CustomElements/AlignmentPropertyDrawer.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Editor/Components/CustomElements/DropdownDrawer.cs b/Packages/app.rive.rive-unity/Editor/Components/CustomElements/DropdownDrawer.cs new file mode 100644 index 00000000..2a9144ec --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Components/CustomElements/DropdownDrawer.cs @@ -0,0 +1,144 @@ +using System.Collections.Generic; +using System.Reflection; +using System.Linq; +using UnityEditor; +using UnityEditor.UIElements; +using UnityEngine.UIElements; +using Rive.Utils; + +namespace Rive.EditorTools +{ + [CustomPropertyDrawer(typeof(DropdownAttribute))] + internal class DropdownDrawer : PropertyDrawer + { + private PopupOrTextField dropdown; + private SerializedProperty property; + private object target; + private DropdownAttribute dropdownAttr; + private MemberInfo optionsMember; + + public override VisualElement CreatePropertyGUI(SerializedProperty property) + { + this.property = property; + dropdownAttr = attribute as DropdownAttribute; + target = property.serializedObject.targetObject; + var targetType = target.GetType(); + + // Try to find member (field, property, or method) + optionsMember = targetType.GetField(dropdownAttr.OptionsMemberName, + BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static); + + if (optionsMember == null) + { + optionsMember = targetType.GetProperty(dropdownAttr.OptionsMemberName, + BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static); + } + + if (optionsMember == null) + { + optionsMember = targetType.GetMethod(dropdownAttr.OptionsMemberName, + BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static); + } + + if (optionsMember == null) + { + var errorContainer = new VisualElement(); + errorContainer.Add(new HelpBox($"Member {dropdownAttr.OptionsMemberName} not found", HelpBoxMessageType.Error)); + errorContainer.Add(new PropertyField(property)); + return errorContainer; + } + + dropdown = CreateDropdown(); + + // Only register for updates if TrackChanges is enabled + if (dropdownAttr.TrackChanges) + { + EditorApplication.update += UpdateDropdownOptions; + + dropdown.RegisterCallback(evt => + { + EditorApplication.update -= UpdateDropdownOptions; + }); + } + else + { + // For non-tracked dropdowns, we still want to update when the panel is attached + dropdown.RegisterCallback(evt => + { + UpdateDropdownOptions(); + }); + } + + return dropdown; + } + + private PopupOrTextField CreateDropdown() + { + var options = GetCurrentOptions(); + var currentValue = property.stringValue; + + var label = ReflectionUtils.GetPropertyLabel(property); + var dropdown = new PopupOrTextField(options, currentValue, + label); + + dropdown.BindProperty(property); + + var inspectorFieldAttr = fieldInfo.GetCustomAttribute(); + if (inspectorFieldAttr != null) + { + dropdown.AddToClassList(StyleHelper.CLASS_FIELD); + } + + return dropdown; + } + + private List GetCurrentOptions() + { + object options = null; + + switch (optionsMember) + { + case FieldInfo field: + options = field.GetValue(target); + break; + case PropertyInfo prop: + options = prop.GetValue(target); + break; + case MethodInfo method: + options = method.Invoke(target, null); + break; + } + + if (options is IEnumerable enumerable) + { + return enumerable.ToList(); + } + + return new List(); + } + + private void UpdateDropdownOptions() + { + if (dropdown?.panel == null) return; + + var newOptions = GetCurrentOptions(); + if (!AreOptionsEqual(dropdown.Choices, newOptions)) + { + dropdown.Choices = newOptions; + + } + + + } + + private bool AreOptionsEqual(List a, List b) + { + if (a.Count != b.Count) return false; + for (int i = 0; i < a.Count; i++) + { + if (a[i] != b[i]) return false; + } + return true; + } + } +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Editor/Components/CustomElements/DropdownDrawer.cs.meta b/Packages/app.rive.rive-unity/Editor/Components/CustomElements/DropdownDrawer.cs.meta new file mode 100644 index 00000000..3ee8a251 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Components/CustomElements/DropdownDrawer.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 55ad3672c80b042f288de391c21e3bf9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Editor/Components/CustomElements/DropdownDrawer.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Editor/Components/CustomElements/MaterialPropertiesDrawer.cs b/Packages/app.rive.rive-unity/Editor/Components/CustomElements/MaterialPropertiesDrawer.cs new file mode 100644 index 00000000..e7fd56e4 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Components/CustomElements/MaterialPropertiesDrawer.cs @@ -0,0 +1,237 @@ +using UnityEditor; +using UnityEngine; +using UnityEngine.UIElements; +using UnityEditor.UIElements; +using System.Collections.Generic; +using System.Linq; +using Rive.Utils; +#if UNITY_6000_3_OR_NEWER +using MaterialShaderPropertyType = UnityEngine.Rendering.ShaderPropertyType; +#else +using MaterialShaderPropertyType = UnityEditor.ShaderUtil.ShaderPropertyType; +#endif + +namespace Rive.EditorTools +{ + /// + /// Draws a list of properties from a material on a component as a dropdown. This is useful if you want to display a list of properties from a material on a component in the inspector. + /// + [CustomPropertyDrawer(typeof(MaterialPropertiesAttribute))] + internal class MaterialPropertiesDrawer : PropertyDrawer + { + private VisualElement m_root; + private List m_availablePropertyNames = new List(); + private SerializedObject m_serializedObject; + + private Material[] GetMaterialsFromSource(object target, string sourceName) + { + // Try to get materials directly + if (ReflectionUtils.TryGetValue(target, sourceName, out var materials)) + { + return materials; + } + + // If we got a renderer instead, get its materials + if (ReflectionUtils.TryGetValue(target, sourceName, out var renderer)) + { + return renderer?.sharedMaterials; + } + + return null; + } + + public override VisualElement CreatePropertyGUI(SerializedProperty property) + { + var attr = attribute as MaterialPropertiesAttribute; + m_root = new VisualElement(); + m_serializedObject = property.serializedObject; + + var target = property.serializedObject.targetObject; + var materials = GetMaterialsFromSource(target, attr.MaterialsSourceName); + + if (materials == null) + { + m_root.Add(new HelpBox($"Could not find materials source: {attr.MaterialsSourceName}", HelpBoxMessageType.Error)); + return m_root; + } + + UpdateUI(property, materials, attr.PropertyType); + return m_root; + } + + private void UpdateUI(SerializedProperty property, Material[] materials, MaterialShaderPropertyType propertyType) + { + m_root.Clear(); + UpdateAvailablePropertyNames(materials, propertyType); + + var keysProperty = property.FindPropertyRelative(SerializedDictionary.BindingPath_Keys); + var valuesProperty = property.FindPropertyRelative(SerializedDictionary.BindingPath_Values); + + // Pre-create property holders for all materials + EnsurePropertyHoldersExist(keysProperty, valuesProperty, materials.Length); + + for (int i = 0; i < materials.Length; i++) + { + var material = materials[i]; + if (material == null) continue; + + var materialFoldout = new Foldout { text = $"Material {i}: {material.name}" }; + m_root.Add(materialFoldout); + + var propertyListHolder = FindPropertyListHolder(keysProperty, valuesProperty, i); + if (propertyListHolder != null) + { + var propertyList = propertyListHolder.FindPropertyRelative(Components.RiveTextureRenderer.PropertyNameListHolder.BindingPath_PropertyNames); + if (propertyList != null && propertyList.serializedObject != null) + { + var listView = CreateListView(propertyList); + materialFoldout.Add(listView); + } + } + } + + // Apply any changes made during setup + property.serializedObject.ApplyModifiedProperties(); + } + + private void EnsurePropertyHoldersExist(SerializedProperty keysProperty, SerializedProperty valuesProperty, int materialCount) + { + // First, create a list of existing material indices + var existingIndices = new HashSet(); + for (int i = 0; i < keysProperty.arraySize; i++) + { + existingIndices.Add(keysProperty.GetArrayElementAtIndex(i).intValue); + } + + // Create missing property holders + for (int i = 0; i < materialCount; i++) + { + if (!existingIndices.Contains(i)) + { + keysProperty.InsertArrayElementAtIndex(keysProperty.arraySize); + keysProperty.GetArrayElementAtIndex(keysProperty.arraySize - 1).intValue = i; + + valuesProperty.InsertArrayElementAtIndex(valuesProperty.arraySize); + } + } + } + + private SerializedProperty FindPropertyListHolder(SerializedProperty keysProperty, SerializedProperty valuesProperty, int materialIndex) + { + for (int i = 0; i < keysProperty.arraySize; i++) + { + if (keysProperty.GetArrayElementAtIndex(i).intValue == materialIndex) + { + return valuesProperty.GetArrayElementAtIndex(i); + } + } + return null; + } + + private ListView CreateListView(SerializedProperty propertyList) + { + var listView = new ListView() + { + reorderable = true, + showAddRemoveFooter = true, + showBorder = true, + showFoldoutHeader = false, + showBoundCollectionSize = false, + virtualizationMethod = CollectionVirtualizationMethod.DynamicHeight + }; + + // Delay binding until the next frame to ensure proper initialization + m_root.schedule.Execute(() => + { + listView.bindingPath = propertyList.propertyPath; + listView.BindProperty(propertyList.serializedObject); + }); + + listView.makeItem = () => new PopupOrTextField(m_availablePropertyNames, ""); + listView.bindItem = (element, index) => + { + var popupOrTextField = element as PopupOrTextField; + popupOrTextField.Choices = m_availablePropertyNames; + + if (propertyList != null && propertyList.serializedObject != null) + { + var itemProperty = propertyList.GetArrayElementAtIndex(index); + popupOrTextField.BindProperty(itemProperty); + } + }; + + listView.itemsAdded += (indexes) => + { + if (propertyList != null && propertyList.serializedObject != null) + { + foreach (int index in indexes) + { + var itemProperty = propertyList.GetArrayElementAtIndex(index); + if (string.IsNullOrEmpty(itemProperty.stringValue)) + { + itemProperty.stringValue = m_availablePropertyNames.FirstOrDefault() ?? ""; + propertyList.serializedObject.ApplyModifiedProperties(); + } + } + } + listView.Rebuild(); + }; + + return listView; + } + + private static int GetPropertyCount(Shader shader) + { +#if UNITY_6000_3_OR_NEWER + return shader.GetPropertyCount(); +#else + return ShaderUtil.GetPropertyCount(shader); +#endif + } + + private static MaterialShaderPropertyType GetPropertyType(Shader shader, int index) + { +#if UNITY_6000_3_OR_NEWER + return shader.GetPropertyType(index); +#else + return ShaderUtil.GetPropertyType(shader, index); +#endif + } + + private static string GetPropertyName(Shader shader, int index) + { +#if UNITY_6000_3_OR_NEWER + return shader.GetPropertyName(index); +#else + return ShaderUtil.GetPropertyName(shader, index); +#endif + } + + private void UpdateAvailablePropertyNames(Material[] materials, MaterialShaderPropertyType propertyType) + { + m_availablePropertyNames.Clear(); + + foreach (var material in materials) + { + if (material != null) + { + var shader = material.shader; + for (int i = 0; i < GetPropertyCount(shader); i++) + { + if (GetPropertyType(shader, i) == propertyType) + { + string propertyName = GetPropertyName(shader, i); + if (!m_availablePropertyNames.Contains(propertyName)) + { + m_availablePropertyNames.Add(propertyName); + } + } + } + } + } + } + + + + } +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Editor/Components/CustomElements/MaterialPropertiesDrawer.cs.meta b/Packages/app.rive.rive-unity/Editor/Components/CustomElements/MaterialPropertiesDrawer.cs.meta new file mode 100644 index 00000000..356fc4b0 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Components/CustomElements/MaterialPropertiesDrawer.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 13ea997b79c3b4e1b82a9adeabd70082 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Editor/Components/CustomElements/MaterialPropertiesDrawer.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Editor/Components/CustomElements/PopupOrTextField.cs b/Packages/app.rive.rive-unity/Editor/Components/CustomElements/PopupOrTextField.cs new file mode 100644 index 00000000..99cfe8ae --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Components/CustomElements/PopupOrTextField.cs @@ -0,0 +1,445 @@ +using UnityEngine.UIElements; +using System.Collections.Generic; +using System; +using UnityEditor; +using UnityEngine; +using UnityEditor.UIElements; +using Rive.Utils; + +namespace Rive.EditorTools +{ + /// + /// A visual element that allows the user to select from a list of choices or enter a custom value. + /// + internal class PopupOrTextField : VisualElement, INotifyValueChanged + { + private PopupField popupField; + private TextField textField; + private Button switchModeButton; + private bool isCustomValue; + private bool isUserEditing; + private bool isProgrammaticChange; + private SerializedProperty boundProperty; + private SerializedObject serializedObject; + private UnityEngine.Object targetObject; + + private string m_Value; + public string value + { + get => m_Value; + set + { + if (m_Value != value) + { + using (var changeEvent = ChangeEvent.GetPooled(m_Value, value)) + { + changeEvent.target = this; + SetValueWithoutNotify(value); + SendEvent(changeEvent); + } + } + } + } + + public List Choices + { + get => popupField.choices; + set + { + popupField.choices = value; + bool valueIsInChoices = value.Contains(m_Value); + + // Handle transition from Popup to Custom + if (!isCustomValue && !valueIsInChoices) + { + isCustomValue = true; + isProgrammaticChange = true; + SetValueWithoutNotify(m_Value); + isProgrammaticChange = false; + } + // Handle transition from Custom to Popup + else if (valueIsInChoices && isCustomValue) + { + isCustomValue = false; + isProgrammaticChange = true; + SetValueWithoutNotify(m_Value); + isProgrammaticChange = false; + } + + UpdateVisibility(); + } + } + + public string Label + { + get => popupField.label; + set + { + popupField.label = value; + textField.label = value; + } + } + + public PopupOrTextField() : this(new List(), "") { } + + public PopupOrTextField(List choices, string currentValue, string labelText = null) + { + popupField = new PopupField(choices, 0); + textField = new TextField(); + switchModeButton = new Button(ToggleMode) + { + text = "✎", + tooltip = "Switch to text input" + }; + + SetupUI(); + SetupCallbacks(); + SetInitialState(currentValue); + + if (labelText != null) + { + Label = labelText; + } + + RegisterCallback(OnSerializedPropertyChange); + } + + private void SetupUI() + { + var container = new VisualElement(); + container.style.flexDirection = FlexDirection.Row; + container.style.width = new StyleLength(Length.Percent(100)); + container.Add(popupField); + container.Add(textField); + container.Add(switchModeButton); + + SetupFieldStyles(popupField); + SetupFieldStyles(textField); + SetupButtonStyles(switchModeButton); + + textField.style.display = DisplayStyle.None; + textField.visible = false; + popupField.style.display = DisplayStyle.Flex; + popupField.visible = true; + + Add(container); + } + + private void SetupFieldStyles(VisualElement field) + { + // This keeps inspector positioned around the same point as other unity fields. Otherwise the popup fills the whole row, when it should stop in the middle. + field.AddToClassList(BaseField.alignedFieldUssClassName); // Same as using "unity-base-field__aligned" in UXML + + + field.style.flexGrow = 1; + field.style.marginRight = 20; + field.style.paddingBottom = 0; + field.style.paddingTop = 0; + field.style.paddingLeft = 0; + field.style.marginBottom = 0; + field.style.marginTop = 0; + field.style.marginLeft = 0; + } + + private void SetupButtonStyles(Button button) + { + button.style.position = Position.Absolute; + button.style.right = 0; + button.style.width = 20; + button.style.height = popupField.style.height; + button.style.marginRight = 0; + button.style.marginLeft = 0; + button.style.marginTop = 0; + button.style.marginBottom = 0; + button.style.paddingBottom = 0; + button.style.paddingTop = 0; + button.style.paddingLeft = 0; + button.style.paddingRight = 0; + } + + + private void SetupCallbacks() + { + popupField.RegisterValueChangedCallback(evt => + { + if (isProgrammaticChange) + return; // Ignore programmatic changes to prevent recursive calls + + value = evt.newValue; + }); + + textField.RegisterCallback(evt => isUserEditing = true); + textField.RegisterCallback(evt => + { + isUserEditing = false; + UpdateVisualState(); + }); + + textField.RegisterValueChangedCallback(evt => + { + if (isProgrammaticChange) + return; + + value = evt.newValue; + }); + } + + private void SetInitialState(string initialValue) + { + m_Value = initialValue; + isCustomValue = !Choices.Contains(initialValue); + + if (!isCustomValue) + { + popupField.SetValueWithoutNotify(initialValue); + } + else + { + textField.SetValueWithoutNotify(initialValue); + } + + UpdateVisibility(); + } + + private void ToggleMode() + { + if (targetObject != null) + { + Undo.RecordObject(targetObject, "Toggle PopupOrTextField Mode"); + } + + var initialValue = m_Value; + isCustomValue = !isCustomValue; + + if (isCustomValue) + { + textField.SetValueWithoutNotify(m_Value); + } + else + { + if (Choices.Contains(m_Value)) + { + popupField.SetValueWithoutNotify(m_Value); + } + else if (Choices.Count > 0) + { + SetValueWithoutNotify(Choices[0]); + } + else + { + popupField.SetValueWithoutNotify(string.Empty); + } + } + + UpdateVisibility(); + + if (targetObject != null) + { + EditorUtility.SetDirty(targetObject); + } + + if (initialValue != m_Value) + { + using (var changeEvent = ChangeEvent.GetPooled(initialValue, m_Value)) + { + changeEvent.target = this; + SendEvent(changeEvent); + } + } + } + + private void UpdateVisualState() + { + bool valueInChoices = Choices.Contains(m_Value); + + if (valueInChoices) + { + if (!isCustomValue) + { + // We make sure the popupField reflects the current value + popupField.SetValueWithoutNotify(m_Value); + } + + if (isCustomValue && !isUserEditing) + { + isCustomValue = false; + UpdateVisibility(); + } + } + else + { + textField.SetValueWithoutNotify(m_Value); + if (!isCustomValue) + { + isCustomValue = true; + UpdateVisibility(); + } + } + } + + private void UpdateVisibility() + { + if (isCustomValue) + { + popupField.style.display = DisplayStyle.None; + popupField.visible = false; + + textField.style.display = DisplayStyle.Flex; + textField.visible = true; + + switchModeButton.text = "▼"; + switchModeButton.tooltip = "Switch to dropdown"; + } + else + { + textField.style.display = DisplayStyle.None; + textField.visible = false; + + popupField.style.display = DisplayStyle.Flex; + popupField.visible = true; + + switchModeButton.text = "✎"; + switchModeButton.tooltip = "Switch to text input"; + } + + this.MarkDirtyRepaint(); + } + + public void SetValueWithoutNotify(string newValue) + { + if (serializedObject != null) + { + serializedObject.Update(); + } + + m_Value = newValue; + + // Force check if value is in choices and update mode accordingly + bool valueInChoices = Choices.Contains(newValue); + + if (valueInChoices && (!isUserEditing || isProgrammaticChange)) + { + isCustomValue = false; + isProgrammaticChange = true; + popupField.SetValueWithoutNotify(newValue); + isProgrammaticChange = false; + } + else + { + if (!valueInChoices) + { + isCustomValue = true; + } + isProgrammaticChange = true; + textField.SetValueWithoutNotify(newValue); + isProgrammaticChange = false; + } + + UpdateVisibility(); + + if (boundProperty != null) + { + boundProperty.stringValue = newValue; + serializedObject.ApplyModifiedProperties(); + } + } + + private void OnSerializedPropertyChange(SerializedPropertyChangeEvent evt) + { + if (evt.changedProperty == boundProperty) + { + isProgrammaticChange = true; + SetValueWithoutNotify(boundProperty.stringValue); + isProgrammaticChange = false; + } + } + + public void BindProperty(SerializedProperty property) + { + UnbindProperty(); + + if (property != null && property.propertyType == SerializedPropertyType.String) + { + boundProperty = property; + serializedObject = property.serializedObject; + targetObject = serializedObject.targetObject; + SetInitialState(property.stringValue); + EditorApplication.update += UpdateFromSerializedProperty; + } + else + { + DebugLogger.Instance.LogError("PopupOrTextField: Attempted to bind to a null or non-string property."); + } + + this.RegisterCallback(OnAttachToPanel); + this.RegisterCallback(OnDetachFromPanel); + } + + private void OnAttachToPanel(AttachToPanelEvent evt) + { + if (serializedObject != null && boundProperty != null) + { + serializedObject.Update(); + SetInitialState(boundProperty.stringValue); + } + } + + private void OnDetachFromPanel(DetachFromPanelEvent evt) + { + UnbindProperty(); + } + + private void UpdateFromSerializedProperty() + { + try + { + if (serializedObject == null || boundProperty == null) + { + UnbindProperty(); + return; + } + + // Check if the serializedObject is still valid + if (serializedObject.targetObject == null) + { + UnbindProperty(); + return; + } + + serializedObject.Update(); + + // Double-check everything is still valid after the update + if (boundProperty == null || boundProperty.serializedObject == null || boundProperty.serializedObject.targetObject == null) + { + UnbindProperty(); + return; + } + + if (boundProperty.propertyType == SerializedPropertyType.String) + { + string newValue = boundProperty.stringValue; + if (m_Value != newValue && !isUserEditing) + { + SetValueWithoutNotify(newValue); + } + } + else + { + DebugLogger.Instance.LogWarning($"PopupOrTextField: Bound property is not a string. Property path: {boundProperty.propertyPath}"); + } + } + catch (Exception) + { + UnbindProperty(); + } + } + + private void UnbindProperty() + { + boundProperty = null; + serializedObject = null; + targetObject = null; + EditorApplication.update -= UpdateFromSerializedProperty; + } + } +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Editor/Components/CustomElements/PopupOrTextField.cs.meta b/Packages/app.rive.rive-unity/Editor/Components/CustomElements/PopupOrTextField.cs.meta new file mode 100644 index 00000000..2a9fad2b --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Components/CustomElements/PopupOrTextField.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 226b35944e5bc4908b226f5fb91d99d2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Editor/Components/CustomElements/PopupOrTextField.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Editor/Components/CustomElements/WidthHeightDimensionsDrawer.cs b/Packages/app.rive.rive-unity/Editor/Components/CustomElements/WidthHeightDimensionsDrawer.cs new file mode 100644 index 00000000..245e721b --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Components/CustomElements/WidthHeightDimensionsDrawer.cs @@ -0,0 +1,37 @@ +using UnityEngine; +using UnityEditor; +using UnityEngine.UIElements; +using Rive.Utils; + +namespace Rive.EditorTools +{ + [CustomPropertyDrawer(typeof(WidthHeightDimensionsAttribute))] + internal class WidthHeightDimensionsDrawer : PropertyDrawer + { + public override VisualElement CreatePropertyGUI(SerializedProperty property) + { + var attr = attribute as WidthHeightDimensionsAttribute; + var label = ReflectionUtils.GetPropertyLabel(property) ?? attr.Label; + + // Get tooltip from TooltipAttribute if present + string tooltip = null; + var tooltipAttribute = fieldInfo.GetCustomAttributes(typeof(TooltipAttribute), true); + if (tooltipAttribute.Length > 0) + { + tooltip = (tooltipAttribute[0] as TooltipAttribute).tooltip; + } + + var field = new WidthHeightDimensionsField( + label, + attr.WidthLabel, + attr.HeightLabel, + tooltip + ); + + field.BindProperty(property); + return field; + } + + + } +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Editor/Components/CustomElements/WidthHeightDimensionsDrawer.cs.meta b/Packages/app.rive.rive-unity/Editor/Components/CustomElements/WidthHeightDimensionsDrawer.cs.meta new file mode 100644 index 00000000..2e7eb182 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Components/CustomElements/WidthHeightDimensionsDrawer.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: d32c71bc31ac443d5a36065d1d672d12 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Editor/Components/CustomElements/WidthHeightDimensionsDrawer.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Editor/Components/CustomElements/WidthHeightDimensionsField.cs b/Packages/app.rive.rive-unity/Editor/Components/CustomElements/WidthHeightDimensionsField.cs new file mode 100644 index 00000000..c5a5698f --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Components/CustomElements/WidthHeightDimensionsField.cs @@ -0,0 +1,50 @@ +using UnityEngine.UIElements; +using UnityEditor.UIElements; +using UnityEditor; + +namespace Rive.EditorTools +{ + /// + /// A field for editing a Vector2Int representing width and height. + /// + internal class WidthHeightDimensionsField : VisualElement + { + + public IntegerField WidthField { get; private set; } + public IntegerField HeightField { get; private set; } + + public WidthHeightDimensionsField(string label, string widthLabel = "Width", string heightLabel = "Height", string tooltip = null) + { + var foldout = new Foldout + { + text = label, + tooltip = tooltip, + value = true // Start expanded + }; + Add(foldout); + + var container = new VisualElement(); + foldout.Add(container); + + WidthField = new IntegerField(widthLabel) + { + style = { marginTop = 4 } + }; + WidthField.AddToClassList(BaseField.alignedFieldUssClassName); + container.Add(WidthField); + + HeightField = new IntegerField(heightLabel) + { + style = { marginTop = 4 } + }; + HeightField.AddToClassList(BaseField.alignedFieldUssClassName); + container.Add(HeightField); + } + + public void BindProperty(SerializedProperty property) + { + WidthField.BindProperty(property.FindPropertyRelative("x")); + HeightField.BindProperty(property.FindPropertyRelative("y")); + } + } +} diff --git a/Packages/app.rive.rive-unity/Editor/Components/CustomElements/WidthHeightDimensionsField.cs.meta b/Packages/app.rive.rive-unity/Editor/Components/CustomElements/WidthHeightDimensionsField.cs.meta new file mode 100644 index 00000000..3aaccd69 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Components/CustomElements/WidthHeightDimensionsField.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 18c92b4c6ab3f42e6a1e827ed99c91fa +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Editor/Components/CustomElements/WidthHeightDimensionsField.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Editor/Components/DataBindingPlaygroundWindow.cs b/Packages/app.rive.rive-unity/Editor/Components/DataBindingPlaygroundWindow.cs new file mode 100644 index 00000000..d63d7a40 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Components/DataBindingPlaygroundWindow.cs @@ -0,0 +1,2090 @@ +using System; +using System.Collections.Generic; +using System.Collections; +using System.Linq; +using Rive; +using Rive.Components; +using UnityEditor; +using UnityEditor.UIElements; +using UnityEngine; +using UnityEngine.UIElements; + +namespace Rive.EditorTools +{ + internal class DataBindingPlaygroundWindow : EditorWindow + { + private RiveWidget m_widget; + private ObjectField m_widgetField; + private HelpBox m_playModeHelpBox; + private VisualElement m_interactiveContainer; + private ScrollView m_propertiesScroll; + + private readonly List m_propertyBindings = new List(); + private readonly List m_listBindings = new List(); + private readonly List m_triggerBindingDisposers = new List(); + private bool m_isRefreshing; + private const double TriggerFiredHighlightSeconds = 0.75d; + private enum PlaygroundState + { + NotPlaying, + NoWidget, + NoFileMetadata, + NoViewModels, + NoArtboardMetadata, + NoDefaultViewModel, + WidgetNotLoaded, + NoViewModelInstance, + Ready + } + + private FileMetadata m_fileMetadata; + private FileMetadata.ArtboardMetadata m_artboardMetadata; + private double m_nextRefreshTime; + private readonly Dictionary m_imageSelectionCache = new Dictionary(); + private readonly Dictionary m_artboardSelectionCache = new Dictionary(); + private readonly Dictionary m_viewModelExpansion = new Dictionary(); + + // Used for the artboard databinding dropdowns + private enum ArtboardViewModelBindingMode + { + ExistingInstance, + CreateNewInstance + } + + private class ArtboardSelection + { + public Asset Asset; + public File File; + public string ArtboardName; + public ArtboardViewModelBindingMode ViewModelBindingMode = ArtboardViewModelBindingMode.ExistingInstance; + public string ExistingViewModelInstanceName; + public ViewModelInstance CustomViewModelInstance; + public readonly List CustomBindings = new List(); + public readonly List CustomListBindings = new List(); + + public void DisposeCustomViewModelInstance() + { + CustomViewModelInstance?.Dispose(); + CustomViewModelInstance = null; + CustomBindings.Clear(); + CustomListBindings.Clear(); + } + + public void DisposeAll() + { + DisposeCustomViewModelInstance(); + File = null; + } + } + + private const string DocsBaseUrl = InspectorDocLinks.UnityDataBinding; + + private class PropertyBinding + { + public string Path; + public VisualElement Control; + public Action Sync; + } + + private class ListPropertyBinding + { + public string Path; + public VisualElement Control; + public Action Sync; + public List LastItems = new List(); + public bool InitializedTypeSelection; + } + + // Adapter that proxies a list property directly into a ListView without keeping a stale mirror. + private class ListPropertyAdapter : IList, IList + { + private readonly Func m_propertyGetter; + private readonly Func m_factory; + + public ListPropertyAdapter(Func propertyGetter, Func factory) + { + m_propertyGetter = propertyGetter; + m_factory = factory; + } + + private ViewModelInstanceListProperty Prop => m_propertyGetter?.Invoke(); + + public int Count => Prop?.Count ?? 0; + + public bool IsReadOnly => false; + bool IList.IsFixedSize => false; + + public ViewModelInstance this[int index] + { + get => Prop?.GetInstanceAt(index); + set => MoveOrReplace(index, value); + } + + object IList.this[int index] + { + get => this[index]; + set + { + MoveOrReplace(index, value as ViewModelInstance); + } + } + + private void MoveOrReplace(int index, ViewModelInstance value) + { + var prop = Prop; + if (prop == null || value == null) + { + return; + } + + // If the instance already exists in the list, move it. + int existingIndex = -1; + for (int i = 0; i < prop.Count; i++) + { + if (ReferenceEquals(prop.GetInstanceAt(i), value)) + { + existingIndex = i; + break; + } + } + + if (existingIndex == index) + { + return; + } + + if (existingIndex >= 0) + { + prop.RemoveAt(existingIndex); + if (existingIndex < index) + { + index -= 1; + } + } + else if (index < prop.Count) + { + // Replace the current item at index if value not found elsewhere + prop.RemoveAt(index); + } + + index = Mathf.Clamp(index, 0, prop.Count); + prop.Insert(value, index); + } + + public void Add(ViewModelInstance item) + { + var prop = Prop; + if (prop == null) + { + return; + } + + var toAdd = item ?? m_factory?.Invoke(); + if (toAdd != null) + { + prop.Add(toAdd); + } + } + + int IList.Add(object value) + { + var prop = Prop; + if (prop == null) + { + return -1; + } + + Add(value as ViewModelInstance); + return prop.Count - 1; + } + + public void Clear() + { + var prop = Prop; + if (prop == null) + { + return; + } + + for (int i = prop.Count - 1; i >= 0; i--) + { + prop.RemoveAt(i); + } + } + + public bool Contains(ViewModelInstance item) + { + var prop = Prop; + if (prop == null || item == null) + { + return false; + } + + for (int i = 0; i < prop.Count; i++) + { + if (ReferenceEquals(prop.GetInstanceAt(i), item)) + { + return true; + } + } + + return false; + } + + public void CopyTo(ViewModelInstance[] array, int arrayIndex) + { + var prop = Prop; + if (prop == null || array == null) + { + return; + } + + int count = prop.Count; + for (int i = 0; i < count && arrayIndex + i < array.Length; i++) + { + array[arrayIndex + i] = prop.GetInstanceAt(i); + } + } + + public IEnumerator GetEnumerator() + { + var prop = Prop; + if (prop == null) + { + yield break; + } + + int count = prop.Count; + for (int i = 0; i < count; i++) + { + yield return prop.GetInstanceAt(i); + } + } + + public int IndexOf(ViewModelInstance item) + { + var prop = Prop; + if (prop == null || item == null) + { + return -1; + } + + for (int i = 0; i < prop.Count; i++) + { + if (ReferenceEquals(prop.GetInstanceAt(i), item)) + { + return i; + } + } + + return -1; + } + + public void Insert(int index, ViewModelInstance item) + { + var prop = Prop; + if (prop == null) + { + return; + } + + var toInsert = item ?? m_factory?.Invoke(); + if (toInsert == null) + { + return; + } + + index = Mathf.Clamp(index, 0, prop.Count); + prop.Insert(toInsert, index); + } + + void IList.Insert(int index, object value) => Insert(index, value as ViewModelInstance); + + public bool Remove(ViewModelInstance item) + { + var prop = Prop; + if (prop == null || item == null) + { + return false; + } + + prop.Remove(item); + return true; + } + + void IList.Remove(object value) => Remove(value as ViewModelInstance); + + public void RemoveAt(int index) + { + var prop = Prop; + if (prop == null || index < 0 || index >= prop.Count) + { + return; + } + + prop.RemoveAt(index); + } + + bool IList.Contains(object value) => Contains(value as ViewModelInstance); + + void ICollection.CopyTo(Array array, int index) + { + if (array == null) + { + return; + } + + var prop = Prop; + if (prop == null) + { + return; + } + + for (int i = 0; i < prop.Count && index + i < array.Length; i++) + { + array.SetValue(prop.GetInstanceAt(i), index + i); + } + } + + bool ICollection.IsSynchronized => false; + + private readonly object m_syncRoot = new object(); + object ICollection.SyncRoot => m_syncRoot; + + int IList.IndexOf(object value) => IndexOf(value as ViewModelInstance); + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => GetEnumerator(); + } + + public static void Open(RiveWidget widget) + { + var window = GetWindow(); + window.titleContent = new GUIContent("Rive Data Binding Playground"); + window.minSize = new Vector2(420, 360); + window.SetTarget(widget); + window.Show(); + } + + private void OnEnable() + { + titleContent = new GUIContent("Rive Data Binding Playground"); + minSize = new Vector2(420, 360); + BuildLayout(); + EditorApplication.update += EditorUpdate; + } + + private void OnDisable() + { + EditorApplication.update -= EditorUpdate; + ClearTriggerBindings(); + m_propertyBindings.Clear(); + m_listBindings.Clear(); + m_widget = null; + foreach (var selection in m_artboardSelectionCache.Values) + { + selection.DisposeAll(); + } + m_artboardSelectionCache.Clear(); + m_viewModelExpansion.Clear(); + } + + private void EditorUpdate() + { + // throttle refreshes to avoid unnecessary work + if (EditorApplication.timeSinceStartup < m_nextRefreshTime) + { + return; + } + + m_nextRefreshTime = EditorApplication.timeSinceStartup + 0.25f; + UpdateVisibility(); + RefreshValues(); + } + + private void BuildLayout() + { + var root = rootVisualElement; + root.Clear(); + root.style.paddingLeft = 10; + root.style.paddingRight = 10; + root.style.paddingTop = 8; + root.style.paddingBottom = 10; + + var subtitleRow = new VisualElement + { + style = + { + flexDirection = FlexDirection.Row, + alignItems = Align.Center, + marginBottom = 14 + } + }; + var subtitle = new Label("Inspect and tweak ViewModel instance properties for the selected RiveWidget."); + subtitle.style.flexGrow = 1; + subtitle.style.fontSize = 12; + subtitle.style.color = new UnityEngine.Color(0.8f, 0.8f, 0.8f, 0.95f); + + var docsLink = new Label("View Data Binding Docs"); + StyleLinkLabel(docsLink, InspectorDocLinks.UnityDataBinding); + + subtitleRow.Add(subtitle); + subtitleRow.Add(docsLink); + root.Add(subtitleRow); + + m_playModeHelpBox = new HelpBox( + "Play with data binding values for the selected RiveWidget while in Play Mode. " + + "Changes are applied to the widget's current ViewModel instance.", + HelpBoxMessageType.Info); + + m_playModeHelpBox.style.marginBottom = 10; + root.Add(m_playModeHelpBox); + + m_widgetField = new ObjectField("Widget") + { + objectType = typeof(RiveWidget), + allowSceneObjects = true + }; + m_widgetField.RegisterValueChangedCallback(evt => + { + SetTarget(evt.newValue as RiveWidget); + }); + root.Add(m_widgetField); + + m_interactiveContainer = new VisualElement(); + m_interactiveContainer.style.flexDirection = FlexDirection.Column; + m_interactiveContainer.style.flexGrow = 1; + root.Add(m_interactiveContainer); + + m_propertiesScroll = new ScrollView + { + style = + { + flexGrow = 1 + } + }; + m_interactiveContainer.Add(m_propertiesScroll); + + UpdateVisibility(); + } + + private void SetTarget(RiveWidget widget) + { + m_widget = widget; + m_widgetField?.SetValueWithoutNotify(widget); + RefreshMetadata(); + RebuildProperties(); + UpdateVisibility(); + RefreshValues(); + } + + private void RefreshMetadata() + { + m_fileMetadata = m_widget?.Asset?.EditorOnlyMetadata; + m_artboardMetadata = null; + + if (m_fileMetadata == null) + { + return; + } + + var artboardName = !string.IsNullOrEmpty(m_widget?.ArtboardName) + ? m_widget.ArtboardName + : m_fileMetadata.GetArtboardNames().FirstOrDefault(); + + if (!string.IsNullOrEmpty(artboardName)) + { + m_artboardMetadata = m_fileMetadata.GetArtboard(artboardName); + } + } + + private void RebuildProperties() + { + ClearTriggerBindings(); + m_propertyBindings.Clear(); + m_listBindings.Clear(); + m_viewModelExpansion.Clear(); + m_propertiesScroll.Clear(); + + if (m_widget == null) + { + m_propertiesScroll.Add(new Label("Select a RiveWidget to get started.")); + return; + } + + if (m_artboardMetadata == null) + { + m_propertiesScroll.Add(new HelpBox("No artboard metadata found for the selected widget.", HelpBoxMessageType.Warning)); + return; + } + + if (m_artboardMetadata.DefaultViewModel == null) + { + m_propertiesScroll.Add(new HelpBox("The current artboard does not have a default ViewModel.", HelpBoxMessageType.Warning)); + return; + } + + BuildViewModelSection( + m_artboardMetadata.DefaultViewModel, + string.Empty, + m_propertiesScroll, + 0); + } + + private FileMetadata.ViewModelMetadata FindViewModelMetadata(string viewModelName, FileMetadata metadataContext = null) + { + var metadata = metadataContext ?? m_fileMetadata; + if (metadata == null || string.IsNullOrEmpty(viewModelName)) + { + return null; + } + + return metadata.ViewModels.FirstOrDefault(vm => vm.Name == viewModelName); + } + + private List GetEnumOptions(FileMetadata.ViewModelPropertyMetadata property, FileMetadata metadataContext = null) + { + var metadata = metadataContext ?? m_fileMetadata; + if (metadata == null || metadata.Enums == null || string.IsNullOrEmpty(property.EnumTypeName)) + { + return null; + } + + var enumMeta = metadata.Enums.FirstOrDefault(e => e.Name == property.EnumTypeName); + return enumMeta?.Values?.ToList(); + } + + private void AddStringField(VisualElement parent, string path, string displayName, Func instanceProvider = null, string cacheKey = null, string pathLabelOverride = null, List bindingList = null) + { + instanceProvider ??= GetCurrentInstance; + cacheKey ??= path; + bindingList ??= m_propertyBindings; + + var field = new TextField(); + field.RegisterValueChangedCallback(evt => + { + var instance = instanceProvider(); + var prop = instance?.GetStringProperty(path); + if (prop != null) + { + prop.Value = evt.newValue; + } + }); + + bindingList.Add(new PropertyBinding + { + Path = cacheKey, + Control = field, + Sync = instance => + { + var current = instanceProvider(); + var prop = current?.GetStringProperty(path); + field.SetEnabled(prop != null); + if (prop != null) + { + field.SetValueWithoutNotify(prop.Value ?? string.Empty); + } + } + }); + + parent.Add(CreatePropertyCard(displayName, pathLabelOverride ?? path, "String", GetDocUrl(ViewModelDataType.String), + null, field)); + } + + private void AddNumberField(VisualElement parent, string path, string displayName, Func instanceProvider = null, string cacheKey = null, string pathLabelOverride = null, List bindingList = null) + { + instanceProvider ??= GetCurrentInstance; + cacheKey ??= path; + bindingList ??= m_propertyBindings; + + var field = new FloatField(); + field.RegisterValueChangedCallback(evt => + { + var instance = instanceProvider(); + var prop = instance?.GetNumberProperty(path); + if (prop != null) + { + prop.Value = evt.newValue; + } + }); + + bindingList.Add(new PropertyBinding + { + Path = cacheKey, + Control = field, + Sync = instance => + { + var current = instanceProvider(); + var prop = current?.GetNumberProperty(path); + field.SetEnabled(prop != null); + if (prop != null) + { + field.SetValueWithoutNotify(prop.Value); + } + } + }); + + parent.Add(CreatePropertyCard(displayName, pathLabelOverride ?? path, "Number", GetDocUrl(ViewModelDataType.Number), + null, field)); + } + + private void AddBooleanField(VisualElement parent, string path, string displayName, Func instanceProvider = null, string cacheKey = null, string pathLabelOverride = null, List bindingList = null) + { + instanceProvider ??= GetCurrentInstance; + cacheKey ??= path; + bindingList ??= m_propertyBindings; + + var toggle = new Toggle(); + toggle.RegisterValueChangedCallback(evt => + { + var instance = instanceProvider(); + var prop = instance?.GetBooleanProperty(path); + if (prop != null) + { + prop.Value = evt.newValue; + } + }); + + bindingList.Add(new PropertyBinding + { + Path = cacheKey, + Control = toggle, + Sync = instance => + { + var current = instanceProvider(); + var prop = current?.GetBooleanProperty(path); + toggle.SetEnabled(prop != null); + if (prop != null) + { + toggle.SetValueWithoutNotify(prop.Value); + } + } + }); + + parent.Add(CreatePropertyCard(displayName, pathLabelOverride ?? path, "Boolean", GetDocUrl(ViewModelDataType.Boolean), + null, toggle)); + } + + private void AddColorField(VisualElement parent, string path, string displayName, Func instanceProvider = null, string cacheKey = null, string pathLabelOverride = null, List bindingList = null) + { + instanceProvider ??= GetCurrentInstance; + cacheKey ??= path; + bindingList ??= m_propertyBindings; + + var field = new ColorField(); + field.RegisterValueChangedCallback(evt => + { + var instance = instanceProvider(); + var prop = instance?.GetColorProperty(path); + if (prop != null) + { + prop.Value = evt.newValue; + } + }); + + bindingList.Add(new PropertyBinding + { + Path = cacheKey, + Control = field, + Sync = instance => + { + var current = instanceProvider(); + var prop = current?.GetColorProperty(path); + field.SetEnabled(prop != null); + if (prop != null) + { + field.SetValueWithoutNotify(prop.Value); + } + } + }); + + parent.Add(CreatePropertyCard(displayName, pathLabelOverride ?? path, "Color", GetDocUrl(ViewModelDataType.Color), + null, field)); + } + + private void AddImageField(VisualElement parent, string path, string displayName, Func instanceProvider = null, string cacheKey = null, string pathLabelOverride = null, List bindingList = null) + { + instanceProvider ??= GetCurrentInstance; + cacheKey ??= path; + bindingList ??= m_propertyBindings; + + var field = new ObjectField + { + objectType = typeof(ImageOutOfBandAsset), + allowSceneObjects = false + }; + + field.RegisterValueChangedCallback(evt => + { + var instance = instanceProvider(); + var prop = instance?.GetImageProperty(path); + if (prop == null) + { + return; + } + + var asset = evt.newValue as ImageOutOfBandAsset; + if (asset == null) + { + m_imageSelectionCache[cacheKey] = null; + prop.Value = null; + return; + } + + m_imageSelectionCache[cacheKey] = asset; + asset.Load(); + prop.Value = asset; + asset.Unload(); + }); + + bindingList.Add(new PropertyBinding + { + Path = cacheKey, + Control = field, + Sync = instance => + { + var current = instanceProvider(); + var prop = current?.GetImageProperty(path); + field.SetEnabled(prop != null); + // Reflect cached selection for UX (no getter available from runtime) + if (m_imageSelectionCache.TryGetValue(cacheKey, out var cached)) + { + field.SetValueWithoutNotify(cached); + } + else + { + field.SetValueWithoutNotify(null); + } + } + }); + + parent.Add(CreatePropertyCard(displayName, pathLabelOverride ?? path, "Image", GetDocUrl(ViewModelDataType.AssetImage), + null, field)); + } + + private void AddEnumField(VisualElement parent, string path, FileMetadata.ViewModelPropertyMetadata property, Func instanceProvider = null, string cacheKey = null, string pathLabelOverride = null, List bindingList = null, FileMetadata metadataContext = null) + { + instanceProvider ??= GetCurrentInstance; + cacheKey ??= path; + bindingList ??= m_propertyBindings; + + var options = GetEnumOptions(property, metadataContext) ?? new List(); + var defaultOption = options.Count > 0 ? options[0] : string.Empty; + var popup = new PopupField(null, options, defaultOption); + + popup.RegisterValueChangedCallback(evt => + { + if (string.IsNullOrEmpty(evt.newValue)) + { + return; + } + + var instance = instanceProvider(); + var prop = instance?.GetEnumProperty(path); + if (prop != null) + { + prop.Value = evt.newValue; + } + }); + + bindingList.Add(new PropertyBinding + { + Path = cacheKey, + Control = popup, + Sync = instance => + { + var currentInstance = instanceProvider(); + var prop = currentInstance?.GetEnumProperty(path); + bool hasProp = prop != null; + popup.SetEnabled(hasProp && popup.choices.Count > 0); + + if (!hasProp) + { + return; + } + + var currentValue = prop.Value; + if (!options.Contains(currentValue)) + { + options = prop.EnumValues?.Where(v => !string.IsNullOrEmpty(v)).ToList() ?? options; + popup.choices = options; + popup.SetEnabled(options.Count > 0); + } + + if (!string.IsNullOrEmpty(currentValue) && options.Contains(currentValue)) + { + popup.SetValueWithoutNotify(currentValue); + } + else if (options.Count > 0) + { + popup.SetValueWithoutNotify(options[0]); + } + } + }); + + parent.Add(CreatePropertyCard(property.Name, pathLabelOverride ?? path, $"Enum ({property.EnumTypeName})", GetDocUrl(ViewModelDataType.Enum), + null, popup)); + } + + private ArtboardSelection GetOrCreateArtboardSelection(string path) + { + if (!m_artboardSelectionCache.TryGetValue(path, out var selection)) + { + selection = new ArtboardSelection(); + m_artboardSelectionCache[path] = selection; + } + return selection; + } + + private void DisposeArtboardSelection(string path) + { + if (m_artboardSelectionCache.TryGetValue(path, out var selection)) + { + selection.DisposeAll(); + } + } + + private void AddArtboardField(VisualElement parent, string path, string displayName, Func instanceProvider = null, string cacheKey = null, string pathLabelOverride = null, List bindingList = null) + { + instanceProvider ??= GetCurrentInstance; + cacheKey ??= path; + bindingList ??= m_propertyBindings; + + var selection = GetOrCreateArtboardSelection(cacheKey); + + var assetField = new ObjectField + { + objectType = typeof(Asset), + allowSceneObjects = false, + label = "Rive File", + tooltip = "Select the Rive file containing the desired artboard to bind" + }; + + assetField.style.marginLeft = 0; + + + var artboardDropdown = new DropdownField + { + choices = new List(), + label = "Artboard", + tooltip = "Select the artboard to bind from the selected Rive file", + value = null + }; + + artboardDropdown.style.marginLeft = 0; + + var vmBindingModeOptions = new List { "Use Existing Instance", "New Instance" }; + var vmBindingModeDropdown = new DropdownField( + "View Model Binding", + vmBindingModeOptions, + vmBindingModeOptions[(int)selection.ViewModelBindingMode]) + { + tooltip = "Select whether to bind using a named instance from the selected artboard's default ViewModel or create a new instance" + }; + vmBindingModeDropdown.style.marginLeft = 0; + vmBindingModeDropdown.style.display = DisplayStyle.None; + + var vmInstanceDropdown = new DropdownField + { + choices = new List(), + label = "Instance", + tooltip = "Select a named instance from the artboard's default ViewModel", + value = null + }; + vmInstanceDropdown.style.marginLeft = 0; + vmInstanceDropdown.style.display = DisplayStyle.None; + + var vmHintHelpBox = new HelpBox(string.Empty, HelpBoxMessageType.Info); + vmHintHelpBox.style.display = DisplayStyle.None; + vmHintHelpBox.style.marginTop = 4; + + var customVmContainer = new VisualElement(); + customVmContainer.style.flexDirection = FlexDirection.Column; + customVmContainer.style.display = DisplayStyle.None; + customVmContainer.style.marginTop = 6; + + FileMetadata.ArtboardMetadata GetSelectedArtboardMetadata() + { + var metadata = selection.Asset?.EditorOnlyMetadata; + if (metadata == null || string.IsNullOrEmpty(selection.ArtboardName)) + { + return null; + } + + return metadata.GetArtboard(selection.ArtboardName); + } + + FileMetadata.ViewModelMetadata GetDefaultViewModelMetadata() + { + return GetSelectedArtboardMetadata()?.DefaultViewModel; + } + + ViewModel GetDefaultViewModelFromFile() + { + var vmMeta = GetDefaultViewModelMetadata(); + if (selection.File == null || vmMeta == null || string.IsNullOrEmpty(vmMeta.Name)) + { + return null; + } + + return selection.File.GetViewModelByName(vmMeta.Name); + } + + void EnsureCustomViewModelInstance() + { + if (selection.CustomViewModelInstance != null) + { + return; + } + + var defaultVm = GetDefaultViewModelFromFile(); + if (defaultVm == null) + { + return; + } + + selection.CustomViewModelInstance = defaultVm.CreateInstance(); + } + + void RebuildCustomInstanceEditor() + { + selection.CustomBindings.Clear(); + selection.CustomListBindings.Clear(); + customVmContainer.Clear(); + + var defaultVmMeta = GetDefaultViewModelMetadata(); + if (defaultVmMeta == null || selection.CustomViewModelInstance == null) + { + return; + } + + BuildViewModelSection( + defaultVmMeta, + string.Empty, + customVmContainer, + 0, + () => selection.CustomViewModelInstance, + displayPathPrefix: "custom-instance", + cachePathPrefix: $"{cacheKey}/custom-instance", + bindingList: selection.CustomBindings, + listBindingList: selection.CustomListBindings, + metadataContext: selection.Asset?.EditorOnlyMetadata, + viewModelResolver: name => string.IsNullOrEmpty(name) ? null : selection.File?.GetViewModelByName(name)); + } + + void ApplySelectionToProperty() + { + var instance = instanceProvider(); + var prop = instance?.GetArtboardProperty(path); + if (prop == null) + { + return; + } + + if (selection.File == null || string.IsNullOrEmpty(selection.ArtboardName)) + { + prop.Value = null; + return; + } + + BindableArtboard bindable = null; + var defaultVmMeta = GetDefaultViewModelMetadata(); + bool hasDefaultVm = defaultVmMeta != null && !string.IsNullOrEmpty(defaultVmMeta.Name); + + if (hasDefaultVm) + { + ViewModelInstance targetInstance = null; + if (selection.ViewModelBindingMode == ArtboardViewModelBindingMode.ExistingInstance) + { + var vm = GetDefaultViewModelFromFile(); + if (vm != null && !string.IsNullOrEmpty(selection.ExistingViewModelInstanceName)) + { + targetInstance = vm.CreateInstanceByName(selection.ExistingViewModelInstanceName); + } + } + else + { + EnsureCustomViewModelInstance(); + targetInstance = selection.CustomViewModelInstance; + } + + bindable = selection.File.BindableArtboard(selection.ArtboardName, targetInstance); + } + else + { + bindable = selection.File.BindableArtboard(selection.ArtboardName); + } + + if (bindable != null) + { + prop.Value = bindable; + } + } + + void RefreshViewModelControls() + { + var defaultVmMeta = GetDefaultViewModelMetadata(); + bool hasDefaultVm = defaultVmMeta != null && !string.IsNullOrEmpty(defaultVmMeta.Name); + + vmBindingModeDropdown.style.display = hasDefaultVm ? DisplayStyle.Flex : DisplayStyle.None; + vmHintHelpBox.style.display = hasDefaultVm ? DisplayStyle.None : (selection.Asset == null ? DisplayStyle.None : DisplayStyle.Flex); + vmHintHelpBox.text = "This artboard doesn't support databinding."; + + if (!hasDefaultVm) + { + vmInstanceDropdown.style.display = DisplayStyle.None; + customVmContainer.style.display = DisplayStyle.None; + selection.ExistingViewModelInstanceName = null; + selection.DisposeCustomViewModelInstance(); + return; + } + + var instanceNames = defaultVmMeta.InstanceNames ?? new List(); + vmInstanceDropdown.choices = instanceNames.ToList(); + + if (!string.IsNullOrEmpty(selection.ExistingViewModelInstanceName) && + vmInstanceDropdown.choices.Contains(selection.ExistingViewModelInstanceName)) + { + vmInstanceDropdown.SetValueWithoutNotify(selection.ExistingViewModelInstanceName); + } + else + { + selection.ExistingViewModelInstanceName = vmInstanceDropdown.choices.FirstOrDefault(); + vmInstanceDropdown.SetValueWithoutNotify(selection.ExistingViewModelInstanceName); + } + + vmBindingModeDropdown.SetValueWithoutNotify(vmBindingModeOptions[(int)selection.ViewModelBindingMode]); + bool isExistingMode = selection.ViewModelBindingMode == ArtboardViewModelBindingMode.ExistingInstance; + vmInstanceDropdown.style.display = isExistingMode ? DisplayStyle.Flex : DisplayStyle.None; + vmInstanceDropdown.SetEnabled(isExistingMode && vmInstanceDropdown.choices.Count > 0); + + if (isExistingMode) + { + customVmContainer.style.display = DisplayStyle.None; + } + else + { + EnsureCustomViewModelInstance(); + if (customVmContainer.childCount == 0) + { + RebuildCustomInstanceEditor(); + } + customVmContainer.style.display = selection.CustomViewModelInstance != null + ? DisplayStyle.Flex + : DisplayStyle.None; + } + } + + void PopulateArtboards(Asset asset) + { + artboardDropdown.choices = new List(); + artboardDropdown.value = null; + selection.ArtboardName = null; + artboardDropdown.style.display = asset == null ? DisplayStyle.None : DisplayStyle.Flex; + + if (asset == null) + { + return; + } + + var names = asset.EditorOnlyMetadata?.GetArtboardNames() ?? Array.Empty(); + artboardDropdown.choices = names.ToList(); + + if (names.Length > 0) + { + var chosenArtboard = selection.ArtboardName; + if (string.IsNullOrEmpty(chosenArtboard) || !names.Contains(chosenArtboard)) + { + chosenArtboard = names[0]; + } + selection.ArtboardName = chosenArtboard; + artboardDropdown.value = chosenArtboard; + } + } + + assetField.RegisterValueChangedCallback(evt => + { + var newAsset = evt.newValue as Asset; + if (!ReferenceEquals(selection.Asset, newAsset)) + { + DisposeArtboardSelection(cacheKey); + selection.Asset = newAsset; + selection.File = null; + selection.ArtboardName = null; + } + + PopulateArtboards(newAsset); + + if (newAsset != null) + { + selection.File = File.Load(newAsset); + } + + RefreshViewModelControls(); + ApplySelectionToProperty(); + }); + + artboardDropdown.RegisterValueChangedCallback(evt => + { + selection.ArtboardName = evt.newValue; + selection.DisposeCustomViewModelInstance(); + customVmContainer.Clear(); + RefreshViewModelControls(); + ApplySelectionToProperty(); + }); + + vmBindingModeDropdown.RegisterValueChangedCallback(evt => + { + selection.ViewModelBindingMode = evt.newValue == vmBindingModeOptions[(int)ArtboardViewModelBindingMode.CreateNewInstance] + ? ArtboardViewModelBindingMode.CreateNewInstance + : ArtboardViewModelBindingMode.ExistingInstance; + + if (selection.ViewModelBindingMode == ArtboardViewModelBindingMode.CreateNewInstance) + { + selection.DisposeCustomViewModelInstance(); + customVmContainer.Clear(); + } + + RefreshViewModelControls(); + ApplySelectionToProperty(); + }); + + vmInstanceDropdown.RegisterValueChangedCallback(evt => + { + selection.ExistingViewModelInstanceName = evt.newValue; + ApplySelectionToProperty(); + }); + + bindingList.Add(new PropertyBinding + { + Path = cacheKey, + Control = artboardDropdown, + Sync = instance => + { + var current = instanceProvider(); + var prop = current?.GetArtboardProperty(path); + bool hasProp = prop != null; + assetField.SetEnabled(hasProp); + artboardDropdown.SetEnabled(hasProp && selection.Asset != null); + vmBindingModeDropdown.SetEnabled(hasProp); + artboardDropdown.style.display = selection.Asset == null ? DisplayStyle.None : DisplayStyle.Flex; + + if (assetField.value != selection.Asset) + { + assetField.SetValueWithoutNotify(selection.Asset); + } + + // Ensure file is loaded if we have an asset but no file yet + if (hasProp && selection.Asset != null && selection.File == null) + { + selection.File = File.Load(selection.Asset); + } + + // Populate dropdown if empty but we have asset metadata + if (artboardDropdown.choices.Count == 0 && selection.Asset != null) + { + PopulateArtboards(selection.Asset); + } + + // Keep dropdown selection in sync with cached choice + if (selection.ArtboardName != null && artboardDropdown.value != selection.ArtboardName) + { + artboardDropdown.SetValueWithoutNotify(selection.ArtboardName); + } + + RefreshViewModelControls(); + foreach (var customBinding in selection.CustomBindings) + { + customBinding.Sync?.Invoke(selection.CustomViewModelInstance); + } + foreach (var customListBinding in selection.CustomListBindings) + { + customListBinding.Sync?.Invoke(selection.CustomViewModelInstance); + } + } + }); + + var container = new VisualElement(); + container.style.flexDirection = FlexDirection.Column; + container.Add(assetField); + container.Add(artboardDropdown); + container.Add(vmBindingModeDropdown); + container.Add(vmInstanceDropdown); + container.Add(vmHintHelpBox); + container.Add(customVmContainer); + + parent.Add(CreatePropertyCard(displayName, pathLabelOverride ?? path, "Artboard", GetDocUrl(ViewModelDataType.Artboard), + null, container)); + } + + private void AddTriggerField(VisualElement parent, string path, string displayName, Func instanceProvider = null, string cacheKey = null, string pathLabelOverride = null, List bindingList = null) + { + instanceProvider ??= GetCurrentInstance; + cacheKey ??= path; + bindingList ??= m_propertyBindings; + ViewModelInstanceTriggerProperty subscribedProp = null; + double lastTriggeredAt = -1d; + + var button = new Button(() => + { + var instance = instanceProvider(); + var prop = instance?.GetTriggerProperty(path); + prop?.Trigger(); + }) + { + text = $"Fire Trigger" + }; + + var statusLabel = new Label("Fired"); + statusLabel.style.unityTextAlign = TextAnchor.MiddleCenter; + statusLabel.style.paddingLeft = 8; + statusLabel.style.paddingRight = 8; + statusLabel.style.paddingTop = 2; + statusLabel.style.paddingBottom = 2; + statusLabel.style.marginLeft = 8; + statusLabel.style.borderTopLeftRadius = 4; + statusLabel.style.borderTopRightRadius = 4; + statusLabel.style.borderBottomLeftRadius = 4; + statusLabel.style.borderBottomRightRadius = 4; + statusLabel.style.display = DisplayStyle.None; + + Action onTriggered = () => + { + lastTriggeredAt = EditorApplication.timeSinceStartup; + statusLabel.text = "Fired"; + statusLabel.style.color = new UnityEngine.Color(0.12f, 0.95f, 0.45f, 1f); + statusLabel.style.backgroundColor = new UnityEngine.Color(0.1f, 0.35f, 0.18f, 0.55f); + statusLabel.style.display = DisplayStyle.Flex; + }; + + void UpdateTriggerStatus(bool hasProp) + { + if (!hasProp) + { + statusLabel.style.display = DisplayStyle.None; + return; + } + + bool recentlyFired = lastTriggeredAt >= 0d && + EditorApplication.timeSinceStartup - lastTriggeredAt <= TriggerFiredHighlightSeconds; + statusLabel.style.display = recentlyFired ? DisplayStyle.Flex : DisplayStyle.None; + } + + void DisposeSubscription() + { + if (subscribedProp != null) + { + subscribedProp.OnTriggered -= onTriggered; + subscribedProp = null; + } + } + + m_triggerBindingDisposers.Add(DisposeSubscription); + + bindingList.Add(new PropertyBinding + { + Path = cacheKey, + Control = button, + Sync = instance => + { + var current = instanceProvider(); + var prop = current?.GetTriggerProperty(path); + button.SetEnabled(prop != null); + + if (!ReferenceEquals(subscribedProp, prop)) + { + DisposeSubscription(); + subscribedProp = prop; + if (subscribedProp != null) + { + subscribedProp.OnTriggered += onTriggered; + } + } + + UpdateTriggerStatus(prop != null); + } + }); + + var triggerControlRow = new VisualElement(); + triggerControlRow.style.flexDirection = FlexDirection.Row; + triggerControlRow.style.alignItems = Align.Center; + triggerControlRow.Add(button); + triggerControlRow.Add(statusLabel); + + parent.Add(CreatePropertyCard(displayName, pathLabelOverride ?? path, "Trigger", GetDocUrl(ViewModelDataType.Trigger), + null, triggerControlRow)); + } + + private void ClearTriggerBindings() + { + foreach (var dispose in m_triggerBindingDisposers) + { + dispose?.Invoke(); + } + m_triggerBindingDisposers.Clear(); + } + + private void AddListField( + VisualElement parent, + string path, + string displayName, + Func instanceProvider = null, + string cacheKey = null, + string pathLabelOverride = null, + List listBindingList = null, + FileMetadata metadataContext = null, + Func viewModelResolver = null) + { + instanceProvider ??= GetCurrentInstance; + cacheKey ??= path; + listBindingList ??= m_listBindings; + metadataContext ??= m_fileMetadata; + viewModelResolver ??= name => string.IsNullOrEmpty(name) ? null : m_widget?.File?.GetViewModelByName(name); + + var listContainer = new VisualElement(); + listContainer.style.flexDirection = FlexDirection.Column; + + var vmNames = metadataContext?.ViewModels? + .Select(vm => vm.Name) + .Where(n => !string.IsNullOrEmpty(n)) + .Distinct() + .ToList() ?? new List(); + + var typeRow = new VisualElement { style = { flexDirection = FlexDirection.Row, alignItems = Align.Center } }; + var initialType = vmNames.FirstOrDefault(); + var typeDropdown = new DropdownField("New Item Type", vmNames, initialType) + { + tooltip = "Select the ViewModel type for newly added list items" + }; + + typeDropdown.style.flexGrow = 1; + typeDropdown.style.flexShrink = 1; + typeDropdown.style.marginRight = 6; + typeDropdown.style.marginBottom = 6; + + + typeRow.Add(typeDropdown); + typeRow.style.marginBottom = 4; + listContainer.Add(typeRow); + + var itemBindings = new Dictionary>(); + + ViewModelInstance CreateInstanceForList() + { + string targetType = typeDropdown.value; + var listProp = instanceProvider()?.GetListProperty(path); + if (string.IsNullOrEmpty(targetType)) + { + targetType = listProp?.Count > 0 ? listProp.GetInstanceAt(0)?.ViewModelName : null; + } + + var vm = !string.IsNullOrEmpty(targetType) ? viewModelResolver(targetType) : null; + return vm?.CreateInstance(); + } + + var listView = new ListView + { + reorderable = true, + showAddRemoveFooter = true, + virtualizationMethod = CollectionVirtualizationMethod.DynamicHeight, + selectionType = SelectionType.Single + }; + listView.style.flexGrow = 1; + listView.style.minHeight = 80; + + // Adapter that proxies directly to the live list property to avoid stale counts + var listAdapter = new ListPropertyAdapter( + () => instanceProvider()?.GetListProperty(path), + CreateInstanceForList); + listView.itemsSource = listAdapter; + + listView.makeItem = () => + { + var root = new VisualElement(); + root.style.flexDirection = FlexDirection.Column; + root.style.paddingTop = 6; + root.style.paddingBottom = 6; + root.style.paddingLeft = 4; + root.style.paddingRight = 4; + root.style.borderBottomWidth = 1; + root.style.borderBottomColor = new UnityEngine.Color(0.25f, 0.25f, 0.25f, 0.25f); + return root; + }; + + listView.bindItem = (element, index) => + { + element.Clear(); + var bindings = new List(); + itemBindings[index] = bindings; + + var listProp = instanceProvider()?.GetListProperty(path); + var instance = (listProp != null && index >= 0 && index < listProp.Count) ? listProp.GetInstanceAt(index) : null; + + var header = new VisualElement { style = { flexDirection = FlexDirection.Row, alignItems = Align.Center } }; + var title = new Label(instance?.ViewModelName ?? "Item"); + title.style.unityFontStyleAndWeight = FontStyle.Bold; + title.style.flexGrow = 1; + //header.Add(title); + element.Add(header); + + if (instance == null) + { + element.Add(new HelpBox("List item is null.", HelpBoxMessageType.Warning)); + return; + } + + var meta = FindViewModelMetadata(instance.ViewModelName, metadataContext); + if (meta == null) + { + element.Add(new HelpBox($"No metadata found for '{instance.ViewModelName}'.", HelpBoxMessageType.Warning)); + return; + } + + BuildViewModelSection(meta, string.Empty, element, 1, () => instance, $"{path}[{index}]", $"{path}[{index}]", + bindings, null, metadataContext, viewModelResolver); + }; + + listContainer.Add(listView); + + var listBinding = new ListPropertyBinding + { + Path = cacheKey, + Control = listContainer, + }; + + listBinding.Sync = _ => + { + var listProp = instanceProvider()?.GetListProperty(path); + bool hasProp = listProp != null; + listView.SetEnabled(hasProp); + typeDropdown.SetEnabled(hasProp); + + if (!hasProp) + { + itemBindings.Clear(); + listView.itemsSource = listAdapter; + listView.Rebuild(); + listView.ClearSelection(); + listBinding.LastItems.Clear(); + listBinding.InitializedTypeSelection = false; + return; + } + + // Detect structural changes to avoid unnecessary rebuilds that steal focus + var currentItems = new List(listProp.Count); + for (int i = 0; i < listProp.Count; i++) + { + currentItems.Add(listProp.GetInstanceAt(i)); + } + + bool structureChanged = currentItems.Count != listBinding.LastItems.Count; + if (!structureChanged) + { + for (int i = 0; i < currentItems.Count; i++) + { + if (!ReferenceEquals(currentItems[i], listBinding.LastItems[i])) + { + structureChanged = true; + break; + } + } + } + + if (structureChanged) + { + itemBindings.Clear(); + listView.itemsSource = listAdapter; + listView.Rebuild(); + listView.ClearSelection(); + listBinding.LastItems = currentItems; + } + else + { + listBinding.LastItems = currentItems; + if (listView.selectedIndex >= listProp.Count) + { + listView.ClearSelection(); + } + } + + + string inferred = listProp.Count > 0 ? listProp.GetInstanceAt(0)?.ViewModelName : null; + + if (!listBinding.InitializedTypeSelection) + { + if (!string.IsNullOrEmpty(inferred) && typeDropdown.choices.Contains(inferred)) + { + typeDropdown.SetValueWithoutNotify(inferred); + } + else if (string.IsNullOrEmpty(typeDropdown.value) && typeDropdown.choices.Count > 0) + { + typeDropdown.SetValueWithoutNotify(typeDropdown.choices[0]); + } + + listBinding.InitializedTypeSelection = true; + } + else + { + bool selectionMissing = string.IsNullOrEmpty(typeDropdown.value) || !typeDropdown.choices.Contains(typeDropdown.value); + if (selectionMissing && !string.IsNullOrEmpty(inferred) && typeDropdown.choices.Contains(inferred)) + { + typeDropdown.SetValueWithoutNotify(inferred); + } + } + + foreach (var kvp in itemBindings) + { + var idx = kvp.Key; + if (idx < 0 || idx >= listProp.Count) + { + continue; + } + + var instance = listProp.GetInstanceAt(idx); + foreach (var binding in kvp.Value) + { + binding.Sync?.Invoke(instance); + } + } + }; + + listBindingList.Add(listBinding); + + parent.Add(CreatePropertyCard(displayName, pathLabelOverride ?? path, "List", GetDocUrl(ViewModelDataType.List), + null, listContainer, false)); + } + + private void AddUnsupportedLabel(VisualElement parent, string name, ViewModelDataType type) + { + var label = new Label($"This property type is not configurable in the playground."); + label.style.color = new UnityEngine.Color(0.7f, 0.7f, 0.7f); + parent.Add(CreatePropertyCard(name, name, type.ToString(), GetDocUrl(type), + null, label)); + } + + private void RefreshValues() + { + if (m_isRefreshing) + { + return; + } + + m_isRefreshing = true; + var instance = GetCurrentInstance(); + try + { + foreach (var binding in m_propertyBindings.ToList()) + { + binding.Sync?.Invoke(instance); + } + + foreach (var listBinding in m_listBindings.ToList()) + { + listBinding.Sync?.Invoke(instance); + } + } + finally + { + m_isRefreshing = false; + } + } + + private void UpdateVisibility() + { + string message; + var state = GetPlaygroundState(out message); + bool ready = state == PlaygroundState.Ready; + + if (m_playModeHelpBox != null) + { + m_playModeHelpBox.text = message; + m_playModeHelpBox.style.display = ready ? DisplayStyle.None : DisplayStyle.Flex; + } + + if (m_widgetField != null) + { + // Only show the widget selector while in Play Mode + m_widgetField.style.display = EditorApplication.isPlaying ? DisplayStyle.Flex : DisplayStyle.None; + } + + if (m_interactiveContainer != null) + { + m_interactiveContainer.style.display = ready ? DisplayStyle.Flex : DisplayStyle.None; + } + } + + private PlaygroundState GetPlaygroundState(out string message) + { + if (!EditorApplication.isPlaying) + { + message = "Enter Play Mode to update values in the widget."; + return PlaygroundState.NotPlaying; + } + + if (m_widget == null) + { + message = "Select a RiveWidget to get started."; + return PlaygroundState.NoWidget; + } + + if (m_fileMetadata == null) + { + message = "Selected Rive file has no metadata yet. Reimport or select a Rive asset."; + return PlaygroundState.NoFileMetadata; + } + + if (m_fileMetadata.ViewModels == null || m_fileMetadata.ViewModels.Count == 0) + { + message = "This Rive file has no ViewModels. Add data binding in the Rive Editor to use the playground."; + return PlaygroundState.NoViewModels; + } + + if (m_artboardMetadata == null) + { + message = "No artboard metadata found for the selected widget."; + return PlaygroundState.NoArtboardMetadata; + } + + if (m_artboardMetadata.DefaultViewModel == null) + { + message = "The current artboard has no default ViewModel."; + return PlaygroundState.NoDefaultViewModel; + } + + if (m_widget.Status != WidgetStatus.Loaded || m_widget.StateMachine == null) + { + message = "Widget is not loaded yet."; + return PlaygroundState.WidgetNotLoaded; + } + + if (m_widget.StateMachine.ViewModelInstance == null) + { + message = "No ViewModel instance bound to the state machine."; + return PlaygroundState.NoViewModelInstance; + } + + message = string.Empty; + return PlaygroundState.Ready; + } + + private Button CreateMoreActionsButton(string path, string displayName) + { + var button = new Button(() => + { + var menu = new GenericMenu(); + bool hasIndexPath = !string.IsNullOrEmpty(path) && path.Contains("["); + if (!string.IsNullOrEmpty(path) && !hasIndexPath) + { + menu.AddItem(new GUIContent("Copy Path"), false, () => + { + EditorGUIUtility.systemCopyBuffer = path; + }); + } + else + { + string label = hasIndexPath ? "Copy Path (not supported for list items)" : "Copy Path"; + menu.AddDisabledItem(new GUIContent(label)); + } + + string nameOnly = !string.IsNullOrEmpty(path) ? path.Split('/').Last() : displayName; + menu.AddItem(new GUIContent("Copy Name"), false, () => + { + EditorGUIUtility.systemCopyBuffer = nameOnly; + }); + + menu.ShowAsContext(); + }) + { + text = "⋮", + tooltip = "More actions", + }; + button.style.width = 26; + button.style.marginLeft = 4; + button.style.height = 20; + button.style.backgroundColor = new UnityEngine.Color(0, 0, 0, 0); + button.style.borderLeftWidth = 0; + button.style.borderRightWidth = 0; + button.style.borderTopWidth = 0; + button.style.borderBottomWidth = 0; + button.style.fontSize = 14; + button.style.unityFontStyleAndWeight = FontStyle.Bold; + + button.RegisterCallback(_ => + { + button.style.backgroundColor = new UnityEngine.Color(0.345f, 0.345f, 0.345f, 0.6f); + }); + + button.RegisterCallback(_ => + { + button.style.backgroundColor = new UnityEngine.Color(0, 0, 0, 0); + }); + + return button; + } + + private void StyleLinkLabel(Label label, string url) + { + label.style.fontSize = 11; + var linkColor = new UnityEngine.Color(0.55f, 0.78f, 1f, 1f); + label.style.color = linkColor; + label.style.marginLeft = 6; + // We keep the border width constant to avoid layout shift; toggle only the color. + label.style.borderBottomWidth = 1; + label.style.borderBottomColor = new StyleColor(new UnityEngine.Color(0, 0, 0, 0)); + + label.RegisterCallback(_ => + { + label.style.borderBottomColor = new StyleColor(linkColor); + }); + + label.RegisterCallback(_ => + { + label.style.borderBottomColor = new StyleColor(new UnityEngine.Color(0, 0, 0, 0)); + }); + + label.RegisterCallback(_ => Application.OpenURL(url)); + } + + private ViewModelInstance GetCurrentInstance() + { + return m_widget?.StateMachine?.ViewModelInstance; + } + + private void BuildViewModelSection( + FileMetadata.ViewModelMetadata viewModel, + string accessPathPrefix, + VisualElement parent, + int depth, + Func instanceProvider = null, + string displayPathPrefix = null, + string cachePathPrefix = null, + List bindingList = null, + List listBindingList = null, + FileMetadata metadataContext = null, + Func viewModelResolver = null) + { + instanceProvider ??= GetCurrentInstance; + bindingList ??= m_propertyBindings; + listBindingList ??= m_listBindings; + metadataContext ??= m_fileMetadata; + viewModelResolver ??= name => string.IsNullOrEmpty(name) ? null : m_widget?.File?.GetViewModelByName(name); + + string resolvedDisplayPrefix = displayPathPrefix ?? accessPathPrefix; + string resolvedCachePrefix = cachePathPrefix ?? accessPathPrefix; + string expansionKey = string.IsNullOrEmpty(resolvedCachePrefix) ? "(root)" : resolvedCachePrefix; + + string vmLabel = string.IsNullOrEmpty(accessPathPrefix) + ? (string.IsNullOrEmpty(viewModel.Name) ? "Default ViewModel" : viewModel.Name) + : accessPathPrefix.Split('/').Last(); + + string viewModelNameLabel = string.IsNullOrEmpty(viewModel.Name) ? null : viewModel.Name; + string pathLabel = string.IsNullOrEmpty(resolvedDisplayPrefix) ? "(root)" : resolvedDisplayPrefix; + int childCount = viewModel.Properties?.Count ?? 0; + + bool expanded = m_viewModelExpansion.TryGetValue(expansionKey, out var savedExpanded) + ? savedExpanded + : depth == 0; + + var header = new VisualElement { style = { flexDirection = FlexDirection.Row, alignItems = Align.Center } }; + + var expander = new Button(); + expander.style.width = 20; + expander.style.height = 20; + expander.style.paddingLeft = 0; + expander.style.paddingRight = 0; + expander.style.marginRight = 3; + expander.text = expanded ? "▾" : "▸"; + expander.tooltip = "Expand / collapse view model"; + expander.style.fontSize = 30; + expander.style.backgroundColor = new UnityEngine.Color(0, 0, 0, 0); + expander.style.borderLeftWidth = 0; + expander.style.borderRightWidth = 0; + expander.style.borderTopWidth = 0; + expander.style.borderBottomWidth = 0; + + var vmName = new Label(vmLabel) { style = { unityFontStyleAndWeight = FontStyle.Bold, flexGrow = 1 } }; + + var vmPill = new Label(string.IsNullOrEmpty(viewModelNameLabel) + ? "View Model" + : $"View Model ({viewModelNameLabel})"); + vmPill.style.unityTextAlign = TextAnchor.MiddleCenter; + vmPill.style.paddingLeft = 6; + vmPill.style.paddingRight = 6; + vmPill.style.paddingTop = 2; + vmPill.style.paddingBottom = 2; + vmPill.style.marginLeft = 4; + vmPill.style.borderTopLeftRadius = 4; + vmPill.style.borderTopRightRadius = 4; + vmPill.style.borderBottomLeftRadius = 4; + vmPill.style.borderBottomRightRadius = 4; + vmPill.style.backgroundColor = new UnityEngine.Color(0.25f, 0.25f, 0.35f, 0.9f); + vmPill.style.color = new UnityEngine.Color(0.9f, 0.9f, 1f, 1f); + + var countLabel = new Label($"{childCount} properties"); + countLabel.style.marginLeft = 6; + countLabel.style.fontSize = 11; + countLabel.style.color = new UnityEngine.Color(0.8f, 0.8f, 0.85f, 0.9f); + + header.Add(expander); + header.Add(vmName); + header.Add(vmPill); + header.Add(countLabel); + header.Add(CreateMoreActionsButton(resolvedDisplayPrefix, vmLabel)); + + + var container = new VisualElement(); + container.style.marginLeft = 12; + container.style.marginTop = 8; + container.style.marginBottom = 8; + container.style.display = expanded ? DisplayStyle.Flex : DisplayStyle.None; + container.style.flexDirection = FlexDirection.Column; + + foreach (var property in viewModel.Properties) + { + string propertyAccessPath = string.IsNullOrEmpty(accessPathPrefix) + ? property.Name + : $"{accessPathPrefix}/{property.Name}"; + string propertyDisplayPath = string.IsNullOrEmpty(resolvedDisplayPrefix) + ? property.Name + : $"{resolvedDisplayPrefix}/{property.Name}"; + string propertyCachePath = string.IsNullOrEmpty(resolvedCachePrefix) + ? propertyAccessPath + : $"{resolvedCachePrefix}/{property.Name}"; + + switch (property.Type) + { + case ViewModelDataType.String: + AddStringField(container, propertyAccessPath, property.Name, instanceProvider, propertyCachePath, propertyDisplayPath, bindingList); + break; + case ViewModelDataType.Number: + AddNumberField(container, propertyAccessPath, property.Name, instanceProvider, propertyCachePath, propertyDisplayPath, bindingList); + break; + case ViewModelDataType.Boolean: + AddBooleanField(container, propertyAccessPath, property.Name, instanceProvider, propertyCachePath, propertyDisplayPath, bindingList); + break; + case ViewModelDataType.Color: + AddColorField(container, propertyAccessPath, property.Name, instanceProvider, propertyCachePath, propertyDisplayPath, bindingList); + break; + case ViewModelDataType.AssetImage: + AddImageField(container, propertyAccessPath, property.Name, instanceProvider, propertyCachePath, propertyDisplayPath, bindingList); + break; + case ViewModelDataType.Artboard: + AddArtboardField(container, propertyAccessPath, property.Name, instanceProvider, propertyCachePath, propertyDisplayPath, bindingList); + break; + case ViewModelDataType.Enum: + AddEnumField(container, propertyAccessPath, property, instanceProvider, propertyCachePath, propertyDisplayPath, bindingList, metadataContext); + break; + case ViewModelDataType.Trigger: + AddTriggerField(container, propertyAccessPath, property.Name, instanceProvider, propertyCachePath, propertyDisplayPath, bindingList); + break; + case ViewModelDataType.ViewModel: + var nestedMeta = FindViewModelMetadata(property.NestedViewModelName, metadataContext); + if (nestedMeta != null) + { + BuildViewModelSection(nestedMeta, propertyAccessPath, container, depth + 1, instanceProvider, propertyDisplayPath, propertyCachePath, + bindingList, listBindingList, metadataContext, viewModelResolver); + } + else + { + var missingLabel = new Label($"Nested view model '{property.NestedViewModelName}' not found."); + missingLabel.style.color = UnityEngine.Color.yellow; + container.Add(missingLabel); + } + break; + case ViewModelDataType.List: + AddListField(container, propertyAccessPath, property.Name, instanceProvider, propertyCachePath, propertyDisplayPath, + listBindingList, metadataContext, viewModelResolver); + break; + case ViewModelDataType.ListIndex: + AddUnsupportedLabel(container, property.Name, property.Type); + break; + default: + AddUnsupportedLabel(container, property.Name, property.Type); + break; + } + } + + void ToggleExpanded() + { + expanded = !expanded; + container.style.display = expanded ? DisplayStyle.Flex : DisplayStyle.None; + expander.text = expanded ? "▾" : "▸"; + m_viewModelExpansion[expansionKey] = expanded; + } + + expander.clicked += ToggleExpanded; + + // wrap in a card for clarity + var vmCard = new VisualElement(); + vmCard.style.marginTop = depth == 0 ? 8 : 4; + vmCard.style.paddingTop = 8; + vmCard.style.paddingBottom = 8; + vmCard.style.paddingLeft = 8; + vmCard.style.paddingRight = 8; + vmCard.style.borderTopWidth = 1; + vmCard.style.borderBottomWidth = 1; + vmCard.style.borderLeftWidth = 1; + vmCard.style.borderRightWidth = 1; + vmCard.style.borderTopColor = new UnityEngine.Color(0.344f, 0.344f, 0.349f, 0.5f); + vmCard.style.borderBottomColor = new UnityEngine.Color(0.344f, 0.344f, 0.349f, 0.5f); + vmCard.style.borderLeftColor = new UnityEngine.Color(0.344f, 0.344f, 0.349f, 0.5f); + vmCard.style.borderRightColor = new UnityEngine.Color(0.344f, 0.344f, 0.349f, 0.5f); + vmCard.style.backgroundColor = new UnityEngine.Color(0.145f, 0.145f, 0.152f, 0.55f); + vmCard.style.borderTopLeftRadius = 6; + vmCard.style.borderTopRightRadius = 6; + vmCard.style.borderBottomLeftRadius = 6; + vmCard.style.borderBottomRightRadius = 6; + + vmCard.Add(header); + vmCard.Add(container); + + parent.Add(vmCard); + } + + private string GetDocUrl(ViewModelDataType type) + { + switch (type) + { + case ViewModelDataType.String: + return InspectorDocLinks.UnityDataBindingProperties; + case ViewModelDataType.Number: + return InspectorDocLinks.UnityDataBindingProperties; + case ViewModelDataType.Boolean: + return InspectorDocLinks.UnityDataBindingProperties; + case ViewModelDataType.Color: + return InspectorDocLinks.UnityDataBindingProperties; + case ViewModelDataType.Trigger: + return InspectorDocLinks.UnityDataBindingProperties; + case ViewModelDataType.Enum: + return InspectorDocLinks.UnityDataBindingEnums; + case ViewModelDataType.ViewModel: + return InspectorDocLinks.UnityDataBindingViewModel; + case ViewModelDataType.AssetImage: + return InspectorDocLinks.UnityDataBindingImages; + case ViewModelDataType.List: + return InspectorDocLinks.UnityDataBindingLists; + case ViewModelDataType.ListIndex: + return InspectorDocLinks.UnityDataBindingListViewModelIndex; + case ViewModelDataType.Artboard: + return InspectorDocLinks.UnityDataBindingArtboards; + default: + return InspectorDocLinks.UnityDataBinding; + } + } + + private VisualElement CreatePropertyCard(string displayName, string path, string typeLabel, string docUrl, string description, VisualElement control, bool showTypePill = false) + { + var card = new VisualElement(); + card.style.marginTop = 6; + card.style.paddingTop = 8; + card.style.paddingBottom = 8; + card.style.paddingLeft = 10; + card.style.paddingRight = 10; + card.style.borderTopLeftRadius = 6; + card.style.borderTopRightRadius = 6; + card.style.borderBottomLeftRadius = 6; + card.style.borderBottomRightRadius = 6; + card.style.borderBottomWidth = 1; + card.style.borderTopWidth = 1; + card.style.borderLeftWidth = 1; + card.style.borderRightWidth = 1; + card.style.borderBottomColor = new UnityEngine.Color(0.25f, 0.25f, 0.25f, 0.4f); + card.style.borderTopColor = new UnityEngine.Color(0.25f, 0.25f, 0.25f, 0.4f); + card.style.borderLeftColor = new UnityEngine.Color(0.25f, 0.25f, 0.25f, 0.4f); + card.style.borderRightColor = new UnityEngine.Color(0.25f, 0.25f, 0.25f, 0.4f); + card.style.backgroundColor = new UnityEngine.Color(0.12f, 0.12f, 0.12f, 0.45f); + + var header = new VisualElement { style = { flexDirection = FlexDirection.Row, alignItems = Align.Center } }; + var nameLabel = new Label(displayName); + nameLabel.style.unityFontStyleAndWeight = FontStyle.Bold; + nameLabel.style.flexGrow = 1; + + if (showTypePill && !string.IsNullOrEmpty(typeLabel)) + { + var typePill = new Label(typeLabel); + typePill.style.unityTextAlign = TextAnchor.MiddleCenter; + typePill.style.paddingLeft = 6; + typePill.style.paddingRight = 6; + typePill.style.paddingTop = 2; + typePill.style.paddingBottom = 2; + typePill.style.marginLeft = 4; + typePill.style.borderTopLeftRadius = 4; + typePill.style.borderTopRightRadius = 4; + typePill.style.borderBottomLeftRadius = 4; + typePill.style.borderBottomRightRadius = 4; + typePill.style.backgroundColor = new UnityEngine.Color(0.25f, 0.25f, 0.25f, 0.8f); + typePill.style.color = new UnityEngine.Color(0.85f, 0.85f, 0.85f, 1f); + header.Add(typePill); + } + + var menuButton = CreateMoreActionsButton(path, displayName); + + // Remove potential parenthesis text to account for enum values. E.g. "Enum (MyEnum)" should be "Enum" + string strippedTypeLabel = typeLabel; + if (!string.IsNullOrEmpty(strippedTypeLabel)) + { + int parenIndex = strippedTypeLabel.IndexOf(" (", StringComparison.Ordinal); + if (parenIndex > 0) + { + strippedTypeLabel = strippedTypeLabel.Substring(0, parenIndex); + } + } + + string docLabel = string.IsNullOrEmpty(typeLabel) ? "Docs" : $"{strippedTypeLabel} Property Documentation"; + var docButton = new Label(docLabel); + StyleLinkLabel(docButton, docUrl); + docButton.style.marginLeft = 6; + docButton.style.alignSelf = Align.Center; + docButton.style.display = DisplayStyle.None; + + header.Add(nameLabel); + header.Add(docButton); + header.Add(menuButton); + + card.Add(header); + + card.RegisterCallback(_ => + { + docButton.style.display = DisplayStyle.Flex; + }); + + card.RegisterCallback(_ => + { + docButton.style.display = DisplayStyle.None; + }); + + string pathLineText = null; + if (!showTypePill) + { + pathLineText = $"{typeLabel}"; + } + else if (!string.IsNullOrEmpty(path)) + { + pathLineText = $"Path: {path}"; + } + + if (!string.IsNullOrEmpty(pathLineText)) + { + var pathLabel = new Label(pathLineText); + pathLabel.style.fontSize = 11; + pathLabel.style.color = new UnityEngine.Color(0.75f, 0.75f, 0.75f, 0.9f); + pathLabel.style.marginTop = 2; + card.Add(pathLabel); + } + + if (!string.IsNullOrEmpty(description)) + { + var desc = new Label(description); + desc.style.fontSize = 11; + desc.style.color = new UnityEngine.Color(0.8f, 0.8f, 0.8f, 0.95f); + desc.style.marginTop = 4; + card.Add(desc); + } + + control.style.marginTop = 6; + card.Add(control); + + return card; + } + } +} + diff --git a/Packages/app.rive.rive-unity/Editor/Components/DataBindingPlaygroundWindow.cs.meta b/Packages/app.rive.rive-unity/Editor/Components/DataBindingPlaygroundWindow.cs.meta new file mode 100644 index 00000000..1cee062d --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Components/DataBindingPlaygroundWindow.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: f3793298efdc946ffb5185da184f3cf6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Editor/Components/DataBindingPlaygroundWindow.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Editor/Components/MenuItems.cs b/Packages/app.rive.rive-unity/Editor/Components/MenuItems.cs new file mode 100644 index 00000000..a916a810 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Components/MenuItems.cs @@ -0,0 +1,383 @@ +using System.Runtime.CompilerServices; +using Rive.Components; +using UnityEditor; +using UnityEngine; +using UnityEngine.UI; + +[assembly: InternalsVisibleTo("Rive.Tests.Editor")] +namespace Rive.EditorTools +{ + /// + /// Custom menu items for creating Rive components. + /// + //Make internals visible to test assembly + internal class MenuItems + { + internal enum PanelContext + { + Standalone = 0, + Canvas = 1 + } + + [MenuItem("GameObject/Rive/Rive Panel", false, 10)] + static void CreateRivePanel(MenuCommand menuCommand) => + CreateRivePanelInternal(menuCommand, PanelContext.Standalone); + + [MenuItem("GameObject/Rive/Rive Panel (Canvas)", false, 11)] + static void CreateRivePanelWithCanvas(MenuCommand menuCommand) => + CreateRivePanelInternal(menuCommand, PanelContext.Canvas); + + [MenuItem("GameObject/Rive/Widgets/Rive Widget", false, 12)] + static void CreateRiveWidget(MenuCommand menuCommand) + { + GameObject widgetObj = new GameObject("Rive Widget", typeof(RiveWidget)); + + // If we have a context (selected object), try to parent to it + GameObject parent = menuCommand.context as GameObject; + if (parent != null) + { + GameObjectUtility.SetParentAndAlign(widgetObj, parent); + + ConfigureRectTransformToFill(widgetObj.GetComponent()); + + } + + Undo.RegisterCreatedObjectUndo(widgetObj, "Create Rive Widget"); + Selection.activeObject = widgetObj; + } + + [MenuItem("GameObject/Rive/Widgets/Procedural Rive Widget", false, 13)] + static void CreateProceduralRiveWidget(MenuCommand menuCommand) + { + GameObject widgetObj = new GameObject("Procedural Rive Widget", typeof(ProceduralRiveWidget)); + + // If we have a context (selected object), try to parent to it + GameObject parent = menuCommand.context as GameObject; + if (parent != null) + { + GameObjectUtility.SetParentAndAlign(widgetObj, parent); + + ConfigureRectTransformToFill(widgetObj.GetComponent()); + + } + + Undo.RegisterCreatedObjectUndo(widgetObj, "Create Procedural Rive Widget"); + Selection.activeObject = widgetObj; + } + + + + [MenuItem("GameObject/Rive/Render Target Strategies/Atlas Render Target Strategy", false, 21)] + static void CreateAtlasRenderTargetStrategy(MenuCommand menuCommand) => + CreateRenderTargetStrategy(menuCommand); + + [MenuItem("GameObject/Rive/Render Target Strategies/Pooled Render Target Strategy", false, 22)] + static void CreatePooledRenderTargetStrategy(MenuCommand menuCommand) => + CreateRenderTargetStrategy(menuCommand); + + private static void CreateRenderTargetStrategy(MenuCommand menuCommand) where T : RenderTargetStrategy + { + string typeName = typeof(T).Name; + string objectName = ObjectNames.NicifyVariableName(typeName); + + GameObject obj = new GameObject(objectName, typeof(T)); + GameObjectUtility.SetParentAndAlign(obj, menuCommand.context as GameObject); + + Undo.RegisterCreatedObjectUndo(obj, $"Create {objectName}"); + Selection.activeObject = obj; + } + + internal static RivePanel CreateRivePanelInternal(MenuCommand menuCommand, PanelContext context) + { + GameObject rootObject; + GameObject panelObj; + + if (context == PanelContext.Canvas) + { + // Check if we already have a canvas parent + Canvas parentCanvas = null; + GameObject contextObj = menuCommand.context as GameObject; + if (contextObj != null) + { + parentCanvas = contextObj.GetComponentInParent(); + } + + if (parentCanvas != null) + { + // Use existing canvas as root + rootObject = parentCanvas.gameObject; + } + else + { + // Create new canvas + rootObject = new GameObject("Canvas", typeof(Canvas), typeof(CanvasScaler), typeof(GraphicRaycaster)); + GameObjectUtility.SetParentAndAlign(rootObject, contextObj); + rootObject.GetComponent().renderMode = RenderMode.ScreenSpaceOverlay; + } + + panelObj = new GameObject("Rive Panel", typeof(RivePanel), typeof(RiveCanvasRenderer)); + panelObj.transform.SetParent(rootObject.transform, false); + + var renderer = panelObj.GetComponent(); + renderer.RivePanel = panelObj.GetComponent(); + + // Canvas panel fills parent + ConfigureRectTransformToFill(panelObj.GetComponent()); + } + else + { + panelObj = new GameObject("Rive Panel", typeof(RectTransform), typeof(RivePanel)); + GameObjectUtility.SetParentAndAlign(panelObj, menuCommand.context as GameObject); + rootObject = panelObj; + + // Standalone panel uses absolute size + panelObj.GetComponent().SetDimensions(new Vector2(1920, 1080)); + } + + // Temporarily disable so that re-enabling the gameobjects triggers a refresh when everything is set up. Otherwise, the RivePanel might not be initialized correctly for editor preview. + panelObj.SetActive(false); + + // Create and configure widget. We also want it to fill the parent. + GameObject widgetObj = new GameObject("Rive Widget", typeof(RectTransform), typeof(RiveWidget)); + widgetObj.transform.SetParent(panelObj.transform, false); + ConfigureRectTransformToFill(widgetObj.GetComponent()); + + // Re-enable panel after everything is set up so that the editor preview has enough information to render the panel + panelObj.SetActive(true); + + // Register undo and select the panel so that the user can start editing it right away + Undo.RegisterCreatedObjectUndo(rootObject, $"Create Rive Panel{(context == PanelContext.Canvas ? " with Canvas" : "")}"); + Selection.activeObject = widgetObj; + + return panelObj.GetComponent(); + } + + internal static void ConfigureRectTransformToFill(RectTransform rect) + { + rect.anchorMin = Vector2.zero; + rect.anchorMax = Vector2.one; + rect.sizeDelta = Vector2.zero; + } + + + [InitializeOnLoadMethod] + static void OnLoad() + { +#if UNITY_6000_3_OR_NEWER + DragAndDrop.AddDropHandlerV2(OnSceneDrop); + DragAndDrop.AddDropHandlerV2(OnHierarchyDropV2); +#else + DragAndDrop.AddDropHandler(OnSceneDrop); + DragAndDrop.AddDropHandler(OnHierarchyDrop); +#endif + } + + private static bool ValidateRiveAssetDrag() + { + if (DragAndDrop.objectReferences.Length != 1) + return false; + + return DragAndDrop.objectReferences[0] is Asset; + } + + private static DragAndDropVisualMode OnSceneDrop(Object dropUpon, Vector3 worldPosition, Vector2 viewportPosition, Transform parentForDraggedObjects, bool perform) + { + if (!ValidateRiveAssetDrag()) + { + return DragAndDropVisualMode.None; + } + + if (perform) + { + Asset riveAsset = DragAndDrop.objectReferences[0] as Asset; + + if (riveAsset == null) + return DragAndDropVisualMode.Rejected; + + GameObject parentObject = dropUpon as GameObject; + Transform parentTransform = parentObject != null ? parentObject.transform : null; + HandleAssetDrop(riveAsset, parentTransform); + } + return DragAndDropVisualMode.Move; + } + + private static UnityEngine.EventSystems.EventSystem GetExistingEventSystem() + { + +#if UNITY_6000_0_OR_NEWER + return Object.FindFirstObjectByType(); +#else + return Object.FindObjectOfType(); +#endif + + } + + private static void EnsureEventSystemExists() + { + + if (GetExistingEventSystem() == null) + { + GameObject eventSystem = new GameObject("EventSystem", + typeof(UnityEngine.EventSystems.EventSystem), + typeof(UnityEngine.EventSystems.StandaloneInputModule)); + + Undo.RegisterCreatedObjectUndo(eventSystem, "Create EventSystem"); + } + } + + /// + /// Handles dropping a Rive asset onto a game object in the heirarchy/scene. + /// + /// The Rive asset to drop. + /// The parent transform to drop the asset under. + internal static void HandleAssetDrop(Asset riveAsset, Transform parent) + { + // If the RivePanel is just dropped into the scene, we want to create a standalone panel that displays within a canvas. + // However, when the panel is dropped onto a game object with a MeshRenderer, we want to create a standalone RivePanel, then add a RiveTextureRenderer to the meshrenderer game object. + + // Create a group for all undo operations so we can collapse them into a single undo step at the end + Undo.IncrementCurrentGroup(); + var undoGroupIndex = Undo.GetCurrentGroup(); + + // Check if we're dropping onto or under an existing RivePanel + RivePanel existingPanel = null; + if (parent != null) + { + existingPanel = parent.GetComponent(); + + + if (existingPanel == null) + { + + existingPanel = parent.GetComponentInParent(); + } + + + } + + // If we're under an existing panel, we want to create a widget under it, instead of creating a new panel. + if (existingPanel != null) + { + + RiveWidget parentWidget = parent.GetComponentInParent(); + + // If the parent is a widget, we want to create the new widget as a sibling to the parent widget. + // Nesting widgets works, but we don't want to encourage it as it might lead to unexpected behavior. + Transform parentTransform = parentWidget != null ? parentWidget.transform.parent : parent; + + GameObject widgetObj = new GameObject("Rive Widget", typeof(RiveWidget)); + GameObjectUtility.SetParentAndAlign(widgetObj, parentTransform.gameObject); + ConfigureRectTransformToFill(widgetObj.GetComponent()); + + var riveWidget = widgetObj.GetComponent(); + Undo.RecordObject(riveWidget, "Set Rive Asset Reference"); + riveWidget.SetEditorAssetReference(riveAsset); + + Undo.RegisterCreatedObjectUndo(widgetObj, "Create Rive Widget"); + Selection.activeObject = widgetObj; + + Undo.CollapseUndoOperations(undoGroupIndex); + return; + } + + + PanelContext context = PanelContext.Canvas; + GameObject parentGameObject = parent != null ? parent.gameObject : null; + GameObject meshRendererGameObject = parentGameObject; + + if (parent != null) + { + if (parentGameObject.GetComponent() != null) + { + context = PanelContext.Standalone; + + // We also clear the parent object so that the panel is created as a standalone object in the scene + // This might change in the future, but we do this to avoid a bunch of issues that might come from the parent potentially having non-uniform scale, which would affect the RivePanel's rendering. + // We also want to avoid unnecessarily re-drawing the panel when the parent object transform is updated. + parentGameObject = null; + } + } + + + + RivePanel panel = CreateRivePanelInternal(new MenuCommand(parentGameObject), context); + Undo.RegisterFullObjectHierarchyUndo(panel.gameObject, "Create Rive Panel"); + + var widget = panel.GetComponentInChildren(); + if (widget != null) + { + Undo.RecordObject(widget, "Set Rive Asset Reference"); + widget.SetEditorAssetReference(riveAsset); + } + + if (context == PanelContext.Standalone && meshRendererGameObject != null) + { + if (meshRendererGameObject != null) + { + // Add a RiveTextureRenderer to the meshRendererGameObject object so that the RivePanel is rendered there. + RiveTextureRenderer textureRenderer; + if (!meshRendererGameObject.TryGetComponent(out textureRenderer)) + { + textureRenderer = Undo.AddComponent(meshRendererGameObject); + } + + Undo.RecordObject(textureRenderer, "Set Rive Panel Reference"); + textureRenderer.RivePanel = panel; + } + + // Set the Panel dimensions to match the default Artboard's size so that the RivePanel is rendered with the correct aspect ratio. + if (riveAsset.EditorOnlyMetadata.Artboards.Count > 0) + { + + FileMetadata.ArtboardMetadata defaultArtboard = riveAsset.EditorOnlyMetadata.Artboards[0]; + + panel.SetDimensions(new Vector2(defaultArtboard.Width, defaultArtboard.Height)); + } + } + + // Ensure we have an EventSystem in the scene so that the RivePanel can receive input events + EnsureEventSystemExists(); + + // Collapse all operations into a single undo step + Undo.CollapseUndoOperations(undoGroupIndex); + } + + private static DragAndDropVisualMode HandleHierarchyDrop(GameObject parentObject, bool perform) + { + if (!ValidateRiveAssetDrag()) + { + // If we don't do this, it breaks regular drag and drop in the hierarchy + // e.g. dragging a game object into another game object stops working + return DragAndDropVisualMode.None; + } + + if (perform) + { + Asset riveAsset = DragAndDrop.objectReferences[0] as Asset; + + if (riveAsset == null) + return DragAndDropVisualMode.Rejected; + + Transform parentTransform = parentObject != null ? parentObject.transform : null; + HandleAssetDrop(riveAsset, parentTransform); + } + + return DragAndDropVisualMode.Move; + } + +#if UNITY_6000_3_OR_NEWER + private static DragAndDropVisualMode OnHierarchyDropV2(EntityId dropTargetEntityId, HierarchyDropFlags dropMode, Transform parentForDraggedObjects, bool perform) + { + GameObject parentObject = EditorUtility.EntityIdToObject(dropTargetEntityId) as GameObject; + return HandleHierarchyDrop(parentObject, perform); + } +#else + private static DragAndDropVisualMode OnHierarchyDrop(int dropTargetInstanceID, HierarchyDropFlags dropMode, Transform parentForDraggedObjects, bool perform) + { + GameObject parentObject = EditorUtility.InstanceIDToObject(dropTargetInstanceID) as GameObject; + return HandleHierarchyDrop(parentObject, perform); + } +#endif + + } +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Editor/Components/MenuItems.cs.meta b/Packages/app.rive.rive-unity/Editor/Components/MenuItems.cs.meta new file mode 100644 index 00000000..635ad227 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Components/MenuItems.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 3644f9a909df34335a9332c966ac74d1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Editor/Components/MenuItems.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Editor/Components/PanelContextPreviewManagerEditor.cs b/Packages/app.rive.rive-unity/Editor/Components/PanelContextPreviewManagerEditor.cs new file mode 100644 index 00000000..1eaca4a4 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Components/PanelContextPreviewManagerEditor.cs @@ -0,0 +1,14 @@ +using System.Collections; +using System.Collections.Generic; +using Rive.Components; +using UnityEditor; +using UnityEngine; + +namespace Rive.EditorTools +{ + [CustomEditor(typeof(PanelContextPreviewManager), true)] + internal class PanelContextPreviewManagerEditor : RiveBaseEditor + { + + } +} diff --git a/Packages/app.rive.rive-unity/Editor/Components/PanelContextPreviewManagerEditor.cs.meta b/Packages/app.rive.rive-unity/Editor/Components/PanelContextPreviewManagerEditor.cs.meta new file mode 100644 index 00000000..7b928dbf --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Components/PanelContextPreviewManagerEditor.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: a28b8f2410fbe4723957384e2cc23554 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Editor/Components/PanelContextPreviewManagerEditor.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Editor/Components/PanelRendererInspector.cs b/Packages/app.rive.rive-unity/Editor/Components/PanelRendererInspector.cs new file mode 100644 index 00000000..7649ec7b --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Components/PanelRendererInspector.cs @@ -0,0 +1,14 @@ +using Rive.Components; +using UnityEditor; + + +namespace Rive.EditorTools +{ + [CustomEditor(typeof(PanelRenderer), true)] + internal class PanelRendererInspector : RiveBaseEditor + { + + protected PanelRenderer PanelRenderer => target as PanelRenderer; + + } +} diff --git a/Packages/app.rive.rive-unity/Editor/Components/PanelRendererInspector.cs.meta b/Packages/app.rive.rive-unity/Editor/Components/PanelRendererInspector.cs.meta new file mode 100644 index 00000000..992181a6 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Components/PanelRendererInspector.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 858abbdc5eb964808a982516a48d13d3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Editor/Components/PanelRendererInspector.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Editor/Components/PooledRenderTextureStrategyInspector.cs b/Packages/app.rive.rive-unity/Editor/Components/PooledRenderTextureStrategyInspector.cs new file mode 100644 index 00000000..27d780ef --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Components/PooledRenderTextureStrategyInspector.cs @@ -0,0 +1,11 @@ +using Rive.Components; +using UnityEditor; + +namespace Rive.EditorTools +{ + [CustomEditor(typeof(PooledRenderTargetStrategy), true)] + internal class PooledRenderTextureStrategyInspector : RiveBaseEditor + { + + } +} diff --git a/Packages/app.rive.rive-unity/Editor/Components/PooledRenderTextureStrategyInspector.cs.meta b/Packages/app.rive.rive-unity/Editor/Components/PooledRenderTextureStrategyInspector.cs.meta new file mode 100644 index 00000000..9ce00a58 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Components/PooledRenderTextureStrategyInspector.cs.meta @@ -0,0 +1,20 @@ +fileFormatVersion: 2 +guid: 46a5871697e4343d8a234cc693c64687 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: + - m_styleSheet: {fileID: 7433441132597879392, guid: cc66ac87f8ecb4e3c91384370163ee7b, + type: 3} + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Editor/Components/PooledRenderTextureStrategyInspector.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Editor/Components/Rive.Editor.Components.asmdef b/Packages/app.rive.rive-unity/Editor/Components/Rive.Editor.Components.asmdef new file mode 100644 index 00000000..ca518cf1 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Components/Rive.Editor.Components.asmdef @@ -0,0 +1,28 @@ +{ + "name": "Rive.Editor.Components", + "rootNamespace": "Rive.EditorTools.Components", + "references": [ + "GUID:e11e939ddee8146e1976384f79284b41", + "GUID:4d624505c28284c90a482e4d6ec34ada", + "GUID:0a82aeb665886483c867b7d137563619" + ], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [ + "RIVE_USING_UGUI" + ], + "versionDefines": [ + { + "name": "com.unity.ugui", + "expression": "1.0.0", + "define": "RIVE_USING_UGUI" + } + ], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Editor/Components/Rive.Editor.Components.asmdef.meta b/Packages/app.rive.rive-unity/Editor/Components/Rive.Editor.Components.asmdef.meta new file mode 100644 index 00000000..a02a5577 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Components/Rive.Editor.Components.asmdef.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 4a6f82b4f2b19414aa4548e19d8ad1b8 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Editor/Components/Rive.Editor.Components.asmdef + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Editor/Components/RiveBaseEditor.cs b/Packages/app.rive.rive-unity/Editor/Components/RiveBaseEditor.cs new file mode 100644 index 00000000..7042c977 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Components/RiveBaseEditor.cs @@ -0,0 +1,445 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using Rive.Utils; +using UnityEditor; +using UnityEditor.UIElements; +using UnityEngine; +using UnityEngine.UIElements; + +namespace Rive.EditorTools +{ +#if UNITY_EDITOR + /// + /// Base class for custom inspectors for Rive components. + /// + internal class RiveBaseEditor : Editor + { + protected VisualElement rootElement; + + private GameObject m_gameObject; + + private Dictionary sections = new Dictionary(); + + protected virtual void OnEnable() + { + if (target is MonoBehaviour) + { + m_gameObject = (target as MonoBehaviour).gameObject; + } + + + // Using Editor.update, queue a repaint for the next frame to hide components + // Hiding immediately causes issues with the inspector layout + EditorApplication.update += FirstRepaint; + + } + + private void FirstRepaint() + { + HandleHideComponents(); + + EditorApplication.update -= FirstRepaint; + + } + + + private void HandleHideComponents() + { + var hideComponentsAttrs = target.GetType().GetCustomAttributes(); + var targetComponent = target as MonoBehaviour; + + if (targetComponent != null) + { + foreach (var attr in hideComponentsAttrs) + { + CustomInspectorUtils.HideNonInteractiveComponents( + targetComponent, + new List(attr.ComponentTypes), + this, + attr.HideFlags + ); + } + + } + } + + + + public override VisualElement CreateInspectorGUI() + { + rootElement = new VisualElement(); + rootElement.styleSheets.Add(StyleHelper.StyleSheet); + rootElement.AddToClassList("rive-inspector"); + + var serializedFields = GetSerializedFields(); + + // Get all fields with InspectorFieldAttribute + var attributeFields = serializedFields + .Where(f => f.GetCustomAttribute() != null) + .OrderBy(f => f.GetCustomAttribute().Order); + + // Split into fields with and without sections + var sectionFields = attributeFields.Where(f => + !string.IsNullOrEmpty(f.GetCustomAttribute().SectionId)); + var nonSectionFields = attributeFields.Where(f => + string.IsNullOrEmpty(f.GetCustomAttribute().SectionId)); + + // Get fields without any attributes + var plainFields = serializedFields + .Except(attributeFields); + + // Process non-sectioned fields first (both plain and attributed) + foreach (var field in plainFields.Concat(nonSectionFields)) + { + var attr = field.GetCustomAttribute(); + CreateFieldElement(field, attr, rootElement); + } + + // Get sections that have fields + var usedSectionIds = sectionFields + .Select(f => f.GetCustomAttribute().SectionId) + .Distinct() + .ToHashSet(); + + CreateSections(usedSectionIds); + + foreach (var field in sectionFields) + { + var attr = field.GetCustomAttribute(); + var container = sections[attr.SectionId]; + CreateFieldElement(field, attr, container); + } + + + return rootElement; + } + + + private HashSet GetSerializedFields() + { + var fields = new HashSet(); + var currentType = target.GetType(); + + // Walk up the inheritance chain until we hit MonoBehaviour + while (currentType != typeof(MonoBehaviour) && currentType != null) + { + var typeFields = currentType + .GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly) + .Where(f => + (f.GetCustomAttribute() != null || f.IsPublic) && + f.GetCustomAttribute() == null && + IsUnitySerializable(f.FieldType)); // check for Unity-serializable types + + foreach (var field in typeFields) + { + fields.Add(field); + } + + currentType = currentType.BaseType; + } + + return fields; + } + + // Helper method to check if a type is serializable by Unity. We do this to avoid types like Actions, Funcs, etc not showing up in the inspector but still taking up space. + private bool IsUnitySerializable(Type type) + { + if (type == null) return false; + + if (Attribute.IsDefined(type, typeof(SerializableAttribute))) + return true; + + if (type.IsPrimitive || type == typeof(string) || type == typeof(decimal)) + return true; + + if (typeof(UnityEngine.Object).IsAssignableFrom(type)) + return true; + + if (type.IsEnum) + return true; + + if (type.IsValueType && !type.IsPrimitive) + return true; + + if (typeof(UnityEngine.Events.UnityEventBase).IsAssignableFrom(type)) + return true; + + if (type.IsArray) + return IsUnitySerializable(type.GetElementType()); + if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>)) + return IsUnitySerializable(type.GetGenericArguments()[0]); + + + return false; + } + + private void CreateSections(HashSet usedSectionIds) + { + var sectionAttrs = target.GetType() + .GetCustomAttributes() + .OrderBy(s => s.Order); + + foreach (var attr in sectionAttrs) + { + // Only create sections that have fields + if (!usedSectionIds.Contains(attr.Id)) + { + continue; + } + + VisualElement section; + switch (attr.Style) + { + case SectionStyle.Foldout: + var foldout = new Foldout { text = attr.DisplayName }; + foldout.viewDataKey = $"RiveFoldout_{target.GetType().Name}_{attr.Id}"; + // The initial value will be used only if there's no saved state + foldout.value = attr.StartExpanded; + section = foldout; + break; + + case SectionStyle.Header: + default: + section = new VisualElement(); + if (!string.IsNullOrEmpty(attr.DisplayName)) + { + var label = new Label(attr.DisplayName); + label.AddToClassList(StyleHelper.CLASS_SECTION_LABEL); + section.Add(label); + } + break; + } + + section.AddToClassList(StyleHelper.CLASS_SECTION); + sections[attr.Id] = section; + rootElement.Add(section); + } + } + + public static VisualElement GetVisualElementForField(FieldInfo field, SerializedProperty property, string label = null) + { + VisualElement element; + + // We do this to show the alignment dropdown because some versions of Unity seems to have issues with the default PropertyDrawer (e.g Unity 2022.3.10) + // In those versions, the default PropertyDrawer doesn't show the dropdown, but rather the X and Y fields. + // It's possible that this is a bug in Unity, but this is a workaround for now. + if (field.FieldType == typeof(Alignment)) + { + var alignmentDrawer = new AlignmentPropertyDrawer(); + element = alignmentDrawer.CreatePropertyGUI(property); + + } + else + { + var propertyField = new PropertyField + { + bindingPath = field.Name + }; + + if (label != null) + { + propertyField.label = label; + } + + element = propertyField; + } + + + + return element; + + } + + + private void CreateFieldElement(FieldInfo field, InspectorFieldAttribute attr, VisualElement container) + { + string displayName = attr?.DisplayName ?? ObjectNames.NicifyVariableName(field.Name); + var property = serializedObject.FindProperty(field.Name); + + VisualElement element = GetVisualElementForField(field, property, displayName); + string uniqueId = $"field-{target.GetInstanceID()}-{target.GetType().Name}-{field.Name}"; + element.name = uniqueId; + + HandleValueChangedIfNeeded(field, element); + + VisualElement fieldRoot = element; + if (attr != null && attr.HasHelpUrl) + { + var fieldContainer = new VisualElement(); + fieldContainer.AddToClassList(StyleHelper.CLASS_FIELD_CONTAINER); + fieldContainer.style.flexDirection = FlexDirection.Row; + fieldContainer.style.alignItems = Align.Center; + + element.AddToClassList(StyleHelper.CLASS_FIELD_CONTENT); + fieldContainer.Add(element); + fieldContainer.Add(CreateHelpButton(attr.HelpUrl, displayName)); + fieldRoot = fieldContainer; + } + + HandleConditionalVisibilityIfNeeded(field, fieldRoot, property); + + element.Bind(serializedObject); + fieldRoot.AddToClassList(StyleHelper.CLASS_FIELD); + container.Add(fieldRoot); + } + + private void HandleValueChangedIfNeeded(FieldInfo field, VisualElement element) + { + var onValueChangedAttr = field.GetCustomAttribute(); + if (onValueChangedAttr != null) + { + var methodInfo = target.GetType().GetMethod(onValueChangedAttr.CallbackName, + BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); + + if (methodInfo != null) + { + bool isInitializing = true; + element.RegisterCallback(evt => + { + element.schedule.Execute(() => + { + isInitializing = false; + }); + }); + + + if (element is PropertyField propertyField) + { + propertyField.RegisterValueChangeCallback(evt => + { + if (!isInitializing || onValueChangedAttr.InvokeOnInitialization) + { + methodInfo.Invoke(target, null); + } + }); + return; + } + + // The alignment dropdown is a PopupField + // Get the PopupField from the element. It's possible that the passed in element might be a container so we might need to find the PopupField in the children. + var popupField = element.Q>(); + + if (element != null) + { + popupField.RegisterValueChangedCallback(evt => + { + if (!isInitializing || onValueChangedAttr.InvokeOnInitialization) + { + methodInfo.Invoke(target, null); + } + }); + } + } + } + } + + private void HandleConditionalVisibilityIfNeeded(FieldInfo field, VisualElement element, SerializedProperty property) + { + var showIfAttr = field.GetCustomAttribute(); + var hideIfAttr = field.GetCustomAttribute(); + + if (showIfAttr == null && hideIfAttr == null) return; + string conditionName = showIfAttr?.ConditionName ?? hideIfAttr?.ConditionName; + bool isHideIf = hideIfAttr != null; + + void UpdateVisibility() + { + if (property.serializedObject == null || property.serializedObject.targetObject == null) + { + return; + } + + var target = property.serializedObject.targetObject; + if (ReflectionUtils.TryGetBoolValue(target, conditionName, out bool condition)) + { + element.style.display = (condition != isHideIf) ? DisplayStyle.Flex : DisplayStyle.None; + } + } + + element.RegisterCallback(evt => + { + property.serializedObject.Update(); + UpdateVisibility(); + }); + + UpdateVisibility(); + // Update visibility whenever the inspector updates + scheduledUpdate = element.schedule.Execute(() => + { + if (property.serializedObject == null || property.serializedObject.targetObject == null) + { + // Stop scheduling future updates + scheduledUpdate?.Pause(); + return; + } + + property.serializedObject.Update(); + UpdateVisibility(); + }).Every(100); + } + + private IVisualElementScheduledItem scheduledUpdate; + + private Button CreateHelpButton(string helpUrl, string displayName) + { + var button = new Button(() => + { + if (!string.IsNullOrEmpty(helpUrl)) + { + Application.OpenURL(helpUrl); + } + }); + + button.tooltip = "Open documentation for this field"; + button.focusable = false; + button.AddToClassList(StyleHelper.CLASS_FIELD_HELP_BUTTON); + + var iconContent = EditorGUIUtility.IconContent("_Help"); + if (iconContent?.image != null) + { + var icon = new Image + { + image = iconContent.image, + scaleMode = ScaleMode.ScaleToFit + }; + button.Add(icon); + } + else + { + button.text = "?"; + } + + return button; + } + + private void OnDestroy() + { + if (Application.isPlaying) return; + + + + bool componentRemoved = m_gameObject != null && m_gameObject.GetComponent(target.GetType()) == null; + + + //If the component was removed but not the gameobject, let's destroy the required components it added that are hidden + // If they're not hidden, then the user can remove them manually. + if (componentRemoved) + { + var hideComponentsAttrs = target.GetType().GetCustomAttributes(); + foreach (var attr in hideComponentsAttrs) + { + CustomInspectorUtils.DestroyRequiredHiddenComponents( + m_gameObject, + target.GetType(), + component => (component.hideFlags & attr.HideFlags) != 0 + ); + } + } + } + + + } +#endif +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Editor/Components/RiveBaseEditor.cs.meta b/Packages/app.rive.rive-unity/Editor/Components/RiveBaseEditor.cs.meta new file mode 100644 index 00000000..e52760d8 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Components/RiveBaseEditor.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: a7b60061c641d4f969e8522e1c71afe7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Editor/Components/RiveBaseEditor.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Editor/Components/RivePanelInspector.cs b/Packages/app.rive.rive-unity/Editor/Components/RivePanelInspector.cs new file mode 100644 index 00000000..7c35a536 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Components/RivePanelInspector.cs @@ -0,0 +1,12 @@ +using Rive.Components; +using UnityEditor; + +namespace Rive.EditorTools +{ + [CustomEditor(typeof(RivePanel), true)] + internal class RivePanelInspector : RiveBaseEditor + { + + + } +} diff --git a/Packages/app.rive.rive-unity/Editor/Components/RivePanelInspector.cs.meta b/Packages/app.rive.rive-unity/Editor/Components/RivePanelInspector.cs.meta new file mode 100644 index 00000000..25790413 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Components/RivePanelInspector.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: a405a6d22e0d94955a82a4b7ba363a47 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Editor/Components/RivePanelInspector.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Editor/Components/RiveRawImageEditor.cs b/Packages/app.rive.rive-unity/Editor/Components/RiveRawImageEditor.cs new file mode 100644 index 00000000..9e8ae836 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Components/RiveRawImageEditor.cs @@ -0,0 +1,42 @@ +using UnityEditor; +using UnityEngine; +using UnityEngine.UIElements; +using UnityEditor.UIElements; +using Rive.Components; + +namespace Rive.EditorTools +{ + [CustomEditor(typeof(CanvasRendererRawImage))] + internal class RiveRawImageEditor : Editor + { + public override VisualElement CreateInspectorGUI() + { + var root = new VisualElement(); + + // We want to show the texture field in the inspector when in play mode, but we want it to be read-only. + if (Application.isPlaying) + { + var textureField = new ObjectField("Texture") + { + objectType = typeof(Texture), + value = (target as CanvasRendererRawImage)?.texture, + }; + + textureField.SetEnabled(false); + + root.Add(textureField); + + // Update the texture field when the selection changes + EditorApplication.update += () => + { + if (target != null && textureField != null) + { + textureField.value = (target as CanvasRendererRawImage)?.texture; + } + }; + } + + return root; + } + } +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Editor/Components/RiveRawImageEditor.cs.meta b/Packages/app.rive.rive-unity/Editor/Components/RiveRawImageEditor.cs.meta new file mode 100644 index 00000000..50e7441e --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Components/RiveRawImageEditor.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 4da44f8147bcc4b92b05f99b9c4148f2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Editor/Components/RiveRawImageEditor.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Editor/Components/RiveWidgetInspector.cs b/Packages/app.rive.rive-unity/Editor/Components/RiveWidgetInspector.cs new file mode 100644 index 00000000..d7f764ff --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Components/RiveWidgetInspector.cs @@ -0,0 +1,39 @@ +using System.Collections; +using System.Collections.Generic; +using Rive.Components; +using UnityEditor; +using UnityEngine; +using UnityEngine.UIElements; + +namespace Rive.EditorTools +{ + [CustomEditor(typeof(WidgetBehaviour), true)] + internal class RiveWidgetInspector : RiveBaseEditor + { + + public override VisualElement CreateInspectorGUI() + { + var root = base.CreateInspectorGUI(); + + if (target is RiveWidget widget) + { + var playgroundRow = new VisualElement(); + playgroundRow.style.marginTop = 6; + + var playgroundButton = new Button(() => + { + DataBindingPlaygroundWindow.Open(widget); + }) + { + text = "Open Playground", + tooltip = "Open a data binding playground for this widget" + }; + + playgroundRow.Add(playgroundButton); + root.Add(playgroundRow); + } + + return root; + } + } +} diff --git a/Packages/app.rive.rive-unity/Editor/Components/RiveWidgetInspector.cs.meta b/Packages/app.rive.rive-unity/Editor/Components/RiveWidgetInspector.cs.meta new file mode 100644 index 00000000..b7dc0b41 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Components/RiveWidgetInspector.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: e222c1dcc24154d079cbc89601fdd730 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Editor/Components/RiveWidgetInspector.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Editor/Components/Styles.meta b/Packages/app.rive.rive-unity/Editor/Components/Styles.meta new file mode 100644 index 00000000..4d5249ec --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Components/Styles.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ab89f3c9590794a79b784619bcdc32ae +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Editor/Components/Styles/RiveInspectorStyleSheet.uss b/Packages/app.rive.rive-unity/Editor/Components/Styles/RiveInspectorStyleSheet.uss new file mode 100644 index 00000000..651a3cc7 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Components/Styles/RiveInspectorStyleSheet.uss @@ -0,0 +1,62 @@ +.rive-inspector { + padding-top: 9px; +} + +.rive-inspector__section { + margin-bottom: 9px; + margin-top: 3px; +} + +.rive-inspector__foldout { +} + +.rive-inspector__field { + margin-bottom: 3px; + margin-left: 3px; +} +.rive-inspector__field > Label { + min-width: 117px; +} + +.rive-inspector__field-container { + flex-direction: row; + align-items: center; +} + +.rive-inspector__field-content { + flex: 1 1 auto; +} + +.rive-inspector__field-help-button { + width: 20px; + height: 20px; + padding: 0; + margin-left: 4px; + flex-shrink: 0; + justify-content: center; + align-items: center; + background-color: rgba(0, 0, 0, 0); + border-width: 0; +} + +.rive-inspector__field-help-button > Image { + width: 14px; + height: 14px; +} + +.rive-inspector__field-help-button:hover { + background-color: rgba(0, 0, 0, 0.08); +} + +.rive-inspector__section-label { + -unity-font-style: bold; + margin-bottom: 4px; + margin-left: 5.2px; + +} + +.unity-foldout__input > Label { + -unity-font-style: bold; + margin-left: 1px; + +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Editor/Components/Styles/RiveInspectorStyleSheet.uss.meta b/Packages/app.rive.rive-unity/Editor/Components/Styles/RiveInspectorStyleSheet.uss.meta new file mode 100644 index 00000000..0c803aa7 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Components/Styles/RiveInspectorStyleSheet.uss.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: cc66ac87f8ecb4e3c91384370163ee7b +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0} + disableValidation: 0 +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Editor/Components/Styles/RiveInspectorStyleSheet.uss + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Editor/Components/Styles/StyleHelper.cs b/Packages/app.rive.rive-unity/Editor/Components/Styles/StyleHelper.cs new file mode 100644 index 00000000..b67b2b43 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Components/Styles/StyleHelper.cs @@ -0,0 +1,63 @@ +using UnityEditor; +using UnityEngine.UIElements; + +namespace Rive +{ + /// + /// Helper class for styling Rive components. + /// + internal class StyleHelper + { + // USS Class Names + /// + /// The block class name for the Rive inspector. + /// + public const string CLASS_BLOCK = "rive-inspector"; + + /// + /// The element class name for sections within the Rive inspector. + /// + public const string CLASS_SECTION = "rive-inspector__section"; + + /// + /// The element class name for section labels within the Rive inspector. + /// + public const string CLASS_SECTION_LABEL = "rive-inspector__section-label"; + + /// + /// The element class name for fields within the Rive inspector. + /// + public const string CLASS_FIELD = "rive-inspector__field"; + + /// + /// Container that wraps a field and its optional help button. + /// + public const string CLASS_FIELD_CONTAINER = "rive-inspector__field-container"; + + /// + /// Class name applied to the primary field element inside a container. + /// + public const string CLASS_FIELD_CONTENT = "rive-inspector__field-content"; + + /// + /// Class name applied to the help/info buttons. + /// + public const string CLASS_FIELD_HELP_BUTTON = "rive-inspector__field-help-button"; + + + private static StyleSheet s_StyleSheet; + + public static StyleSheet StyleSheet + { + get + { + if (s_StyleSheet == null) + { + string ussPath = "Packages/app.rive.rive-unity/Editor/Components/Styles/RiveInspectorStyleSheet.uss"; + s_StyleSheet = AssetDatabase.LoadAssetAtPath(ussPath); + } + return s_StyleSheet; + } + } + } +} diff --git a/Packages/app.rive.rive-unity/Editor/Components/Styles/StyleHelper.cs.meta b/Packages/app.rive.rive-unity/Editor/Components/Styles/StyleHelper.cs.meta new file mode 100644 index 00000000..5e67f8ab --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Components/Styles/StyleHelper.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 8a09ca9bb7cb94661be11fbfb6e25ba0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Editor/Components/Styles/StyleHelper.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Editor/Components/TexturePanelRendererEditor.cs b/Packages/app.rive.rive-unity/Editor/Components/TexturePanelRendererEditor.cs new file mode 100644 index 00000000..2667ebd2 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Components/TexturePanelRendererEditor.cs @@ -0,0 +1,41 @@ +using Rive.Components; +using UnityEditor; +using UnityEngine.UIElements; + + +namespace Rive.EditorTools +{ + + [CustomEditor(typeof(RiveTextureRenderer), true)] + internal class TexturePanelRendererEditor : PanelRendererInspector + { + public override VisualElement CreateInspectorGUI() + { + var root = base.CreateInspectorGUI() ?? new VisualElement(); + + // For worldspace renderers, we display a button to convert materials on the current mesh renderer, if needed. + // Makes it easier for users to switch to Rive materials without having to know the right ones to pick. + var textureRenderer = (RiveTextureRenderer)target; + if (textureRenderer != null && textureRenderer.Renderer != null) + { + System.Action clickAction = () => + { + // This will replace any non-Rive materials with Rive equivalents, even if the existing materials are not Unity defaults. + MaterialConversionUtility.ReplaceMaterialsWithRive(textureRenderer.Renderer); + }; + var convertButton = new Button(() => clickAction()) + { + text = "Replace Materials with Rive Materials" + }; + convertButton.name = "RiveConvertMaterialsButton"; + convertButton.userData = clickAction; // allow tests to invoke without event system/panel + convertButton.style.marginTop = 6; + root.Add(convertButton); + } + + return root; + } + + } +} + diff --git a/Packages/app.rive.rive-unity/Editor/Components/TexturePanelRendererEditor.cs.meta b/Packages/app.rive.rive-unity/Editor/Components/TexturePanelRendererEditor.cs.meta new file mode 100644 index 00000000..671af09d --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Components/TexturePanelRendererEditor.cs.meta @@ -0,0 +1,20 @@ +fileFormatVersion: 2 +guid: b792f3d5adc79476e97be1d9ac3fbad0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: + - m_styleSheet: {fileID: 7433441132597879392, guid: cc66ac87f8ecb4e3c91384370163ee7b, + type: 3} + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Editor/Components/TexturePanelRendererEditor.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Editor/Components/Utils.meta b/Packages/app.rive.rive-unity/Editor/Components/Utils.meta new file mode 100644 index 00000000..4d6bb259 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Components/Utils.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7ba5b52221ad74445868d7b7032fa0a3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Editor/Components/Utils/CustomInspectorUtils.cs b/Packages/app.rive.rive-unity/Editor/Components/Utils/CustomInspectorUtils.cs new file mode 100644 index 00000000..6a4e99d2 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Components/Utils/CustomInspectorUtils.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEditor; +using UnityEngine; + +namespace Rive.EditorTools +{ + internal class CustomInspectorUtils + { + + public static void HideNonInteractiveComponents(MonoBehaviour target, List componentTypes, Editor editor, HideFlags hideFlags = HideFlags.HideInInspector | HideFlags.HideAndDontSave) + { + if (target == null || componentTypes == null) return; + + foreach (var type in componentTypes) + { + var component = target.GetComponent(type); + if (component != null) + { + component.hideFlags = hideFlags; + + } + + } + } + + public static void DestroyRequiredHiddenComponents(GameObject gameObject, Type componentType, Func ComponenentFilter = null) + { + RequireComponent[] requiredComponentsAtts = Attribute.GetCustomAttributes(componentType, typeof(RequireComponent), true) as RequireComponent[]; + + foreach (RequireComponent rc in requiredComponentsAtts) + { + if (rc != null) + { + Type[] typesToRemove = new Type[] { rc.m_Type0, rc.m_Type1, rc.m_Type2 }; + foreach (Type type in typesToRemove) + { + if (type != null) + { + UnityEngine.Component componentToDestroy = gameObject.GetComponent(type); + ComponenentFilter = ComponenentFilter ?? ShouldDestroyComponent; + if (componentToDestroy != null && ShouldDestroyComponent(componentToDestroy)) + { + UnityEngine.Object.DestroyImmediate(componentToDestroy); + } + } + } + } + } + } + + private static bool ShouldDestroyComponent(UnityEngine.Component component) + { + // Check if the component has HideFlags that indicate it should be automatically managed + return (component.hideFlags & (HideFlags.HideInInspector | HideFlags.HideAndDontSave)) != 0; + } + + + } +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Editor/Components/Utils/CustomInspectorUtils.cs.meta b/Packages/app.rive.rive-unity/Editor/Components/Utils/CustomInspectorUtils.cs.meta new file mode 100644 index 00000000..3fd552e5 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Components/Utils/CustomInspectorUtils.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: cc3bdf49da3e34a5089e9857b3d1719e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Editor/Components/Utils/CustomInspectorUtils.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Editor/Components/Utils/ReflectionUtils.cs b/Packages/app.rive.rive-unity/Editor/Components/Utils/ReflectionUtils.cs new file mode 100644 index 00000000..38a6648f --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Components/Utils/ReflectionUtils.cs @@ -0,0 +1,116 @@ +using System; +using System.Reflection; +using Rive.EditorTools; +using UnityEditor; + +namespace Rive.Utils +{ + internal static class ReflectionUtils + { + private const BindingFlags DefaultBindingFlags = + BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; + + public static bool TryGetBoolValue(object target, string memberName, out bool value) + { + value = false; + if (target == null || string.IsNullOrEmpty(memberName)) return false; + + try + { + var type = target.GetType(); + + var field = type.GetField(memberName, DefaultBindingFlags); + if (field != null) + { + value = (bool)field.GetValue(target); + return true; + } + + var prop = type.GetProperty(memberName, DefaultBindingFlags); + if (prop != null) + { + value = (bool)prop.GetValue(target); + return true; + } + + var method = type.GetMethod(memberName, DefaultBindingFlags); + if (method != null) + { + value = (bool)method.Invoke(target, null); + return true; + } + + return false; + } + catch (Exception e) + { + DebugLogger.Instance.LogError($"Error getting bool value for member '{memberName}': {e.Message}"); + return false; + } + } + + public static bool TryGetValue(object target, string memberName, out T value) + { + value = default; + if (target == null || string.IsNullOrEmpty(memberName)) return false; + + try + { + var type = target.GetType(); + + var field = type.GetField(memberName, DefaultBindingFlags); + if (field != null) + { + value = (T)field.GetValue(target); + return true; + } + + var prop = type.GetProperty(memberName, DefaultBindingFlags); + if (prop != null) + { + value = (T)prop.GetValue(target); + return true; + } + + var method = type.GetMethod(memberName, DefaultBindingFlags); + if (method != null) + { + value = (T)method.Invoke(target, null); + return true; + } + + return false; + } + catch (Exception e) + { + DebugLogger.Instance.LogError($"Error getting value of type {typeof(T)} for member '{memberName}': {e.Message}"); + return false; + } + } + + /// + /// Get the display name for a serialized property. This accounts for a custom label being set via an InspectorFieldAttribute. + /// + /// The property to get the label for. + /// The display name for the property. + public static string GetPropertyLabel(SerializedProperty property) + { + if (property == null) return string.Empty; + + try + { + var target = property.serializedObject.targetObject; + var fieldInfo = target.GetType().GetField(property.name, DefaultBindingFlags); + var inspectorAttr = fieldInfo?.GetCustomAttribute(); + + return inspectorAttr?.DisplayName ?? ObjectNames.NicifyVariableName(property.name); + } + catch (Exception e) + { + DebugLogger.Instance.LogError($"Error getting label for property '{property.name}': {e.Message}"); + return ObjectNames.NicifyVariableName(property.name); + + } + } + } +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Editor/Components/Utils/ReflectionUtils.cs.meta b/Packages/app.rive.rive-unity/Editor/Components/Utils/ReflectionUtils.cs.meta new file mode 100644 index 00000000..43572bdf --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Components/Utils/ReflectionUtils.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: a1a5fa6b3a3b640c5b4d63a810c8fee3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Editor/Components/Utils/ReflectionUtils.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Editor/FontAssetImporter.cs b/Packages/app.rive.rive-unity/Editor/FontAssetImporter.cs new file mode 100644 index 00000000..238c8834 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/FontAssetImporter.cs @@ -0,0 +1,28 @@ +using UnityEngine; +using UnityEditor.AssetImporters; + +namespace Rive +{ + + internal static class FontOobAssetExtensions + { + public const string TTF = "ttf"; + public const string OTF = "otf"; + + public static readonly string[] FontExtensions = new[] { TTF, OTF }; + } + + + [ScriptedImporter(2, null, new string[] { FontOobAssetExtensions.TTF, FontOobAssetExtensions.OTF })] + public class FontAssetImporter : ScriptedImporter + { + public override void OnImportAsset(AssetImportContext ctx) + { + byte[] bytesToAssign = System.IO.File.ReadAllBytes(ctx.assetPath); + FontOutOfBandAsset file = OutOfBandAsset.Create(bytesToAssign); + + ctx.AddObjectToAsset("rive-font", file); + ctx.SetMainObject(file); + } + } +} diff --git a/Packages/app.rive.rive-unity/Editor/FontAssetImporter.cs.meta b/Packages/app.rive.rive-unity/Editor/FontAssetImporter.cs.meta new file mode 100644 index 00000000..8de02c89 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/FontAssetImporter.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: e35fd16d945b04aaa9bbb2d5c7224cf9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Editor/FontAssetImporter.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Editor/Icons.meta b/Packages/app.rive.rive-unity/Editor/Icons.meta new file mode 100644 index 00000000..88c22868 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Icons.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cc069e1f0c24d4364bb5c4cd2e0a408a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Editor/Icons/d_rive.png b/Packages/app.rive.rive-unity/Editor/Icons/d_rive.png new file mode 100644 index 00000000..e11ff183 Binary files /dev/null and b/Packages/app.rive.rive-unity/Editor/Icons/d_rive.png differ diff --git a/Packages/app.rive.rive-unity/Editor/Icons/d_rive.png.meta b/Packages/app.rive.rive-unity/Editor/Icons/d_rive.png.meta new file mode 100644 index 00000000..dbe4f3b3 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Icons/d_rive.png.meta @@ -0,0 +1,147 @@ +fileFormatVersion: 2 +guid: f377684eb5623462e80ebba320696f74 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 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: 1 + 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: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 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 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: iPhone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Editor/Icons/d_rive.png + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Editor/Icons/d_rive@2x.png b/Packages/app.rive.rive-unity/Editor/Icons/d_rive@2x.png new file mode 100644 index 00000000..a41830e2 Binary files /dev/null and b/Packages/app.rive.rive-unity/Editor/Icons/d_rive@2x.png differ diff --git a/Packages/app.rive.rive-unity/Editor/Icons/d_rive@2x.png.meta b/Packages/app.rive.rive-unity/Editor/Icons/d_rive@2x.png.meta new file mode 100644 index 00000000..67a60263 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Icons/d_rive@2x.png.meta @@ -0,0 +1,147 @@ +fileFormatVersion: 2 +guid: d85a4632cb63547b38008947f3e6571b +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 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: 1 + 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: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 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 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: iPhone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Editor/Icons/d_rive@2x.png + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Editor/Icons/rive.png b/Packages/app.rive.rive-unity/Editor/Icons/rive.png new file mode 100644 index 00000000..c7e7e6b1 Binary files /dev/null and b/Packages/app.rive.rive-unity/Editor/Icons/rive.png differ diff --git a/Packages/app.rive.rive-unity/Editor/Icons/rive.png.meta b/Packages/app.rive.rive-unity/Editor/Icons/rive.png.meta new file mode 100644 index 00000000..5e2684c0 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Icons/rive.png.meta @@ -0,0 +1,147 @@ +fileFormatVersion: 2 +guid: df0df084c4eaa4149a9c988c71b85313 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 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: 1 + 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: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 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 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: iPhone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Editor/Icons/rive.png + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Editor/Icons/rive@2x.png b/Packages/app.rive.rive-unity/Editor/Icons/rive@2x.png new file mode 100644 index 00000000..1a2958ae Binary files /dev/null and b/Packages/app.rive.rive-unity/Editor/Icons/rive@2x.png differ diff --git a/Packages/app.rive.rive-unity/Editor/Icons/rive@2x.png.meta b/Packages/app.rive.rive-unity/Editor/Icons/rive@2x.png.meta new file mode 100644 index 00000000..3a093798 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Icons/rive@2x.png.meta @@ -0,0 +1,147 @@ +fileFormatVersion: 2 +guid: b448b542b6b2945cb97bbcb34bebfd17 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 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: 1 + 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: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 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 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: iPhone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Editor/Icons/rive@2x.png + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Editor/ImageAssetImporter.cs b/Packages/app.rive.rive-unity/Editor/ImageAssetImporter.cs new file mode 100644 index 00000000..dc910f9e --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/ImageAssetImporter.cs @@ -0,0 +1,28 @@ +using UnityEngine; +using UnityEditor.AssetImporters; + +namespace Rive +{ + internal static class ImageOobAssetExtensions + { + public const string PNG = "png"; + public const string JPG = "jpg"; + public const string JPEG = "jpeg"; + public const string WEBP = "webp"; + + public static readonly string[] ImageExtensions = new[] { PNG, JPG, JPEG, WEBP }; + } + + [ScriptedImporter(2, new string[] { ImageOobAssetExtensions.WEBP }, new string[] { ImageOobAssetExtensions.PNG, ImageOobAssetExtensions.JPG, ImageOobAssetExtensions.JPEG, ImageOobAssetExtensions.WEBP })] + public class ImageAssetImporter : ScriptedImporter + { + public override void OnImportAsset(AssetImportContext ctx) + { + byte[] bytesToAssign = System.IO.File.ReadAllBytes(ctx.assetPath); + ImageOutOfBandAsset file = OutOfBandAsset.Create(bytesToAssign); + + ctx.AddObjectToAsset("rive-image", file); + ctx.SetMainObject(file); + } + } +} diff --git a/Packages/app.rive.rive-unity/Editor/ImageAssetImporter.cs.meta b/Packages/app.rive.rive-unity/Editor/ImageAssetImporter.cs.meta new file mode 100644 index 00000000..a3428c7e --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/ImageAssetImporter.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: b2f3a627015694711ac8598da5383316 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Editor/ImageAssetImporter.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Editor/ImageOutOfBandAssetEditor.cs b/Packages/app.rive.rive-unity/Editor/ImageOutOfBandAssetEditor.cs new file mode 100644 index 00000000..1e0d34ca --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/ImageOutOfBandAssetEditor.cs @@ -0,0 +1,159 @@ +using System; +using System.IO; +using Rive.Utils; +using UnityEditor; +using UnityEngine; + +namespace Rive +{ + /// + /// Custom editor for ImageOutOfBandAsset that displays a preview of the image. + /// + [CustomEditor(typeof(ImageOutOfBandAsset))] + public class ImageOutOfBandAssetEditor : Editor + { + private enum PreviewMode + { + Contain = 0, + Cover = 1 + } + + private PreviewMode previewMode = PreviewMode.Contain; + public override Texture2D RenderStaticPreview(string assetPath, UnityEngine.Object[] subAssets, int width, int height) + { + var asset = (ImageOutOfBandAsset)target; + + if (asset == null || asset.Bytes == null || asset.Bytes.Length == 0) + { + return null; + } + // WebP images are not currently supported for previews because they are not natively supported by the Unity engine, custom support will be added in the future. + if (IsWebp(assetPath)) + { + return null; + } + + Texture2D originalTexture = LoadOriginalTexture(asset.Bytes); + if (originalTexture == null) + { + return null; + } + + Vector2Int newSize = CalculateNewSize(originalTexture.width, originalTexture.height, width, height); + Texture2D resizedTexture = ResizeTexture(originalTexture, newSize.x, newSize.y); + Texture2D previewTexture = CreatePreviewTexture(resizedTexture, width, height); + + UnityEngine.Object.DestroyImmediate(originalTexture); + UnityEngine.Object.DestroyImmediate(resizedTexture); + + return previewTexture; + } + + private Texture2D LoadOriginalTexture(byte[] bytes) + { + Texture2D texture = new Texture2D(2, 2); + if (texture.LoadImage(bytes)) + { + return texture; + } + + DebugLogger.Instance.LogWarning("Failed to load image preview for ImageOutOfBandAsset"); + + return null; + } + + private Vector2Int CalculateNewSize(int originalWidth, int originalHeight, int targetWidth, int targetHeight) + { + float aspectRatio = (float)originalWidth / originalHeight; + float targetAspectRatio = (float)targetWidth / targetHeight; + + switch (previewMode) + { + case PreviewMode.Contain: + if (targetAspectRatio > aspectRatio) + { + return new Vector2Int( + Mathf.RoundToInt(targetHeight * aspectRatio), + targetHeight + ); + } + else + { + return new Vector2Int( + targetWidth, + Mathf.RoundToInt(targetWidth / aspectRatio) + ); + } + + case PreviewMode.Cover: + if (targetAspectRatio > aspectRatio) + { + return new Vector2Int( + targetWidth, + Mathf.RoundToInt(targetWidth / aspectRatio) + ); + } + else + { + return new Vector2Int( + Mathf.RoundToInt(targetHeight * aspectRatio), + targetHeight + ); + } + default: + DebugLogger.Instance.LogWarning($"Unsupported preview mode: {previewMode}. Falling back to Contain mode."); + goto case PreviewMode.Contain; + } + } + + private Texture2D ResizeTexture(Texture2D originalTexture, int newWidth, int newHeight) + { + RenderTexture rt = RenderTexture.GetTemporary(newWidth, newHeight, 0, RenderTextureFormat.Default, RenderTextureReadWrite.Linear); + + // Set the filter mode to bilinear to match the previous scaling method + rt.filterMode = FilterMode.Bilinear; + + RenderTexture.active = rt; + Graphics.Blit(originalTexture, rt); + Texture2D resizedTexture = new Texture2D(newWidth, newHeight); + resizedTexture.ReadPixels(new Rect(0, 0, newWidth, newHeight), 0, 0); + resizedTexture.Apply(); + RenderTexture.active = null; + RenderTexture.ReleaseTemporary(rt); + + return resizedTexture; + } + + private Texture2D CreatePreviewTexture(Texture2D resizedTexture, int width, int height) + { + Texture2D previewTexture = new Texture2D(width, height, TextureFormat.RGBA32, false); + + // Fill the background with transparency + UnityEngine.Color[] fillPixels = new UnityEngine.Color[width * height]; + for (int i = 0; i < fillPixels.Length; i++) + fillPixels[i] = UnityEngine.Color.clear; + previewTexture.SetPixels(fillPixels); + + // Center the resized image + int x = (width - resizedTexture.width) / 2; + int y = (height - resizedTexture.height) / 2; + + // Copy the resized image to the center of the preview texture + previewTexture.SetPixels32(x, y, resizedTexture.width, resizedTexture.height, resizedTexture.GetPixels32()); + previewTexture.Apply(); + + return previewTexture; + } + + private bool IsWebp(string assetPath) + { + if (string.IsNullOrEmpty(assetPath)) + { + return false; + } + + return string.Equals(System.IO.Path.GetExtension(assetPath), ".webp", StringComparison.OrdinalIgnoreCase); + } + + } +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Editor/ImageOutOfBandAssetEditor.cs.meta b/Packages/app.rive.rive-unity/Editor/ImageOutOfBandAssetEditor.cs.meta new file mode 100644 index 00000000..9991f5f6 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/ImageOutOfBandAssetEditor.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: fb25ae926319f442e819f03e76fe3903 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Editor/ImageOutOfBandAssetEditor.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Editor/Images.meta b/Packages/app.rive.rive-unity/Editor/Images.meta new file mode 100644 index 00000000..e8386188 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Images.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 98fa41ca9d0f447c789d57b601a912ae +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Editor/Images/rive-preview-image.png b/Packages/app.rive.rive-unity/Editor/Images/rive-preview-image.png new file mode 100644 index 00000000..171c7d48 Binary files /dev/null and b/Packages/app.rive.rive-unity/Editor/Images/rive-preview-image.png differ diff --git a/Packages/app.rive.rive-unity/Editor/Images/rive-preview-image.png.meta b/Packages/app.rive.rive-unity/Editor/Images/rive-preview-image.png.meta new file mode 100644 index 00000000..4c095cc3 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Images/rive-preview-image.png.meta @@ -0,0 +1,186 @@ +fileFormatVersion: 2 +guid: 233ae908c7a8b4e469e848c97a45f4a6 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + 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 + flipGreenChannel: 0 + isReadable: 1 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + 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: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 1024 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 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 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: iPhone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 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 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: VisionOS + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: tvOS + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Editor/Images/rive-preview-image.png + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Editor/Images/welcome-banner.png b/Packages/app.rive.rive-unity/Editor/Images/welcome-banner.png new file mode 100644 index 00000000..22293df1 Binary files /dev/null and b/Packages/app.rive.rive-unity/Editor/Images/welcome-banner.png differ diff --git a/Packages/app.rive.rive-unity/Editor/Images/welcome-banner.png.meta b/Packages/app.rive.rive-unity/Editor/Images/welcome-banner.png.meta new file mode 100644 index 00000000..c96c7292 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Images/welcome-banner.png.meta @@ -0,0 +1,186 @@ +fileFormatVersion: 2 +guid: e3703478f7a284efb81797fb6fb6820f +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + 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: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 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 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: iPhone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 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 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: VisionOS + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: tvOS + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Editor/Images/welcome-banner.png + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Editor/Menu.meta b/Packages/app.rive.rive-unity/Editor/Menu.meta new file mode 100644 index 00000000..47566249 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Menu.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e44d6a73ac1744ea9b75451a9ff70140 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Editor/Menu/SupportInfoMenu.cs b/Packages/app.rive.rive-unity/Editor/Menu/SupportInfoMenu.cs new file mode 100644 index 00000000..cf9c9aec --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Menu/SupportInfoMenu.cs @@ -0,0 +1,144 @@ +using System; +using System.Linq; +using Rive.EditorTools; +using UnityEditor; +using UnityEngine; +using UnityEngine.Rendering; + +namespace Rive.EditorTools +{ + /// + /// Adds a menu item to copy useful environment information to the clipboard for support tickets. + /// + internal static class SupportInfoMenu + { + private const string MenuPath = "Tools/Rive/Copy Support Info"; + + [MenuItem(MenuPath, priority = 1000)] + private static void CopySupportInfo() + { + try + { + string supportInfo = GenerateSupportInfo(); + EditorGUIUtility.systemCopyBuffer = supportInfo; + EditorUtility.DisplayDialog("Rive", "Support info copied to clipboard.", "OK"); + } + catch (Exception ex) + { + Debug.LogError($"Failed to copy Rive support info: {ex}"); + } + } + + private static string GenerateSupportInfo() + { + string unityVersion = Application.unityVersion; + BuildTarget activeBuildTarget = EditorUserBuildSettings.activeBuildTarget; + + var targetGroup = BuildPipeline.GetBuildTargetGroup(activeBuildTarget); + var apis = PlayerSettings.GetGraphicsAPIs(activeBuildTarget); + string graphicsApis = apis != null && apis.Length > 0 + ? string.Join(", ", apis.Select(api => api.ToString()).ToArray()) + : "Auto (Unity default)"; + + string renderPipeline = GetRenderPipelineDescription(); + + string operatingSystem = SystemInfo.operatingSystem; + string graphicsDevice = SystemInfo.graphicsDeviceName + " (" + SystemInfo.graphicsDeviceType + ")"; + + string riveVersion = GetPackageVersion(Rive.EditorTools.PackageInfo.PACKAGE_NAME); + + return + "Rive Unity Support Info\n" + + "------------------------\n" + + $"Unity Version: {unityVersion}\n" + + $"Active Build Target: {activeBuildTarget}\n" + + $"Build Target Group: {targetGroup}\n" + + $"Graphics APIs: {graphicsApis}\n" + + $"Render Pipeline: {renderPipeline}\n" + + $"OS: {operatingSystem}\n" + + $"GPU: {graphicsDevice}\n" + + $"Rive Plugin: {Rive.EditorTools.PackageInfo.PACKAGE_NAME} {riveVersion}\n"; + } + + private static string GetRenderPipelineDescription() + { + var asset = GraphicsSettings.currentRenderPipeline; + if (asset == null) + { + return "Built-in Render Pipeline"; + } + + var srpType = asset.GetType(); + string pipelineName = srpType.Name; + + // Try to fetch version via known properties if available + string version = null; + + var versionProperty = srpType.GetProperty("version") ?? srpType.GetProperty("Version"); + if (versionProperty != null) + { + try + { + var value = versionProperty.GetValue(asset, null); + version = value != null ? value.ToString() : null; + } + catch { } + } + + // Fallback to package if known SRPs + if (string.IsNullOrEmpty(version)) + { + string packageId = null; + if (srpType.FullName.Contains("UniversalRenderPipeline")) + { + packageId = "com.unity.render-pipelines.universal"; + } + else if (srpType.FullName.Contains("HDRenderPipeline")) + { + packageId = "com.unity.render-pipelines.high-definition"; + } + + if (!string.IsNullOrEmpty(packageId)) + { + version = GetPackageVersion(packageId); + } + } + + return string.IsNullOrEmpty(version) ? pipelineName : pipelineName + " " + version; + } + + private static string GetPackageVersion(string packageName) + { + // Use UnityEditor.PackageManager for reliable version when available. + try + { + var request = UnityEditor.PackageManager.Client.List(true, true); + // We've added a busy-wait with timeout to avoid async flow in menu command + var start = DateTime.UtcNow; + while (!request.IsCompleted) + { + if ((DateTime.UtcNow - start).TotalSeconds > 5) + { + break; + } + } + + if (request.IsCompleted && request.Status == UnityEditor.PackageManager.StatusCode.Success) + { + var pkg = request.Result.FirstOrDefault(p => p.name == packageName); + if (pkg != null) + { + return pkg.version; + } + } + } + catch + { + } + + return "(version unknown)"; + } + } +} + + diff --git a/Packages/app.rive.rive-unity/Editor/Menu/SupportInfoMenu.cs.meta b/Packages/app.rive.rive-unity/Editor/Menu/SupportInfoMenu.cs.meta new file mode 100644 index 00000000..a3093f0b --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Menu/SupportInfoMenu.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 544d95f9bf7bf475bb599e5cb74f4015 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Editor/Menu/SupportInfoMenu.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Editor/PackageVersionChecker.cs b/Packages/app.rive.rive-unity/Editor/PackageVersionChecker.cs new file mode 100644 index 00000000..3d4392b1 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/PackageVersionChecker.cs @@ -0,0 +1,58 @@ +using Rive.Utils; +using UnityEditor; +using UnityEditor.PackageManager; + +namespace Rive.EditorTools +{ + /// + /// Checks if the Rive package was updated and shows a dialog to restart the Unity Editor. + /// We do this because the Rive plugin is a native plugin and the Unity Editor needs to be restarted in order unload the old version and load the new one. + /// + [InitializeOnLoad] + internal class PackageVersionChecker + { + static PackageVersionChecker() + { + Events.registeredPackages += OnPackagesRegistered; + } + + private static void OnPackagesRegistered(PackageRegistrationEventArgs args) + { + var updatedPackage = FindByName(args.changedTo); + if (updatedPackage != null) + { + ShowRestartDialog(updatedPackage.version); + } + } + + private static UnityEditor.PackageManager.PackageInfo FindByName(System.Collections.Generic.IEnumerable packages) + { + foreach (var package in packages) + { + if (package != null && package.name == Rive.EditorTools.PackageInfo.PACKAGE_NAME) + { + return package; + } + } + + return null; + } + + private static void ShowRestartDialog(string newVersion) + { + EditorUtility.DisplayDialog( + "Package Update Detected", + $"The Rive plugin has been updated to version {newVersion}.\n\n" + + "Please restart Unity to load the new version.", + "OK" + ); + + DebugLogger.Instance.LogWarning( + $"[{Rive.EditorTools.PackageInfo.PACKAGE_NAME}] Package updated to {newVersion}. " + + "Please restart the Unity Editor to make sure the new version is fully loaded. If you skip this step, you might run into issues, and riv files may not work properly." + ); + } + + } + +} diff --git a/Packages/app.rive.rive-unity/Editor/PackageVersionChecker.cs.meta b/Packages/app.rive.rive-unity/Editor/PackageVersionChecker.cs.meta new file mode 100644 index 00000000..4cae1cbe --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/PackageVersionChecker.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 86ee58136b6f64281b6cd0aaa150fd1d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Editor/PackageVersionChecker.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Editor/Rive.Editor.asmdef b/Packages/app.rive.rive-unity/Editor/Rive.Editor.asmdef new file mode 100644 index 00000000..0bbfec5c --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Rive.Editor.asmdef @@ -0,0 +1,19 @@ +{ + "name": "Rive.Editor", + "rootNamespace": "Rive", + "references": [ + "GUID:0a82aeb665886483c867b7d137563619", + "GUID:df380645f10b7bc4b97d4f5eb6303d95" + ], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Editor/Rive.Editor.asmdef.meta b/Packages/app.rive.rive-unity/Editor/Rive.Editor.asmdef.meta new file mode 100644 index 00000000..044ab6a8 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Rive.Editor.asmdef.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: e11e939ddee8146e1976384f79284b41 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Editor/Rive.Editor.asmdef + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Editor/Shaders.meta b/Packages/app.rive.rive-unity/Editor/Shaders.meta new file mode 100644 index 00000000..de22dbb4 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Shaders.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1530c7930ed7d4437995a5d0cdc9a669 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Editor/Shaders/SRGBEncodePreview.shader b/Packages/app.rive.rive-unity/Editor/Shaders/SRGBEncodePreview.shader new file mode 100644 index 00000000..93d5be51 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Shaders/SRGBEncodePreview.shader @@ -0,0 +1,60 @@ +// Editor-only shader for Rive asset preview in the Unity Inspector. +// This is a simple pass-through shader used ONLY for live preview in Linear color space projects in AssetEditor.cs. +// +// Why pass-through? +// - Rive outputs gamma into the RenderTexture +// - EditorGUI.DrawPreviewTexture expects sRGB input for correct display +// - We just pass the values through unchanged to avoid color conversion issues +// +// Note: Static preview uses a different path (Rive/UI/Default decode material + ReadPixels) so this shader is not used there. +Shader "Hidden/Rive/Editor/SRGBEncodePreview" +{ + SubShader + { + Tags { "RenderType"="Opaque" "Queue"="Overlay" } + Pass + { + ZWrite Off + Cull Off + ZTest Always + Blend One Zero + + HLSLPROGRAM + #pragma vertex vert + #pragma fragment frag + + #include "UnityCG.cginc" + + struct appdata + { + float4 vertex : POSITION; + float2 uv : TEXCOORD0; + }; + + struct v2f + { + float4 pos : SV_POSITION; + float2 uv : TEXCOORD0; + }; + + v2f vert(appdata v) + { + v2f o; + o.pos = UnityObjectToClipPos(v.vertex); + o.uv = v.uv; + return o; + } + + sampler2D _MainTex; + + float4 frag(v2f i) : SV_Target + { + // Simple pass-through: Rive RenderTexture contains gamma values, + // return them unchanged for correct display in EditorGUI preview + float4 c = tex2D(_MainTex, i.uv); + return c; + } + ENDHLSL + } + } +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Editor/Shaders/SRGBEncodePreview.shader.meta b/Packages/app.rive.rive-unity/Editor/Shaders/SRGBEncodePreview.shader.meta new file mode 100644 index 00000000..25590d30 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Shaders/SRGBEncodePreview.shader.meta @@ -0,0 +1,16 @@ +fileFormatVersion: 2 +guid: c21beb37ff9a947549f53fb49764de5a +ShaderImporter: + externalObjects: {} + defaultTextures: [] + nonModifiableTextures: [] + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Editor/Shaders/SRGBEncodePreview.shader + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Editor/WebGLBuildPreprocessor.cs b/Packages/app.rive.rive-unity/Editor/WebGLBuildPreprocessor.cs new file mode 100644 index 00000000..b236e90b --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/WebGLBuildPreprocessor.cs @@ -0,0 +1,209 @@ +#if UNITY_EDITOR && UNITY_WEBGL + +using UnityEditor; +using UnityEditor.Build; +using UnityEditor.Build.Reporting; +using System.Collections.Generic; +using System.Linq; + + +namespace Rive.EditorTools +{ + + /// Handles WebGL native plugin selection based on Unity version. + /// Different Unity versions require different Emscripten-compiled libraries: + /// - Unity 2022.x and earlier use Emscripten 3.1.8 + /// - Unity 2023.x (Unity 6) uses Emscripten 3.1.38 + /// If we don't match the emscripten library Unity uses, the build will fail with an error like: + /// - Building Library\Bee\artifacts\WebGL\build\debug_WebGL_wasm\build.js failed with output: + /// - wasm-ld: error: Library/PackageCache/app.rive.rive-unity/Runtime/Libraries/WebGL/librive_wasm.a(artboard.o): undefined symbol: std::__2::__vector_base_common::__throw_length_error() const + // - emcc: error: 'C:/6000.0.26f1/Editor/Data/PlaybackEngines/WebGLSupport/BuildTools/Emscripten/llvm\wasm-ld.exe @C:\Users\AppData\Local\Temp\emscripten_7f06ey06.rsp.utf-8' failed (returned 1) + /// + /// The ideal way to do this would've been to use BuildUtilities.RegisterShouldIncludeInBuildCallback, but that is only called for managed plugins and not native plugins: https://docs.unity3d.com/ScriptReference/PackageManager.BuildUtilities.RegisterShouldIncludeInBuildCallback.html + /// The other ideal way would've been to use `Define Constraints`, but that also doesn't work for native plugins: https://discussions.unity.com/t/define-constraints-are-not-filtering-plugins-pluginimporter-defineconstraints-also-has-no-effect/873361/5 + /// + /// This preprocessor ensures the correct library is included during WebGL builds by temporarily copying the appropriate libraries to the project's Plugin folder during the build + internal class WebGLBuildPreprocessor : IPreprocessBuildWithReport, IPostprocessBuildWithReport + { + + + + private const string PACKAGE_NAME = PackageInfo.PACKAGE_NAME; + private const string TEMP_PLUGINS_PATH = "Assets/Plugins/WebGL/Rive"; + private const string CREATED_FOLDERS_PREF = "RiveCreatedPluginFolders"; + + public int callbackOrder => 0; + + private static BuildReport currentBuildReport; + + + // We use this to cleanup the plugin files in case of build failure + // This is necessary because the IPostprocessBuildWithReport callback is not called when the build fails, only when it succeeds + private static void OnEditorUpdate() + { + if (currentBuildReport != null && (currentBuildReport.summary.result == BuildResult.Failed || currentBuildReport.summary.result == BuildResult.Cancelled)) + { + // Unsubscribe first to prevent any potential multiple calls + EditorApplication.update -= OnEditorUpdate; + + CleanupPluginFiles(); + + currentBuildReport = null; + } + } + + private void TrackCreatedFolder(string path) + { + var createdFolders = new HashSet( + SessionState.GetString(CREATED_FOLDERS_PREF, "").Split( + new[] { '|' }, System.StringSplitOptions.RemoveEmptyEntries) + ); + createdFolders.Add(path); + SessionState.SetString(CREATED_FOLDERS_PREF, string.Join("|", createdFolders)); + } + + private static bool WasCreatedByUs(string path) + { + var createdFolders = SessionState.GetString(CREATED_FOLDERS_PREF, "").Split( + new[] { '|' }, System.StringSplitOptions.RemoveEmptyEntries + ); + return System.Array.IndexOf(createdFolders, path) != -1; + } + + private static void ClearFolderTracking(string path) + { + var createdFolders = new HashSet( + SessionState.GetString(CREATED_FOLDERS_PREF, "").Split( + new[] { '|' }, System.StringSplitOptions.RemoveEmptyEntries) + ); + createdFolders.Remove(path); + SessionState.SetString(CREATED_FOLDERS_PREF, string.Join("|", createdFolders)); + } + + private static void CleanupBuildPrefs() + { + SessionState.EraseString(CREATED_FOLDERS_PREF); + } + public void OnPreprocessBuild(BuildReport report) + { + if (report.summary.platform != BuildTarget.WebGL) + return; + + + // Store the build report so we can cleanup the plugin files in case of build failure + currentBuildReport = report; + EditorApplication.update += OnEditorUpdate; + + // Clear any leftover prefs from previous builds that might have failed + CleanupBuildPrefs(); + + bool isUnity6OrNewer = UnityEngine.Application.unityVersion.StartsWith("6000") || + UnityEngine.Application.unityVersion.StartsWith("2023"); + + string emscriptenVersion = isUnity6OrNewer ? "3.1.38" : "3.1.8"; + string sourcePath = System.IO.Path.Combine("Packages", PACKAGE_NAME, "Runtime/Libraries/WebGL", $"emscripten_{emscriptenVersion}"); + + if (!System.IO.Directory.Exists(sourcePath)) + { + throw new BuildFailedException($"Rive: Could not find WebGL libraries at {sourcePath}"); + } + + // Create and track directories we need so we can clean them up later + string[] folders = { "Assets/Plugins", "Assets/Plugins/WebGL", TEMP_PLUGINS_PATH }; + foreach (string folder in folders) + { + if (!AssetDatabase.IsValidFolder(folder)) + { + System.IO.Directory.CreateDirectory(folder); + TrackCreatedFolder(folder); + } + } + + // Copy all .a files and configure them for WebGL + foreach (string file in System.IO.Directory.GetFiles(sourcePath, "*.a")) + { + string fileName = System.IO.Path.GetFileName(file); + string destFile = System.IO.Path.Combine(TEMP_PLUGINS_PATH, fileName); + System.IO.File.Copy(file, destFile, true); + + AssetDatabase.ImportAsset(destFile); + var importer = AssetImporter.GetAtPath(destFile) as PluginImporter; + if (importer != null) + { + importer.SetCompatibleWithAnyPlatform(false); + importer.SetCompatibleWithPlatform(BuildTarget.WebGL, true); + importer.SaveAndReimport(); + } + } + + AssetDatabase.Refresh(); + } + + private static bool IsDirectoryEmpty(string path) + { + return !AssetDatabase.FindAssets(string.Empty, new[] { path }).Any(); + } + + private static void DeleteAssetPath(string path) + { + if (AssetDatabase.DeleteAsset(path)) + { + ClearFolderTracking(path); + } + } + + public void OnPostprocessBuild(BuildReport report) + { + if (report.summary.platform != BuildTarget.WebGL) + return; + + try + { + CleanupPluginFiles(); + } + finally + { + // Unsubscribe from editor update since we're handling the cleanup here + EditorApplication.update -= OnEditorUpdate; + currentBuildReport = null; + } + } + + private static void CleanupPluginFiles() + { + try + { + if (AssetDatabase.IsValidFolder(TEMP_PLUGINS_PATH)) + { + DeleteAssetPath(TEMP_PLUGINS_PATH); + } + + // Check and clean up parent directories if empty and created by us + string webglPath = "Assets/Plugins/WebGL"; + if (AssetDatabase.IsValidFolder(webglPath) && + IsDirectoryEmpty(webglPath) && + WasCreatedByUs(webglPath)) + { + DeleteAssetPath(webglPath); + + string pluginsPath = "Assets/Plugins"; + if (AssetDatabase.IsValidFolder(pluginsPath) && + IsDirectoryEmpty(pluginsPath) && + WasCreatedByUs(pluginsPath)) + { + DeleteAssetPath(pluginsPath); + } + } + + AssetDatabase.Refresh(); + } + finally + { + // Cleanup prefs to avoid stale data on next build + CleanupBuildPrefs(); + } + } + } + +} +#endif diff --git a/Packages/app.rive.rive-unity/Editor/WebGLBuildPreprocessor.cs.meta b/Packages/app.rive.rive-unity/Editor/WebGLBuildPreprocessor.cs.meta new file mode 100644 index 00000000..d51258ef --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/WebGLBuildPreprocessor.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 34218ff81ba79467081fa78310f8e39d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Editor/WebGLBuildPreprocessor.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Editor/Windows.meta b/Packages/app.rive.rive-unity/Editor/Windows.meta new file mode 100644 index 00000000..fcbeb5eb --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Windows.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a08dea862c10b45f084ee22c62a638d9 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Editor/Windows/RiveQuickStartWindow.cs b/Packages/app.rive.rive-unity/Editor/Windows/RiveQuickStartWindow.cs new file mode 100644 index 00000000..226c80e7 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Windows/RiveQuickStartWindow.cs @@ -0,0 +1,225 @@ +using System; +using UnityEditor; +using UnityEngine; +using UnityEngine.UIElements; + +namespace Rive.EditorTools +{ + /// + /// Shows a welcome popup when the Unity Editor opens (once per session) unless the user opts out. + /// Also available through the Rive menu for later reference. + /// + internal class RiveQuickStartWindow : EditorWindow + { + private const string ShowOnStartKey = "Rive.Editor.Welcome.ShowOnStart"; + private const string SessionShownKey = "Rive.Editor.Welcome.ShownThisSession"; + private string _version; + + private static void ShowFromMenu() + { + CreateWindow(string.Empty).ShowUtility(); + } + + [MenuItem("Window/Rive/Quick Start", priority = 1000)] + private static void ShowFromToolsMenu() + { + ShowFromMenu(); + } + + [InitializeOnLoadMethod] + private static void ShowOnEditorOpen() + { + if (!IsShowOnStart()) + { + return; + } + + if (SessionState.GetBool(SessionShownKey, false)) + { + return; + } + + SessionState.SetBool(SessionShownKey, true); + // Delay to ensure the editor UI is fully initialized before showing. + EditorApplication.delayCall += () => + { + var window = CreateWindow(string.Empty); + window.ShowUtility(); + window.Focus(); + }; + } + + internal static bool IsShowOnStart() + { + return EditorPrefs.GetBool(ShowOnStartKey, true); + } + + private static void SetShowOnStart(bool show) + { + EditorPrefs.SetBool(ShowOnStartKey, show); + } + + private static RiveQuickStartWindow CreateWindow(string version) + { + var window = CreateInstance(); + window._version = version; + window.titleContent = new GUIContent("Rive for Unity"); + window.minSize = new Vector2(420, 520); + return window; + } + + public void CreateGUI() + { + BuildUI(); + } + + private void BuildUI() + { + var root = rootVisualElement; + root.Clear(); + root.style.flexDirection = FlexDirection.Column; + root.style.paddingLeft = 16; + root.style.paddingRight = 16; + root.style.paddingTop = 12; + root.style.paddingBottom = 12; + + var scroll = new ScrollView { verticalScrollerVisibility = ScrollerVisibility.Auto }; + scroll.style.flexGrow = 1; + scroll.style.marginTop = 6; + root.Add(scroll); + + var logo = AssetDatabase.LoadAssetAtPath("Packages/app.rive.rive-unity/Editor/Images/welcome-banner.png"); + if (logo != null) + { + var logoContainer = new VisualElement(); + logoContainer.style.paddingTop = 0; + logoContainer.style.paddingBottom = 0; + logoContainer.style.paddingLeft = 0; + logoContainer.style.paddingRight = 0; + logoContainer.style.alignItems = Align.Center; + logoContainer.style.marginBottom = 18; + logoContainer.style.maxHeight = 200; + + var logoImage = new Image + { + image = logo, + scaleMode = ScaleMode.ScaleAndCrop + }; + + logoImage.style.alignSelf = Align.Center; + + logoImage.style.borderTopLeftRadius = 7; + logoImage.style.borderTopRightRadius = 7; + logoImage.style.borderBottomLeftRadius = 7; + logoImage.style.borderBottomRightRadius = 7; + + logoImage.style.overflow = Overflow.Hidden; + + logoContainer.Add(logoImage); + scroll.Add(logoContainer); + } + + var subtitle = new Label("Rive is a new way to build menus, HUDs, and 2D graphics for games, with rich interactivity and state-driven animation."); + subtitle.style.whiteSpace = WhiteSpace.Normal; + subtitle.style.marginBottom = 12; + scroll.Add(subtitle); + + + + scroll.Add(CreateSection( + null, + ("Getting Started Guide", InspectorDocLinks.UnityGettingStarted, "Open the getting started guide for the Unity runtime"), + ("Website", InspectorDocLinks.RiveWebsite, "Open the Rive website"), + ("Support", InspectorDocLinks.RiveUnitySupport, "Open the issue tracker for the Rive Unity runtime") + )); + var footer = new VisualElement(); + footer.style.flexShrink = 0; + footer.style.marginTop = 8; + footer.style.paddingTop = 8; + footer.style.borderTopWidth = 1; + footer.style.borderTopColor = new UnityEngine.Color(0f, 0f, 0f, 0.1f); + root.Add(footer); + + var autoShowToggle = new Toggle("Show this window at startup") + { + value = IsShowOnStart() + }; + autoShowToggle.RegisterValueChangedCallback(evt => + { + SetShowOnStart(evt.newValue); + + }); + autoShowToggle.style.marginBottom = 8; + autoShowToggle.tooltip = "If enabled, this quick-start window will open when the editor starts (once per session)."; + footer.Add(autoShowToggle); + + var note = new Label("Reopen this window later via Window > Rive > Quick Start."); + note.style.color = new UnityEngine.Color(0.45f, 0.45f, 0.45f); + note.style.marginBottom = 4; + note.style.marginLeft = 3; + note.style.alignSelf = Align.FlexStart; + footer.Add(note); + + } + + private VisualElement CreateSection(string title, params (string label, string url, string tooltip)[] links) + { + var container = new VisualElement(); + container.style.marginTop = 8; + + + if (!String.IsNullOrEmpty(title)) + { + var header = new Label(title); + header.style.unityFontStyleAndWeight = FontStyle.Bold; + header.style.fontSize = 13; + header.style.marginBottom = 4; + container.Add(header); + } + + + foreach (var (label, url, tooltip) in links) + { + if (string.IsNullOrEmpty(url)) + { + var suggestion = new Label($"• {label}"); + suggestion.style.color = new UnityEngine.Color(0.55f, 0.55f, 0.55f); + suggestion.style.marginBottom = 4; + container.Add(suggestion); + } + else + { + var btn = CreateLinkButton(label, url, tooltip); + btn.style.marginBottom = 4; + container.Add(btn); + } + } + + return container; + } + + private Button CreateLinkButton(string text, string url, string tooltip = "") + { + var button = new Button(); + button.text = text; + button.style.height = 28; + button.style.justifyContent = Justify.FlexStart; + button.style.paddingLeft = 10; + if (!string.IsNullOrEmpty(tooltip)) + { + button.tooltip = tooltip; + } + + if (string.IsNullOrEmpty(url)) + { + button.SetEnabled(false); + } + else + { + button.clicked += () => Application.OpenURL(url); + } + + return button; + } + } +} diff --git a/Packages/app.rive.rive-unity/Editor/Windows/RiveQuickStartWindow.cs.meta b/Packages/app.rive.rive-unity/Editor/Windows/RiveQuickStartWindow.cs.meta new file mode 100644 index 00000000..84f3a500 --- /dev/null +++ b/Packages/app.rive.rive-unity/Editor/Windows/RiveQuickStartWindow.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 3fa3b72758f07491e9cc011de8171f3d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Editor/Windows/RiveQuickStartWindow.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime.meta b/Packages/app.rive.rive-unity/Runtime.meta new file mode 100644 index 00000000..9bc9fd61 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c1f1aebfce5664487a814cdfaa9d1898 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Runtime/Alignment.cs b/Packages/app.rive.rive-unity/Runtime/Alignment.cs new file mode 100644 index 00000000..26096a65 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Alignment.cs @@ -0,0 +1,82 @@ +using System; + +namespace Rive +{ + /// + /// Alignment is used to align the content of a Rive visual within the available bounds. + /// + [System.Serializable] + public struct Alignment : IEquatable + { + public Alignment(float x, float y) + { + m_x = x; + m_y = y; + } + + [UnityEngine.SerializeField] + private float m_x; + + [UnityEngine.SerializeField] + private float m_y; + + public float X + { + get { return m_x; } + } + + public float Y + { + get { return m_y; } + } + + public override string ToString() + { + return $"X: {m_x}, Y: {m_y}"; + } + + public static readonly Alignment TopLeft = new(-1.0f, -1.0f); + public static readonly Alignment TopCenter = new(0.0f, -1.0f); + public static readonly Alignment TopRight = new(1.0f, -1.0f); + public static readonly Alignment CenterLeft = new(-1.0f, 0.0f); + public static readonly Alignment Center = new(0.0f, 0.0f); + public static readonly Alignment CenterRight = new(1.0f, 0.0f); + public static readonly Alignment BottomLeft = new(-1.0f, 1.0f); + public static readonly Alignment BottomCenter = new(0.0f, 1.0f); + public static readonly Alignment BottomRight = new(1.0f, 1.0f); + + + public bool Equals(Alignment other) + { + return m_x.Equals(other.m_x) && m_y.Equals(other.m_y); + } + + public override bool Equals(object obj) + { + return obj is Alignment other && Equals(other); + } + + public override int GetHashCode() + { + return HashCode.Combine(m_x, m_y); + } + + public static bool operator ==(Alignment left, Alignment right) + { + return left.Equals(right); + } + + public static bool operator !=(Alignment left, Alignment right) + { + return !(left == right); + } + + +#if UNITY_EDITOR + internal static string BindingPath_Xfield => nameof(m_x); + internal static string BindingPath_Yfield => nameof(m_y); +#endif + } + + +} diff --git a/Packages/app.rive.rive-unity/Runtime/Alignment.cs.meta b/Packages/app.rive.rive-unity/Runtime/Alignment.cs.meta new file mode 100644 index 00000000..ee06cd1c --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Alignment.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 2fe0dd2d873c64b7d92729cf0d4b4d1f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Alignment.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Artboard.cs b/Packages/app.rive.rive-unity/Runtime/Artboard.cs new file mode 100644 index 00000000..538e99fa --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Artboard.cs @@ -0,0 +1,570 @@ +using UnityEngine; +using System; +using System.Runtime.InteropServices; +using Rive.Utils; + +namespace Rive +{ + /// + /// Represents a Rive Artboard with a File. An Artboard contains StateMachines and Animations. + /// + public class Artboard : IDisposable + { + private readonly IntPtr m_nativeArtboard; + private string m_artboardName; + private ViewModelInstance m_currentViewModelInstance; + private ViewModel m_defaultViewModel; + + private WeakReference m_file; + private bool m_isDisposed = false; + + internal IntPtr NativeArtboard + { + get { return m_nativeArtboard; } + } + + /// + /// Returns true if the artboard has been disposed. + /// + public bool IsDisposed { get => m_isDisposed; } + + /// + /// Constructor for the Artboard class. + /// + /// Pointer to the native artboard. + /// The file that instanced the artboard. + internal Artboard(IntPtr nativeArtboard, File file) + { + m_nativeArtboard = nativeArtboard; + m_file = new WeakReference(file); + } + + /// + /// Dispose of the Artboard and release native resources. + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (!m_isDisposed) + { + if (m_nativeArtboard != IntPtr.Zero) + { + unrefArtboard(m_nativeArtboard); + } + m_isDisposed = true; + } + } + + ~Artboard() + { + Dispose(false); + } + + public Vector2 LocalCoordinate( + Vector2 screenPosition, + Rect screen, + Fit fit, + Alignment alignment + ) + { + Vec2D vec = screenToRive( + screenPosition.x, + screenPosition.y, + screen.xMin, + screen.yMin, + screen.xMax, + screen.yMax, + (byte)fit, + alignment.X, + alignment.Y, + m_nativeArtboard + ); + return new Vector2(vec.x, vec.y); + } + + [Obsolete("Component is deprecated and will be removed in a future release. Please use Databinding instead.")] + public Component Component(string name) + { + var ptr = artboardComponentNamed(m_nativeArtboard, name); + if (ptr == IntPtr.Zero) + { + return null; + } + return new Component(ptr); + } + + + public string Name + { + get + { + if (m_artboardName == null) + { + m_artboardName = Marshal.PtrToStringAnsi(artboardGetName(m_nativeArtboard)); + } + + return m_artboardName; + } + } + + /// + /// Returns true if the artboard has audio. + /// + public bool HasAudio + { + get + { + return artboardHasAudio(m_nativeArtboard); + } + } + + /// + /// Sets the value of a text run with the provided name. + /// + /// The name of the text run. + /// The new value for the text run. + /// + public bool SetTextRun(string name, string value) + { + return artboardSetRunValue(m_nativeArtboard, name, value); + } + + /// + /// Gets the value of a text run with the provided name. + /// + /// The name of the text run. + /// The value of the text run, or null if not found. + public string GetTextRunValue(string runName) + { + return Marshal.PtrToStringAnsi(artboardGetTextRunValue(m_nativeArtboard, runName)); + } + + /// + /// Sets the value of a text run with the provided name at the given path. + /// + /// The name of the text run. + /// The path to the nested artboard where the text run is located. + /// The new value for the text run. + /// True if the text run was successfully set, false otherwise. + public bool SetTextRunValueAtPath(string runName, string path, string value) + { + return artboardSetTextRunValueAtPath(m_nativeArtboard, runName, path, value); + } + + /// + /// Gets the value of a text run with the provided name at the given path. + /// + /// The name of the text run. + /// The path to the nested artboard where the text run is located. + /// The value of the text run, or null if not found. + public string GetTextRunValueAtPath(string runName, string path) + { + return Marshal.PtrToStringAnsi(artboardGetTextRunValueAtPath(m_nativeArtboard, runName, path)); + } + + /// + /// Gets or sets the width of the artboard instance. + /// + public float Width + { + get => getArtboardWidth(m_nativeArtboard); + set => setArtboardWidth(m_nativeArtboard, value); + } + + /// + /// Gets or sets the height of the artboard instance. + /// + public float Height + { + get => getArtboardHeight(m_nativeArtboard); + set => setArtboardHeight(m_nativeArtboard, value); + } + + /// + /// Returns true if the artboard has changed since the last draw. + /// + public bool DidChange() + { + return artboardDidChange(m_nativeArtboard); + } + + /// Returns the number of StateMachines stored in the artboard. + public uint StateMachineCount + { + get { return getStateMachineCount(m_nativeArtboard); } + } + + + /// + /// The default ViewModel for the artboard. + /// + public ViewModel DefaultViewModel + { + get + { + if (m_defaultViewModel == null) + { + var file = m_file.TryGetTarget(out var target) ? target : null; + if (file != null) + { + m_defaultViewModel = file.GetDefaultViewModelForArtboard(this.m_nativeArtboard); + } + } + + return m_defaultViewModel; + } + } + + /// Returns the name of the StateMachine at the given index. + public string StateMachineName(uint index) + { + return Marshal.PtrToStringAnsi(getStateMachineName(m_nativeArtboard, index)); + } + + /// Instance a StateMachine from the Artboard. + public StateMachine StateMachine(uint index) + { + IntPtr ptr = instanceStateMachineAtIndex(m_nativeArtboard, index); + if (ptr == IntPtr.Zero) + { + DebugLogger.Instance.Log($"No StateMachine at index {index}."); + return null; + } + return new StateMachine(ptr); + } + + /// Instance a StateMachine from the Artboard. + public StateMachine StateMachine(string name) + { + IntPtr ptr = instanceStateMachineWithName(m_nativeArtboard, name); + if (ptr == IntPtr.Zero) + { + DebugLogger.Instance.Log($"No StateMachine named \"{name}\"."); + return null; + } + return new StateMachine(ptr); + } + + /// Instance the default StateMachine from the Artboard. + public StateMachine StateMachine() + { + IntPtr ptr = instanceStateMachineDefault(m_nativeArtboard); + if (ptr == IntPtr.Zero) + { + DebugLogger.Instance.Log($"No default StateMachine found."); + return null; + } + return new StateMachine(ptr); + } + + public void SetAudioEngine(AudioEngine audioEngine) + { + setArtboardAudioEngine(m_nativeArtboard, audioEngine.m_nativeAudioEngine); + } + + internal IntPtr GetInputAtPath(string inputName, string path) + { + // Validate the input parameters + if (string.IsNullOrEmpty(inputName)) + { + DebugLogger.Instance.LogWarning($"No input name provided for path '{path}' ."); + return IntPtr.Zero; + } + + if (string.IsNullOrEmpty(path)) + { + DebugLogger.Instance.LogWarning($"No path provided for input '{inputName}'."); + return IntPtr.Zero; + } + + + IntPtr ptr = getSMIInputAtPathArtboard(m_nativeArtboard, inputName, path); + + return ptr; + } + + private void LogMissingInputWarning(string inputName, string path) + { + DebugLogger.Instance.LogWarning($"No input found at path '{path}' with name '{inputName}'."); + } + + private void LogIncorrectInputTypeWarning(string inputName, string path, string expectedType) + { + DebugLogger.Instance.LogWarning($"Input '{inputName}' at path: '{path}' is not a {expectedType} input."); + } + + // Add this description to the method: Set the boolean input with the provided name at the given path with value + + /// + /// Set the boolean input with the provided name at the given path with value. + /// + /// The name of the input to set. + /// The value to set the input to. + /// The location of the input at an artboard level, detailing nested locations if applicable. + public void SetBooleanInputStateAtPath(string inputName, bool value, string path) + { + var nativeSmi = GetInputAtPath(inputName, path); + if (nativeSmi == IntPtr.Zero) + { + LogMissingInputWarning(inputName, path); + return; + } + + if (SMIInput.isSMIBoolean(nativeSmi)) + { + + SMIBool.setSMIBoolValueStateMachine(nativeSmi, value); + } + else + { + LogIncorrectInputTypeWarning(inputName, path, "boolean"); + } + + } + + /// + /// Get the boolean input value with the provided name at the given path. + /// + /// The state machine input name + /// The location of the input at an artboard level, detailing nested locations if applicable. + /// The value of the boolean input. + public bool? GetBooleanInputStateAtPath(string inputName, string path) + { + var nativeSmi = GetInputAtPath(inputName, path); + if (nativeSmi == IntPtr.Zero) + { + LogMissingInputWarning(inputName, path); + return null; + } + + if (SMIInput.isSMIBoolean(nativeSmi)) + { + return SMIBool.getSMIBoolValueStateMachine(nativeSmi); + } + else + { + LogIncorrectInputTypeWarning(inputName, path, "boolean"); + return null; + } + } + + /// + /// Set the number input with the provided name at the given path with value. + /// + /// + /// The number value to set the input to. + /// The location of the input at an artboard level, detailing nested locations if applicable. + public void SetNumberInputStateAtPath(string inputName, float value, string path) + { + var nativeSmi = GetInputAtPath(inputName, path); + if (nativeSmi == IntPtr.Zero) + { + LogMissingInputWarning(inputName, path); + return; + } + + if (SMIInput.isSMINumber(nativeSmi)) + { + SMINumber.setSMINumberValueStateMachine(nativeSmi, value); + } + else + { + LogIncorrectInputTypeWarning(inputName, path, "number"); + } + } + + /// + /// Get the number input value with the provided name at the given path. + /// + /// The state machine input name + /// The location of the input at an artboard level, detailing nested locations if applicable. + /// The value of the number input. + public float? GetNumberInputStateAtPath(string inputName, string path) + { + var nativeSmi = GetInputAtPath(inputName, path); + if (nativeSmi == IntPtr.Zero) + { + LogMissingInputWarning(inputName, path); + return null; + } + + if (SMIInput.isSMINumber(nativeSmi)) + { + return SMINumber.getSMINumberValueStateMachine(nativeSmi); + } + else + { + LogIncorrectInputTypeWarning(inputName, path, "number"); + return null; + } + } + + /// + /// Fire the trigger input with the provided name at the given path + /// + /// The state machine input name + /// The location of the input at an artboard level, detailing nested locations if applicable. + public void FireInputStateAtPath(string inputName, string path) + { + var nativeSmi = GetInputAtPath(inputName, path); + if (nativeSmi == IntPtr.Zero) + { + LogMissingInputWarning(inputName, path); + return; + } + + if (SMIInput.isSMITrigger(nativeSmi)) + { + SMITrigger.fireSMITriggerStateMachine(nativeSmi); + } + else + { + LogIncorrectInputTypeWarning(inputName, path, "trigger"); + } + } + + /// + /// Resets the artboard to its original dimensions. + /// + public void ResetArtboardSize() + { + Width = getArtboardOriginalWidth(m_nativeArtboard); + Height = getArtboardOriginalHeight(m_nativeArtboard); + } + + + /// + /// Sets the data context of the Artboard from the given ViewModelInstance. + /// + /// The ViewModelInstance to bind to the Artboard. + /// + /// This method binds the ViewModelInstance to the Artboard only. If you intend to bind related state machines, + /// you should use the method instead as it automatically binds both the Artboard and the State Machine to the ViewModelInstance. + /// + public void BindViewModelInstance(ViewModelInstance viewModelInstance) + { + if (viewModelInstance == null) + { + DebugLogger.Instance.LogError("ViewModelInstance is null."); + return; + } + + + bindViewModelInstanceToArtboard(NativeArtboard, viewModelInstance.NativeSafeHandle); + + m_currentViewModelInstance = viewModelInstance; + + } + + + + + #region Native Methods + [DllImport(NativeLibrary.name)] + internal static extern void unrefArtboard(IntPtr artboard); + + [DllImport(NativeLibrary.name)] + internal static extern uint getStateMachineCount(IntPtr artboard); + + [DllImport(NativeLibrary.name)] + internal static extern IntPtr getStateMachineName(IntPtr artboard, uint index); + + [DllImport(NativeLibrary.name)] + internal static extern float getArtboardWidth(IntPtr artboard); + + [DllImport(NativeLibrary.name)] + internal static extern float getArtboardHeight(IntPtr artboard); + + [DllImport(NativeLibrary.name)] + internal static extern bool artboardDidChange(IntPtr artboard); + + + + [DllImport(NativeLibrary.name)] + internal static extern float getArtboardOriginalWidth(IntPtr artboard); + + [DllImport(NativeLibrary.name)] + internal static extern float getArtboardOriginalHeight(IntPtr artboard); + + [DllImport(NativeLibrary.name)] + internal static extern void setArtboardWidth(IntPtr artboard, float width); + + [DllImport(NativeLibrary.name)] + internal static extern void setArtboardHeight(IntPtr artboard, float height); + + + [DllImport(NativeLibrary.name)] + internal static extern IntPtr instanceStateMachineAtIndex(IntPtr artboard, uint index); + + [DllImport(NativeLibrary.name)] + internal static extern IntPtr instanceStateMachineWithName(IntPtr artboard, string name); + + [DllImport(NativeLibrary.name)] + internal static extern IntPtr instanceStateMachineDefault(IntPtr artboard); + + [DllImport(NativeLibrary.name)] + internal static extern Vec2D screenToRive( + float x, + float y, + float screenX, + float screenY, + float screenWidth, + float screenHeight, + byte fit, + float alignX, + float alignY, + IntPtr artboard + ); + + [DllImport(NativeLibrary.name)] + internal static extern void setArtboardAudioEngine(IntPtr artboard, IntPtr audioEngine); + + [DllImport(NativeLibrary.name)] + internal static extern bool artboardHasAudio(IntPtr artboard); + + [DllImport(NativeLibrary.name)] + internal static extern IntPtr artboardComponentNamed(IntPtr artboard, string name); + + [DllImport(NativeLibrary.name)] + internal static extern bool artboardSetRunValue( + IntPtr artboard, + string runName, + string text + ); + + [DllImport(NativeLibrary.name)] + internal static extern IntPtr getSMIInputAtPathArtboard(IntPtr artboard, string inputName, string path); + + [DllImport(NativeLibrary.name)] + internal static extern IntPtr artboardGetTextRunValue(IntPtr artboard, string runName); + + [DllImport(NativeLibrary.name)] + internal static extern bool artboardSetTextRunValueAtPath(IntPtr artboard, string runName, string path, string text); + + [DllImport(NativeLibrary.name)] + internal static extern IntPtr artboardGetTextRunValueAtPath(IntPtr artboard, string runName, string path); + + + [DllImport(NativeLibrary.name)] + internal static extern IntPtr artboardGetName(IntPtr artboard); + + // Data binding + + + [DllImport(NativeLibrary.name)] + internal static extern void bindViewModelInstanceToArtboard(IntPtr artboard, ViewModelInstanceSafeHandle viewModelInstance); + #endregion + } +} + +[StructLayout(LayoutKind.Sequential)] +internal struct Vec2D +{ + public float x; + public float y; +} diff --git a/Packages/app.rive.rive-unity/Runtime/Artboard.cs.meta b/Packages/app.rive.rive-unity/Runtime/Artboard.cs.meta new file mode 100644 index 00000000..71600643 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Artboard.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 3fe7ba03515cf4422be26402e8d5e28a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Artboard.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Asset.cs b/Packages/app.rive.rive-unity/Runtime/Asset.cs new file mode 100644 index 00000000..8c3528ba --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Asset.cs @@ -0,0 +1,383 @@ +using System; +using System.Collections.Generic; +#if UNITY_EDITOR +using System.Linq; +#endif +using Rive.Utils; + +using UnityEngine; + +namespace Rive +{ + + + + [Serializable] + internal class FileMetadata + { +#if UNITY_EDITOR + + private const int CURRENT_VERSION = 1; // Increment this whenever the structure changes + [SerializeField] private int m_Version = 1; //And also update this so we can check for changes in the future + + [Serializable] + public class InputMetadata + { + public string Name; + public string Type; + } + + [Serializable] + public class StateMachineMetadata + { + public string Name; + public List Inputs = new List(); + } + + [Serializable] + public class ViewModelPropertyMetadata + { + public string Name; + public ViewModelDataType Type; + + /// + /// The name of the nested view model if the property is a view model. + /// + public string NestedViewModelName; + + /// + /// The name of the enum type if the property is an enum. + /// + public string EnumTypeName; + + public static ViewModelPropertyMetadata FromPropertyData(ViewModelPropertyData propertyData, ViewModel viewModel) + { + if (propertyData.Type == ViewModelDataType.ViewModel) + { + // Get the view model name by loading a view model instance and getting the name of the view model + var instance = viewModel.CreateInstance(); + + ViewModelInstance nestedInstance = instance.GetProperty(propertyData.Name); + + if (nestedInstance == null) + { + DebugLogger.Instance.LogWarning("Could not find nested view model instance for property " + propertyData.Name); + return new ViewModelPropertyMetadata + { + Name = propertyData.Name, + Type = propertyData.Type + }; + } + + string nestedViewModelName = nestedInstance.ViewModelName; + + nestedInstance.Dispose(); // We don't need the instance anymore + + return new ViewModelPropertyMetadata + { + Name = propertyData.Name, + Type = propertyData.Type, + NestedViewModelName = nestedViewModelName + }; + } + else if (propertyData.Type == ViewModelDataType.Enum) + { + // Get the enum name by loading a view model instance and getting the associated enum type. + // Unfortunately, we need to do it this way because the native API doesn't expose the enum type name directly from the property data. + var instance = viewModel.CreateInstance(); + + + var enumType = ViewModelInstancePropertyHandlersFactory.GetEnumForPropertyAtPath(instance, propertyData.Name); + + instance.Dispose(); // We don't need the instance anymore + + return new ViewModelPropertyMetadata + { + Name = propertyData.Name, + Type = propertyData.Type, + EnumTypeName = enumType?.Name + }; + + } + + + return new ViewModelPropertyMetadata + { + Name = propertyData.Name, + Type = propertyData.Type + }; + } + } + + [Serializable] + public class ArtboardMetadata + { + + [SerializeField] private string m_Name; + + [SerializeField] private float m_Width; + + [SerializeField] private float m_Height; + + [SerializeField] private List m_StateMachines; + + [SerializeField] private ViewModelMetadata m_DefaultViewModel; + + public string Name { get { return m_Name; } } + public float Width { get { return m_Width; } } + public float Height { get { return m_Height; } } + public List StateMachines { get { return m_StateMachines; } } + + public ViewModelMetadata DefaultViewModel { get { return m_DefaultViewModel; } } + + public ArtboardMetadata(string name, float width, float height, List stateMachines, ViewModelMetadata defaultViewModel) + { + m_Name = name; + m_Width = width; + m_Height = height; + m_StateMachines = stateMachines == null ? new List() : stateMachines; + m_DefaultViewModel = defaultViewModel; + } + } + + [Serializable] + public class ViewModelMetadata + { + /// + /// The name of the view model. + /// + public string Name; + + /// + /// The properties of the view model. + /// + public List Properties = new List(); + + /// + /// The names of the instances of this view model within the Rive file. + /// + public List InstanceNames = new List(); + + public static ViewModelMetadata FromViewModel(ViewModel viewModel) + { + var viewModelMeta = new ViewModelMetadata + { + Name = viewModel.Name + }; + + IReadOnlyList properties = viewModel.Properties; + + foreach (var property in properties) + { + viewModelMeta.Properties.Add(ViewModelPropertyMetadata.FromPropertyData(property, viewModel)); + } + + viewModelMeta.InstanceNames.AddRange(viewModel.InstanceNames); + + return viewModelMeta; + } + } + + [Serializable] + public class ViewModelEnumMetadata + { + [SerializeField] private string m_Name; + + [SerializeField] private string[] m_Values; + + public string Name { get { return m_Name; } } + public IReadOnlyList Values { get { return m_Values; } } + + public ViewModelEnumMetadata(string name, IReadOnlyList values) + { + m_Name = name; + m_Values = values.ToArray(); + } + } + + public List Artboards = new List(); + + public List ViewModels = new List(); + + public List Enums = new List(); + + public string[] GetArtboardNames() + { + return Artboards.Select(a => a.Name).ToArray(); + } + + public string[] GetStateMachineNames(string artboardName) + { + var artboard = Artboards.FirstOrDefault(a => a.Name == artboardName); + return artboard?.StateMachines.Select(sm => sm.Name).ToArray() ?? new string[0]; + } + + public ArtboardMetadata GetArtboard(string name) + { + return Artboards.FirstOrDefault(a => a.Name == name); + } + + public bool NeedsReload() + { + // Force reload for unversioned (0) or outdated data + return m_Version != CURRENT_VERSION; + } +#endif + } + + + /// + /// Represents a Rive asset (.riv) + /// + public class Asset : ScriptableObject + { + [HideInInspector] + [SerializeField] + private byte[] m_Bytes; + + /// + /// The raw bytes of the Rive asset + /// + public byte[] Bytes { get { return m_Bytes; } } + + [HideInInspector] + [SerializeField] + private EmbeddedAssetData[] m_EmbeddedAssets; + + /// + /// An array of all the embedded asset data in this Rive asset + /// + public IReadOnlyList EmbeddedAssets { get { return m_EmbeddedAssets; } } + + /// + /// The number of embedded asset data in this Rive asset + /// + public int EmbeddedAssetCount { get { return m_EmbeddedAssets == null ? 0 : m_EmbeddedAssets.Length; } } + +#if UNITY_EDITOR + [SerializeField] + private FileMetadata m_FileMetadata; + + /// + /// Metadata about the contents of the Rive file. Available only in the Unity editor. + /// + internal FileMetadata EditorOnlyMetadata + { + get + { + if (m_FileMetadata == null || m_FileMetadata.NeedsReload()) + { + GenerateFileMetadata(); + } + return m_FileMetadata; + } + } + + private void GenerateFileMetadata() + { + m_FileMetadata = new FileMetadata(); + + using (var file = File.Load(this)) + { + if (file == null) return; + + // View models + + IReadOnlyList viewModels = file.ViewModels; + + foreach (var viewModel in viewModels) + { + var viewModelMeta = FileMetadata.ViewModelMetadata.FromViewModel(viewModel); + + m_FileMetadata.ViewModels.Add(viewModelMeta); + } + + // Enums + + foreach (var enumData in file.ViewModelEnums) + { + var enumMeta = new FileMetadata.ViewModelEnumMetadata(enumData.Name, enumData.Values); + m_FileMetadata.Enums.Add(enumMeta); + } + + + for (uint i = 0; i < file.ArtboardCount; i++) + { + var artboard = file.Artboard(i); + if (artboard == null) continue; + + FileMetadata.ViewModelMetadata defaultViewModel = null; + + if (artboard.DefaultViewModel != null) + { + defaultViewModel = FileMetadata.ViewModelMetadata.FromViewModel(artboard.DefaultViewModel); + + } + + var artboardMeta = new FileMetadata.ArtboardMetadata(name: file.ArtboardName(i), width: artboard.Width, height: artboard.Height, stateMachines: new List(), defaultViewModel: defaultViewModel); + + + for (uint j = 0; j < artboard.StateMachineCount; j++) + { + var stateMachine = artboard.StateMachine(j); + if (stateMachine == null) continue; + + var smMeta = new FileMetadata.StateMachineMetadata + { + Name = artboard.StateMachineName(j) + }; + + foreach (var input in stateMachine.Inputs()) + { + var inputMeta = new FileMetadata.InputMetadata + { + Name = input.Name, + Type = input.IsBoolean ? "Boolean" : + input.IsNumber ? "Number" : + input.IsTrigger ? "Trigger" : "Unknown" + }; + smMeta.Inputs.Add(inputMeta); + } + + + artboardMeta.StateMachines.Add(smMeta); + } + + m_FileMetadata.Artboards.Add(artboardMeta); + } + } + } +#endif + + /// + /// Initializes the asset with the given bytes and embedded asset information. + /// + /// The raw bytes of the Rive asset. + /// The embedded asset data in the Rive asset. + internal void SetData(byte[] bytes, EmbeddedAssetData[] embeddedAssetsData) + { + m_Bytes = bytes; + m_EmbeddedAssets = embeddedAssetsData; + +#if UNITY_EDITOR + GenerateFileMetadata(); +#endif + } + + /// + /// Create a new Rive asset instance from the given bytes and embedded asset data. + /// + /// The raw bytes of the Rive asset. + /// The embedded asset data in the Rive asset. + /// The created Rive asset instance. + public static Asset Create(byte[] bytes, EmbeddedAssetData[] embeddedAssetsData) + { + var asset = ScriptableObject.CreateInstance(); + asset.SetData(bytes, embeddedAssetsData); + return asset; + } + + } + + +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Runtime/Asset.cs.meta b/Packages/app.rive.rive-unity/Runtime/Asset.cs.meta new file mode 100644 index 00000000..e49ece64 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Asset.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 7f4fd555db5124bb8afcff52b5d9ed5a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: df0df084c4eaa4149a9c988c71b85313, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Asset.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/AudioEmbeddedAssetReference.cs b/Packages/app.rive.rive-unity/Runtime/AudioEmbeddedAssetReference.cs new file mode 100644 index 00000000..699e965d --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/AudioEmbeddedAssetReference.cs @@ -0,0 +1,36 @@ +namespace Rive +{ + + + /// + /// Represents an Audio file asset within a specific Rive file. + /// + public class AudioEmbeddedAssetReference : EmbeddedAssetReference + { + [System.Obsolete] + public AudioEmbeddedAssetReference(EmbeddedAssetData embeddedAssetData, uint index) + : base(embeddedAssetData, index) + { + } + + [System.Obsolete] + public AudioEmbeddedAssetReference(EmbeddedAssetType assetType, uint id, string name, uint embeddededBytesSize, uint index, OutOfBandAsset outOfBandAsset) : base(assetType, id, name, embeddededBytesSize, index, outOfBandAsset) + { + } + + internal AudioEmbeddedAssetReference(InitializationData initializationData) : base(initializationData) + { + } + + /// + /// Updates the image asset reference in the Rive file. + /// + /// + public void SetAudio(AudioOutOfBandAsset audioAsset) + { + this.UpdateEmbeddedAssetReferenceInFile(audioAsset); + } + } + + +} diff --git a/Packages/app.rive.rive-unity/Runtime/AudioEmbeddedAssetReference.cs.meta b/Packages/app.rive.rive-unity/Runtime/AudioEmbeddedAssetReference.cs.meta new file mode 100644 index 00000000..8b787aa8 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/AudioEmbeddedAssetReference.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: fde3b3762796c4aae9703b3140d41e7d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/AudioEmbeddedAssetReference.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/AudioEngine.cs b/Packages/app.rive.rive-unity/Runtime/AudioEngine.cs new file mode 100644 index 00000000..0d521168 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/AudioEngine.cs @@ -0,0 +1,63 @@ +using UnityEngine; +using System; +using System.Runtime.InteropServices; + +namespace Rive +{ + public class AudioEngine + { + internal IntPtr m_nativeAudioEngine; + + private AudioEngine(IntPtr engine) + { + m_nativeAudioEngine = engine; + } + + public void Read(float[] data, int channels) + { + readAudioEngine(m_nativeAudioEngine, data, (uint)(data.Length / channels)); + } + + public void Sum(float[] data, int channels) + { + sumAudioEngine(m_nativeAudioEngine, data, (uint)(data.Length / channels)); + } + + ~AudioEngine() + { + unrefAudioEngine(m_nativeAudioEngine); + } + + public static AudioEngine Make(int numChannels, int sampleRate) + { + var nativeEngine = makeAudioEngine((uint)numChannels, (uint)sampleRate); + if (nativeEngine == IntPtr.Zero) + { + return null; + } + return new AudioEngine(nativeEngine); + } + + #region Native Methods + [DllImport(NativeLibrary.name)] + private static extern void unrefAudioEngine(IntPtr audioEngine); + + [DllImport(NativeLibrary.name)] + internal static extern void readAudioEngine( + IntPtr audioEngine, + float[] frames, + uint frameCount + ); + + [DllImport(NativeLibrary.name)] + internal static extern void sumAudioEngine( + IntPtr audioEngine, + float[] frames, + uint frameCount + ); + + [DllImport(NativeLibrary.name)] + internal static extern IntPtr makeAudioEngine(uint numChannels, uint sampleRate); + #endregion + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/AudioEngine.cs.meta b/Packages/app.rive.rive-unity/Runtime/AudioEngine.cs.meta new file mode 100644 index 00000000..a5e0da05 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/AudioEngine.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 176c718067c54431f9b1951c422529fb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/AudioEngine.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/AudioOutOfBandAsset.cs b/Packages/app.rive.rive-unity/Runtime/AudioOutOfBandAsset.cs new file mode 100644 index 00000000..46365c3c --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/AudioOutOfBandAsset.cs @@ -0,0 +1,29 @@ +using System; +using System.Runtime.InteropServices; + +namespace Rive +{ + /// + /// Represents an out-of-band Rive font asset. + /// + public class AudioOutOfBandAsset : OutOfBandAsset + { + protected override IntPtr LoadNative(byte[] data) + { + return loadAudioSource(data, (nuint)data.Length); + } + + protected override void UnloadNative(IntPtr nativePtr) + { + unrefAudioSource(nativePtr); + } + + #region Native Methods + [DllImport(NativeLibrary.name)] + private static extern IntPtr loadAudioSource(byte[] bytes, nuint byteCount); + + [DllImport(NativeLibrary.name)] + private static extern void unrefAudioSource(IntPtr audioSource); + #endregion + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/AudioOutOfBandAsset.cs.meta b/Packages/app.rive.rive-unity/Runtime/AudioOutOfBandAsset.cs.meta new file mode 100644 index 00000000..0f36fac3 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/AudioOutOfBandAsset.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: f438b8e4861d745a79fbf2856a04f71f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: df0df084c4eaa4149a9c988c71b85313, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/AudioOutOfBandAsset.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Color.cs b/Packages/app.rive.rive-unity/Runtime/Color.cs new file mode 100644 index 00000000..7573f111 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Color.cs @@ -0,0 +1,111 @@ +using UnityEngine; + +namespace Rive +{ + /// + /// A 32 bit color + /// + public struct Color + { + public uint value; + + /// + /// Creates a new color from the given ARGB values. + /// + static public Color FromARGB(uint a, uint r, uint g, uint b) + { + return new Color( + ((a & 0xff) << 24) | ((r & 0xff) << 16) | ((g & 0xff) << 8) | ((b & 0xff) << 0) + ); + } + + /// + /// Creates a new color from the given RGBO values. + /// + static public Color FromRGBO(uint r, uint g, uint b, float opacity) + { + return new Color( + ((((uint)Mathf.FloorToInt(opacity * 0xff)) & 0xff) << 24) + | ((r & 0xff) << 16) + | ((g & 0xff) << 8) + | ((b & 0xff) << 0) + ); + } + + /// + /// Creates a new color from the given 32 bit value. + /// + public Color(uint value) + { + this.value = value & 0xffffffff; + } + + readonly uint Alpha + { + get { return (0xff000000 & value) >> 24; } + } + + float Opacity + { + get { return Alpha / 0xff; } + } + + readonly uint Red + { + get { return (0x00ff0000 & value) >> 16; } + } + + readonly uint Green + { + get { return (0x0000ff00 & value) >> 8; } + } + + readonly uint Blue + { + get { return (0x000000ff & value) >> 0; } + } + + /// + /// Returns a new color from this color with the given alpha value. + /// + public Color WithAlpha(uint a) + { + return Color.FromARGB(a, Red, Green, Blue); + } + + /// + /// Returns a new color from this color with the given opacity value. + /// + public Color WithOpacity(float opacity) + { + return WithAlpha((uint)Mathf.RoundToInt(255.0f * opacity)); + } + + public override readonly bool Equals(object obj) + { + if (obj == null || GetType() != obj.GetType()) + { + return false; + } + + var other = (Color)obj; + + return other.value == value; + } + + public static bool operator ==(Color c1, Color c2) + { + return c1.value == c2.value; + } + + public static bool operator !=(Color c1, Color c2) + { + return c1.value != c2.value; + } + + public override readonly int GetHashCode() + { + return (int)value; + } + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/Color.cs.meta b/Packages/app.rive.rive-unity/Runtime/Color.cs.meta new file mode 100644 index 00000000..13ea6670 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Color.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 09a1dfb266f304c808233ab1f810acd2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Color.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Component.cs b/Packages/app.rive.rive-unity/Runtime/Component.cs new file mode 100644 index 00000000..f8f4d91a --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Component.cs @@ -0,0 +1,66 @@ +using UnityEngine; +using System; +using System.Runtime.InteropServices; + +namespace Rive +{ + /// + /// Represents a Component of a Rive Artboard. + /// + [Obsolete("Component is deprecated and will be removed in a future release. Please use Databinding instead.")] + public class Component + { + private readonly IntPtr m_nativeComponent; + + internal IntPtr NativeComponent + { + get { return m_nativeComponent; } + } + + internal Component(IntPtr nativeComponent) + { + m_nativeComponent = nativeComponent; + } + + ~Component() + { + unrefArtboardComponent(m_nativeComponent); + } + + public AABB ComputeBounds() + { + return componentBounds(m_nativeComponent); + } + + #region Native Methods + [DllImport(NativeLibrary.name)] + internal static extern void unrefArtboardComponent(IntPtr component); + + [DllImport(NativeLibrary.name)] + internal static extern AABB componentBounds(IntPtr component); + #endregion + } +} + +[StructLayout(LayoutKind.Sequential)] +public struct AABB +{ + public float minX; + public float minY; + public float maxX; + public float maxY; + + public AABB(float minX, float minY, float maxX, float maxY) + { + this.minX = minX; + this.minY = minY; + this.maxX = maxX; + this.maxY = maxY; + } + + public override string ToString() + { + return $"minX: {minX}, minY: {minY}, maxX: {maxX}, maxY: {maxY}"; + } + +} diff --git a/Packages/app.rive.rive-unity/Runtime/Component.cs.meta b/Packages/app.rive.rive-unity/Runtime/Component.cs.meta new file mode 100644 index 00000000..f303c6a1 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Component.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: c3c17818c5fa04d75a7be83a59b2d4f6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Component.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components.meta b/Packages/app.rive.rive-unity/Runtime/Components.meta new file mode 100644 index 00000000..18b3d045 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e2001b8fb858c48e589698dc4133bdd7 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Runtime/Components/CanvasRendererRawImage.cs b/Packages/app.rive.rive-unity/Runtime/Components/CanvasRendererRawImage.cs new file mode 100644 index 00000000..8e8e5613 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/CanvasRendererRawImage.cs @@ -0,0 +1,87 @@ +using UnityEngine; +using UnityEngine.UI; + +namespace Rive.Components +{ + /// + /// A RawImage that can display Rive content. Also used to display Rive content in the editor. + /// + internal class CanvasRendererRawImage : RawImage + { +#if UNITY_EDITOR + private Texture m_editorPreviewTexture; + private bool m_isPopulatingMesh = false; + + internal void UpdateEditorPreview(Texture previewTexture) + { + if (Application.isPlaying) return; + if (m_editorPreviewTexture != previewTexture) + { + m_editorPreviewTexture = previewTexture; + // we're using SetAllDirty() to mark the graphic for rebuilding + SetAllDirty(); + } + } + + internal void CleanupEditorPreview() + { + if (!Application.isPlaying) + { + m_editorPreviewTexture = null; + SetAllDirty(); + } + } + + protected override void OnDisable() + { + base.OnDisable(); + if (!Application.isPlaying) + { + CleanupEditorPreview(); + } + } + + protected override void OnDestroy() + { + base.OnDestroy(); + if (!Application.isPlaying) + { + CleanupEditorPreview(); + } + } + + protected override void OnRectTransformDimensionsChange() + { + base.OnRectTransformDimensionsChange(); + if (!Application.isPlaying) + { + SetAllDirty(); + } + } + // We need to override mainTexture to return the editor preview texture when not playing + // We do this to avoid dirtying the scene view when the editor preview texture changes + public override Texture mainTexture + { + get + { + if (!Application.isPlaying && m_editorPreviewTexture != null) + { + return m_editorPreviewTexture; + } + return base.mainTexture; + } + } + + protected override void OnPopulateMesh(VertexHelper vh) + { + // We've added an m_isPopulatingMesh flag to prevent recursive calls to OnPopulateMesh. + + if (m_isPopulatingMesh) return; + + m_isPopulatingMesh = true; + base.OnPopulateMesh(vh); + m_isPopulatingMesh = false; + } +#endif + } +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Runtime/Components/CanvasRendererRawImage.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/CanvasRendererRawImage.cs.meta new file mode 100644 index 00000000..1ac7b33c --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/CanvasRendererRawImage.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 9727164d01ae84a31a68e1e12835571c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/CanvasRendererRawImage.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/ComponentAssemblyHelper.cs b/Packages/app.rive.rive-unity/Runtime/Components/ComponentAssemblyHelper.cs new file mode 100644 index 00000000..4f59d5e1 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/ComponentAssemblyHelper.cs @@ -0,0 +1,16 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Rive.Editor.Components")] +[assembly: InternalsVisibleTo("Rive.Tests.PlayMode")] +[assembly: InternalsVisibleTo("Rive.Tests.Shared")] +[assembly: InternalsVisibleTo("Rive.Tests.Editor")] +namespace Rive.Components +{ + /// + /// Used to expose internals to other Rive assemblies. + /// + internal class ComponentAssemblyHelper + { + + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/Components/ComponentAssemblyHelper.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/ComponentAssemblyHelper.cs.meta new file mode 100644 index 00000000..6600c0f4 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/ComponentAssemblyHelper.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 67e77bb0829b6419d92972fea03ae5c2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/ComponentAssemblyHelper.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly.meta b/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly.meta new file mode 100644 index 00000000..29cb210a --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4d133d41c26dd4d878cdd4d9884f9261 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors.meta b/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors.meta new file mode 100644 index 00000000..91558787 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 691bfac972ac94f93808693e63b5465a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/DropdownAttribute.cs b/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/DropdownAttribute.cs new file mode 100644 index 00000000..51b8d015 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/DropdownAttribute.cs @@ -0,0 +1,51 @@ +using UnityEngine; + +namespace Rive.EditorTools +{ + /// + /// Attribute to create a dropdown field in the inspector that can be populated from a field, property, or method. + /// + internal class DropdownAttribute : PropertyAttribute + { + /// + /// The name of the member (field, property, or method) that provides the dropdown options. + /// + public string OptionsMemberName { get; private set; } + + /// + /// The name of the method that provides the default index for the dropdown. + /// If not specified, FallbackDefaultIndex will be used. + /// + public string DefaultIndexMethodName { get; private set; } + + /// + /// The default index to use when no DefaultIndexMethodName is specified or when it returns an invalid value. + /// + public int FallbackDefaultIndex { get; private set; } + + /// + /// Whether to continuously track changes to the options source using EditorApplication.update. + /// Enable this if your options can change dynamically during editor time. + /// + public bool TrackChanges { get; private set; } + + /// + /// Creates a dropdown attribute that populates its options from a specified member. + /// + /// Name of the field, property, or method that provides the options. + /// Optional method name that provides the default selected index. + /// Default index to use when no method is specified or when it returns an invalid value. + /// Whether to continuously check for changes to the options. + public DropdownAttribute( + string optionsMemberName, + string defaultIndexMethodName = null, + int fallbackDefaultIndex = 0, + bool trackChanges = false) + { + OptionsMemberName = optionsMemberName; + DefaultIndexMethodName = defaultIndexMethodName; + FallbackDefaultIndex = fallbackDefaultIndex; + TrackChanges = trackChanges; + } + } +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/DropdownAttribute.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/DropdownAttribute.cs.meta new file mode 100644 index 00000000..f06beb91 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/DropdownAttribute.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 2ce214f532a414d06aaea47e0249d426 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/DropdownAttribute.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/HideComponentsAttribute.cs b/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/HideComponentsAttribute.cs new file mode 100644 index 00000000..dd92f833 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/HideComponentsAttribute.cs @@ -0,0 +1,34 @@ +using System; +using UnityEngine; + +namespace Rive.EditorTools +{ + /// + /// Used to hide components in the inspector. + /// + [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] + internal class HideComponentsAttribute : Attribute + { + public Type[] ComponentTypes { get; private set; } + public HideFlags HideFlags { get; private set; } + + /// + /// Specifies which components should be hidden in the inspector. + /// + /// The types of components to hide + public HideComponentsAttribute(params Type[] componentTypes) : this(HideFlags.HideInInspector | HideFlags.HideAndDontSave, componentTypes) + { + } + + /// + /// Specifies which components should be hidden in the inspector with custom hide flags. + /// + /// The HideFlags to apply to the components + /// The types of components to hide + public HideComponentsAttribute(HideFlags hideFlags, params Type[] componentTypes) + { + ComponentTypes = componentTypes; + HideFlags = hideFlags; + } + } +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/HideComponentsAttribute.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/HideComponentsAttribute.cs.meta new file mode 100644 index 00000000..f5bd9b9f --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/HideComponentsAttribute.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: f3c73b7f189f5491d935f52adb37f73f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/HideComponentsAttribute.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/HideIfAttribute.cs b/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/HideIfAttribute.cs new file mode 100644 index 00000000..526e1e5c --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/HideIfAttribute.cs @@ -0,0 +1,21 @@ +using UnityEngine; + +namespace Rive.EditorTools +{ + /// + /// Attribute to hide a field in the inspector if a condition is met. Only works with custom inspectors that inherit from RiveBaseEditor. + /// + internal class HideIfAttribute : PropertyAttribute + { + public string ConditionName { get; private set; } + + /// + /// Attribute to hide a field in the inspector if a condition is met. + /// + /// The name of the condition method to check. This can also be a property name. + public HideIfAttribute(string conditionName) + { + ConditionName = conditionName; + } + } +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/HideIfAttribute.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/HideIfAttribute.cs.meta new file mode 100644 index 00000000..fc37a3e6 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/HideIfAttribute.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 1d108bfb7a8e34141a262e27c4b14183 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/HideIfAttribute.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/InspectorFieldAttribute.cs b/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/InspectorFieldAttribute.cs new file mode 100644 index 00000000..9b228cee --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/InspectorFieldAttribute.cs @@ -0,0 +1,54 @@ +using UnityEngine; + +namespace Rive.EditorTools +{ + /// + /// Attribute to mark a field to be displayed in a custom inspector for a Rive component. + /// + internal class InspectorFieldAttribute : PropertyAttribute + { + /// + /// The section ID this field belongs to. If null, the field will be displayed outside any section. + /// + public string SectionId { get; private set; } + + /// + /// The display name shown in the inspector UI. If null, defaults to the field name. + /// + public string DisplayName { get; private set; } + + /// + /// The order this field appears relative to other fields. Lower numbers appear first. + /// + public int Order { get; private set; } + + /// + /// Optional URL to open when the help/info button is clicked in the inspector. + /// + public string HelpUrl { get; private set; } + + /// + /// Convenience flag to check if a help URL was supplied. + /// + public bool HasHelpUrl => !string.IsNullOrEmpty(HelpUrl); + + /// + /// Creates a new field attribute for the inspector. + /// + /// Section ID this field belongs to. If null, displays outside sections + /// Display name shown in UI. If null, uses field name + /// Order relative to other fields. Lower numbers appear first + /// Optional URL opened when the info button is clicked + public InspectorFieldAttribute( + string sectionId = null, + string displayName = null, + int order = 0, + string helpUrl = null) + { + SectionId = sectionId; + DisplayName = displayName; + Order = order; + HelpUrl = helpUrl; + } + } +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/InspectorFieldAttribute.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/InspectorFieldAttribute.cs.meta new file mode 100644 index 00000000..2c599e1f --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/InspectorFieldAttribute.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 37b38a029e00a4277a06763e2eedb3e3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/InspectorFieldAttribute.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/InspectorSectionAttribute.cs b/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/InspectorSectionAttribute.cs new file mode 100644 index 00000000..aa8283f3 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/InspectorSectionAttribute.cs @@ -0,0 +1,74 @@ +using System; + +namespace Rive.EditorTools +{ + [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)] + /// + /// Attribute to mark a section in a custom inspector for a Rive component. + /// + internal class InspectorSectionAttribute : Attribute + { + /// + /// The unique identifier for this section. + /// + public string Id { get; private set; } + + /// + /// The display name shown in the inspector UI. If not specified, defaults to the Id. + /// + public string DisplayName { get; private set; } + + /// + /// The order this section appears relative to other sections. Lower numbers appear first. + /// + public int Order { get; private set; } + + /// + /// The style used to display this section - either as a header or foldout. + /// + public SectionStyle Style { get; private set; } + + /// + /// Whether a foldout section should start expanded. Only applies when Style is Foldout. + /// + public bool StartExpanded { get; private set; } + + /// + /// Creates a new section in the inspector. + /// + /// Unique identifier for the section + /// Display name shown in UI. Defaults to id if null + /// Order relative to other sections. Lower numbers appear first + /// How to display the section - as a header or foldout + /// Whether a foldout section starts expanded + public InspectorSectionAttribute( + string id, + string displayName = null, + int order = 0, + SectionStyle style = SectionStyle.Header, + bool startExpanded = false) + { + Id = id; + DisplayName = displayName ?? id; + Order = order; + Style = style; + StartExpanded = startExpanded; + } + } + + /// + /// Defines how a section should be displayed in the inspector. + /// + public enum SectionStyle + { + /// + /// Shows a header label above the section content. + /// + Header = 0, + + /// + /// Shows the section as a foldout that can be expanded/collapsed. + /// + Foldout = 1 + } +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/InspectorSectionAttribute.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/InspectorSectionAttribute.cs.meta new file mode 100644 index 00000000..4c169a45 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/InspectorSectionAttribute.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: affca4152ad384ed3a6c300dbd82c1ea +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/InspectorSectionAttribute.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/MaterialPropertiesAttribute.cs b/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/MaterialPropertiesAttribute.cs new file mode 100644 index 00000000..4455eb8b --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/MaterialPropertiesAttribute.cs @@ -0,0 +1,51 @@ +#if UNITY_EDITOR +using UnityEditor; +#if UNITY_6000_3_OR_NEWER +using MaterialShaderPropertyType = UnityEngine.Rendering.ShaderPropertyType; +#else +using MaterialShaderPropertyType = UnityEditor.ShaderUtil.ShaderPropertyType; +#endif +#endif +using UnityEngine; + +namespace Rive.EditorTools +{ + /// + /// Attribute for drawing material property lists for each material. + /// + internal class MaterialPropertiesAttribute : PropertyAttribute + { +#if UNITY_EDITOR + /// + /// Name of the member that provides the materials (can be a field, property, or method). + /// + public string MaterialsSourceName { get; private set; } + + /// + /// The type of shader properties to display (e.g., TexEnv, Float, Color). + /// + public MaterialShaderPropertyType PropertyType { get; private set; } + + /// + /// Creates a new MaterialPropertiesAttribute. + /// + /// Name of the member that provides the materials. + /// Type of shader properties to display. + public MaterialPropertiesAttribute( + string materialsSourceName, + MaterialShaderPropertyType propertyType = +#if UNITY_6000_3_OR_NEWER + MaterialShaderPropertyType.Texture +#else + MaterialShaderPropertyType.TexEnv +#endif + ) + { + MaterialsSourceName = materialsSourceName; + PropertyType = propertyType; + } +#endif + } + + +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/MaterialPropertiesAttribute.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/MaterialPropertiesAttribute.cs.meta new file mode 100644 index 00000000..486615b4 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/MaterialPropertiesAttribute.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: b990db98a04454ef4a47cf84a8acc6d4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/MaterialPropertiesAttribute.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/OnValueChangedAttribute.cs b/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/OnValueChangedAttribute.cs new file mode 100644 index 00000000..3497539d --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/OnValueChangedAttribute.cs @@ -0,0 +1,31 @@ +using UnityEngine; + +namespace Rive.EditorTools +{ + /// + /// Attribute to invoke a callback method when a property value changes. Only works with custom editors that inherit from RiveBaseEditor. + /// + internal class OnValueChangedAttribute : PropertyAttribute + { + /// + /// The name of the callback method to invoke when the value changes. + /// + public string CallbackName { get; private set; } + + /// + /// Whether to invoke the callback during the initial setup of the property drawer. + /// + public bool InvokeOnInitialization { get; private set; } + + /// + /// Attribute to invoke a callback method when a property value changes. + /// + /// The name of the method to call when the value changes. + /// Whether to invoke the callback during initialization (default: false). This is useful for setting up initial values. + public OnValueChangedAttribute(string callbackName, bool invokeOnInitialization = false) + { + CallbackName = callbackName; + InvokeOnInitialization = invokeOnInitialization; + } + } +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/OnValueChangedAttribute.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/OnValueChangedAttribute.cs.meta new file mode 100644 index 00000000..d1383c63 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/OnValueChangedAttribute.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 46b0ca8e95502493798e11215c5030c8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/OnValueChangedAttribute.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/ShowIfAttribute.cs b/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/ShowIfAttribute.cs new file mode 100644 index 00000000..f2b5da5b --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/ShowIfAttribute.cs @@ -0,0 +1,21 @@ +using UnityEngine; + +namespace Rive.EditorTools +{ + /// + /// Attribute to show a property in the inspector if a condition is met. Only works with custom inspectors that inherit from RiveBaseEditor. + /// + internal class ShowIfAttribute : PropertyAttribute + { + public string ConditionName { get; private set; } + + /// + /// Attribute to show a property in the inspector if a condition is met. + /// + /// The name of the condition method to check. This can also be a property name. + public ShowIfAttribute(string conditionName) + { + ConditionName = conditionName; + } + } +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/ShowIfAttribute.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/ShowIfAttribute.cs.meta new file mode 100644 index 00000000..aeec2e8c --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/ShowIfAttribute.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: cc3324a0b6c744395ad566e3aeaa25dd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/ShowIfAttribute.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/WidthHeightDimensionsAttribute.cs b/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/WidthHeightDimensionsAttribute.cs new file mode 100644 index 00000000..eea2775a --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/WidthHeightDimensionsAttribute.cs @@ -0,0 +1,24 @@ +using UnityEngine; + +namespace Rive.EditorTools +{ + /// + /// Attribute to specify that a property is a width/height dimensions pair for a Vector2. + /// + internal class WidthHeightDimensionsAttribute : PropertyAttribute + { + public string Label { get; private set; } + public string WidthLabel { get; private set; } + public string HeightLabel { get; private set; } + + public WidthHeightDimensionsAttribute( + string label, + string widthLabel = "Width", + string heightLabel = "Height") + { + Label = label; + WidthLabel = widthLabel; + HeightLabel = heightLabel; + } + } +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/WidthHeightDimensionsAttribute.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/WidthHeightDimensionsAttribute.cs.meta new file mode 100644 index 00000000..ab49df82 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/WidthHeightDimensionsAttribute.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: e21cd09e2f0e54a718cac38b1b165986 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/Inspectors/WidthHeightDimensionsAttribute.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/MaterialConversionUtility.cs b/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/MaterialConversionUtility.cs new file mode 100644 index 00000000..fc435c05 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/MaterialConversionUtility.cs @@ -0,0 +1,420 @@ +using UnityEngine; +#if UNITY_EDITOR +using UnityEditor; +#endif + +namespace Rive.Components +{ + + /// + /// Helper class for converting default RP materials to Rive variants. + /// + internal static class MaterialConversionUtility + { +#if UNITY_EDITOR + // Exposed constants so tests and editor code can reference folder and name conventions from one place. + internal static class Constants + { + public const string PackageName = Rive.EditorTools.PackageInfo.PACKAGE_NAME; + public const string RPFolderRoot = "RenderPipelines"; + public const string URPFolder = "URP"; + public const string HDRPFolder = "HDRP"; + public const string BuiltInFolder = "BuiltIn"; + public const string MaterialsFolder = "Materials"; + + public const string BaseRiveLit = "RiveLit"; + public const string BaseRiveUnlit = "RiveUnlit"; + + public const string SuffixURP = "URP"; + public const string SuffixHDRP = "HDRP"; + public const string SuffixBiRP = "BiRP"; + + // Unity default shader names for detection (used to identify pipeline defaults) + public const string UnityDefaultShaderURPLit = "Universal Render Pipeline/Lit"; + public const string UnityDefaultShaderURPUnlit = "Universal Render Pipeline/Unlit"; + public const string UnityDefaultShaderHDRPLit = "HDRP/Lit"; + public const string UnityDefaultShaderHDRPUnlit = "HDRP/Unlit"; + public const string UnityDefaultShaderBuiltInLit = "Standard"; + public const string UnityDefaultShaderBuiltInUnlitPrefix = "Unlit/"; + + // Expected material names for the current render pipeline + internal static string ExpectedLitNameForCurrentPipeline + { + get + { + return BaseRiveLit + GetCurrentPipelineSuffix(); + } + } + internal static string ExpectedUnlitNameForCurrentPipeline + { + get + { + return BaseRiveUnlit + GetCurrentPipelineSuffix(); + } + } + + private static string GetCurrentPipelineSuffix() + { + switch (GetCurrentPipeline()) + { + case Pipeline.URP: + return SuffixURP; + case Pipeline.HDRP: + return SuffixHDRP; + default: + return SuffixBiRP; + } + } + } + + private enum Pipeline + { + BuiltIn = 0, + URP = 1, + HDRP = 2, + } + + private static Pipeline GetCurrentPipeline() + { + var rp = UnityEngine.Rendering.GraphicsSettings.currentRenderPipeline; + if (rp == null) + { + return Pipeline.BuiltIn; + } + var typeName = rp.GetType().FullName; + if (!string.IsNullOrEmpty(typeName)) + { + if (typeName.Contains("UniversalRenderPipelineAsset")) + { + return Pipeline.URP; + } + if (typeName.Contains("HDRenderPipelineAsset")) + { + return Pipeline.HDRP; + } + } + return Pipeline.BuiltIn; + } + + // --------------------------- + // Project-material resolution + // --------------------------- + private static Material s_cachedLitMaterial; + private static Material s_cachedUnlitMaterial; + + private static string GetTargetFolderPath() + { + return "Assets/Plugins/Rive/Materials"; + } + + private static string GetBaseName(bool lit) + { + return lit ? Constants.BaseRiveLit : Constants.BaseRiveUnlit; + } + + private static string GetRPFolder(out string suffix) + { + switch (GetCurrentPipeline()) + { + case Pipeline.URP: + suffix = Constants.SuffixURP; + return Constants.URPFolder; + case Pipeline.HDRP: + suffix = Constants.SuffixHDRP; + return Constants.HDRPFolder; + default: + suffix = Constants.SuffixBiRP; + return Constants.BuiltInFolder; + } + } + + private static void EnsureAssetFolder(string path) + { + var parts = path.Split('/'); + if (parts.Length == 0 || parts[0] != "Assets") return; + string current = "Assets"; + for (int i = 1; i < parts.Length; i++) + { + string next = current + "/" + parts[i]; + if (!AssetDatabase.IsValidFolder(next)) + { + AssetDatabase.CreateFolder(current, parts[i]); + } + current = next; + } + } + + private static Shader LoadShaderFromRenderPipelinesFolder(string rpFolder, bool lit, out string resolvedName) + { + // Attempt to load shader directly from RP ShaderGraph asset + string litOrUnlit = lit ? "Lit" : "Unlit"; + string shaderGraphPath = $"Packages/{Constants.PackageName}/Runtime/Components/Public/RenderPipelines/{rpFolder}/Shaders/{litOrUnlit}.shadergraph"; + var shader = AssetDatabase.LoadAssetAtPath(shaderGraphPath); + if (shader != null) + { + resolvedName = shader.name; + return shader; + } + // Fallback search within the RP Shaders folder for any Shader assets and pick by name hint + string folder = $"Packages/{Constants.PackageName}/Runtime/Components/Public/RenderPipelines/{rpFolder}/Shaders"; + string[] guids = AssetDatabase.FindAssets("t:Shader", new[] { folder }); + for (int i = 0; i < guids.Length; i++) + { + string path = AssetDatabase.GUIDToAssetPath(guids[i]); + var s = AssetDatabase.LoadAssetAtPath(path); + if (s != null && s.name.IndexOf(litOrUnlit, System.StringComparison.OrdinalIgnoreCase) >= 0) + { + resolvedName = s.name; + return s; + } + } + resolvedName = $""; + return null; + } + + private static Shader GetPipelineShader(bool lit, out string shaderName) + { + switch (GetCurrentPipeline()) + { + case Pipeline.URP: + return LoadShaderFromRenderPipelinesFolder(Constants.URPFolder, lit, out shaderName); + case Pipeline.HDRP: + return LoadShaderFromRenderPipelinesFolder(Constants.HDRPFolder, lit, out shaderName); + default: + return LoadShaderFromRenderPipelinesFolder(Constants.BuiltInFolder, lit, out shaderName); + } + + } + + private static System.Collections.Generic.List FindProjectMaterialsUsingShader(Shader shader) + { + var results = new System.Collections.Generic.List(); + if (shader == null) + { + return results; + } + var guids = AssetDatabase.FindAssets("t:material", new[] { "Assets" }); + for (int i = 0; i < guids.Length; i++) + { + var path = AssetDatabase.GUIDToAssetPath(guids[i]); + var mat = AssetDatabase.LoadAssetAtPath(path); + if (mat != null && mat.shader == shader) + { + results.Add(mat); + } + } + results.Sort((a, b) => + { + string ta = AssetDatabase.GetAssetPath(a); + string tb = AssetDatabase.GetAssetPath(b); + bool aPrefer = ta.StartsWith(GetTargetFolderPath()); + bool bPrefer = tb.StartsWith(GetTargetFolderPath()); + if (aPrefer == bPrefer) return string.Compare(ta, tb, System.StringComparison.OrdinalIgnoreCase); + return aPrefer ? -1 : 1; + }); + return results; + } + + private static bool ShaderMatches(Shader candidate, Shader target, string targetName) + { + if (candidate == null) + { + return false; + } + if (target != null && candidate == target) + { + return true; + } + if (!string.IsNullOrEmpty(targetName) && + string.Equals(candidate.name, targetName, System.StringComparison.OrdinalIgnoreCase)) + { + return true; + } + return false; + } + + /// + /// Resolve or create a project-local Rive material with exact-name-first strategy: + /// 1) Use Assets/Plugins/Rive/Materials/<Base+Suffix>.mat if present. + /// 2) Else use any material in Assets with that exact name and matching shader. + /// 3) Else, if materials exist with the matching shader, optionally prompt to use suggested; otherwise create. + /// 4) Else create under Assets/Plugins/Rive/Materials with a unique name. + /// + private static Material LoadOrCreateProjectRiveMaterial(bool lit) + { + if (lit && s_cachedLitMaterial != null) return s_cachedLitMaterial; + if (!lit && s_cachedUnlitMaterial != null) return s_cachedUnlitMaterial; + + string suffix; + string rpFolder = GetRPFolder(out suffix); + string expectedName = GetBaseName(lit) + suffix; + + // 1) Exact expected path in Assets/Plugins/Rive/Materials + string targetFolder = GetTargetFolderPath(); + string targetPath = $"{targetFolder}/{expectedName}.mat"; + var atTarget = AssetDatabase.LoadAssetAtPath(targetPath); + if (atTarget != null) + { + if (lit) s_cachedLitMaterial = atTarget; else s_cachedUnlitMaterial = atTarget; + return atTarget; + } + + // Resolve shader + var shader = GetPipelineShader(lit, out var shaderName); + if (shader == null) + { + Debug.LogWarning($"Rive: Could not resolve shader for current render pipeline (lit={lit})."); + } + + // 2) Exact-name anywhere in Assets with matching shader + string[] nameMatches = AssetDatabase.FindAssets($"t:material {expectedName}", new[] { "Assets" }); + for (int i = 0; i < nameMatches.Length; i++) + { + string path = AssetDatabase.GUIDToAssetPath(nameMatches[i]); + var mat = AssetDatabase.LoadAssetAtPath(path); + // If the user has a material with the exact expected name, prefer it regardless of shader; + // this allows overriding shader source differences (Graph vs HLSL) while honoring the name contract. + if (mat != null && mat.name == expectedName) + { + if (lit) s_cachedLitMaterial = mat; else s_cachedUnlitMaterial = mat; + return mat; + } + } + + // 3) If no exact-name match is found, always create a new material in the Plugins folder. + + // 4) Create new in Assets/Plugins/Rive/Materials with unique name if needed + EnsureAssetFolder(targetFolder); + string basePath = $"{targetFolder}/{expectedName}.mat"; + string uniquePath = AssetDatabase.GenerateUniqueAssetPath(basePath); + + Material toSave = new Material(shader != null ? shader : Shader.Find("Hidden/InternalErrorShader")); + + AssetDatabase.CreateAsset(toSave, uniquePath); + AssetDatabase.SaveAssets(); + AssetDatabase.ImportAsset(uniquePath); + + if (lit) s_cachedLitMaterial = toSave; else s_cachedUnlitMaterial = toSave; + return toSave; + } + + + /// + /// Ensures that the given renderer has Rive materials assigned for any default materials. Unlike ReplaceMaterialsWithRive, this only replaces materials that appear to be Unity default materials that Unity would assign automatically. + /// + /// + internal static void EnsureRiveMaterialsOnRenderer(UnityEngine.Renderer renderer) + { + if (renderer == null) + { + return; + } + + var materials = renderer.sharedMaterials; + bool changed = false; + for (int i = 0; i < materials.Length; i++) + { + var mat = materials[i]; + if (mat == null || mat.shader == null) + { + continue; + } + string shaderName = mat.shader.name; + bool isDefaultLit = false; + bool isDefaultUnlit = false; + + + switch (GetCurrentPipeline()) + { + case Pipeline.URP: + isDefaultLit = shaderName == Constants.UnityDefaultShaderURPLit || + shaderName == "Universal Render Pipeline/Simple Lit"; + isDefaultUnlit = shaderName == Constants.UnityDefaultShaderURPUnlit; + break; + case Pipeline.HDRP: + isDefaultLit = shaderName == Constants.UnityDefaultShaderHDRPLit; + isDefaultUnlit = shaderName == Constants.UnityDefaultShaderHDRPUnlit; + break; + default: + isDefaultLit = shaderName == Constants.UnityDefaultShaderBuiltInLit; + isDefaultUnlit = shaderName.StartsWith(Constants.UnityDefaultShaderBuiltInUnlitPrefix); + break; + } + + if (isDefaultLit || isDefaultUnlit) + { + var target = LoadOrCreateProjectRiveMaterial(lit: !isDefaultUnlit); + if (target != null && target != mat) + { + materials[i] = target; + changed = true; + } + } + } + + if (changed) + { + renderer.sharedMaterials = materials; + EditorUtility.SetDirty(renderer); + } + } + /// + /// Replaces any non-Rive materials on the given renderer with Rive equivalents. Unlike EnsureRiveMaterialsOnRenderer, this will replace any material that is not already a Rive material, even if it's a custom material. + /// + /// + internal static void ReplaceMaterialsWithRive(UnityEngine.Renderer renderer) + { + if (renderer == null) + { + return; + } + var materials = renderer.sharedMaterials; + // If there are no materials at all, assign a single lit material. + if (materials == null || materials.Length == 0) + { + var targetIfNone = LoadOrCreateProjectRiveMaterial(lit: true); + if (targetIfNone != null) + { + renderer.sharedMaterials = new[] { targetIfNone }; + EditorUtility.SetDirty(renderer); + } + return; + } + bool changed = false; + for (int i = 0; i < materials.Length; i++) + { + var mat = materials[i]; + if (mat == null || mat.shader == null) + { + // Replace missing/invalid material with a lit material by default. + var defaultLit = LoadOrCreateProjectRiveMaterial(lit: true); + if (defaultLit != null) + { + materials[i] = defaultLit; + changed = true; + } + continue; + } + string shaderName = mat.shader.name ?? string.Empty; + bool appearsUnlit = + shaderName.IndexOf("unlit", System.StringComparison.OrdinalIgnoreCase) >= 0 || + shaderName.StartsWith("Unlit/", System.StringComparison.OrdinalIgnoreCase); + + var target = LoadOrCreateProjectRiveMaterial(lit: !appearsUnlit); + if (target != null && target != mat) + { + materials[i] = target; + changed = true; + } + } + if (changed) + { + renderer.sharedMaterials = materials; + EditorUtility.SetDirty(renderer); + } + } +#endif + } +} + + diff --git a/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/MaterialConversionUtility.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/MaterialConversionUtility.cs.meta new file mode 100644 index 00000000..bcfe3108 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/MaterialConversionUtility.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 8a7e31256da344ea6847dbe0dde1888a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/EditorOnly/MaterialConversionUtility.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Helpers.meta b/Packages/app.rive.rive-unity/Runtime/Components/Helpers.meta new file mode 100644 index 00000000..8ebee07b --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Helpers.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 65d2af391407e4edd83ed4840b47f979 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Helpers/ArtboardLoadHelper.cs b/Packages/app.rive.rive-unity/Runtime/Components/Helpers/ArtboardLoadHelper.cs new file mode 100644 index 00000000..d3c3dbd3 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Helpers/ArtboardLoadHelper.cs @@ -0,0 +1,335 @@ +using System.Collections.Generic; +using Rive.Utils; +using UnityEngine; + +namespace Rive.Components.Utilities +{ + + /// + /// The is responsible for managing the loading Rive file, artboard, state machine. It handles the core logic for loading and unloading artboards from Rive Files. + /// + internal class ArtboardLoadHelper + { + public enum LoadErrorType + { + InvalidArguments = 0, + ArtboardNotFound = 1, + StateMachineNotFound = 2, + } + + + + public readonly struct LoadErrorEventData + { + public LoadErrorType ErrorType { get; } + public string Message { get; } + + public LoadErrorEventData(LoadErrorType errorType, string message = null) + { + ErrorType = errorType; + Message = message; + } + } + + internal struct DataBindingLoadInfo + { + public RiveWidget.DataBindingMode BindingMode { get; } + + public string InstanceName { get; } + + public DataBindingLoadInfo(RiveWidget.DataBindingMode bindingMode, string instanceName) + { + BindingMode = bindingMode; + InstanceName = instanceName; + } + } + + internal struct LoadResult + { + public bool Success { get; } + public LoadErrorEventData ErrorData { get; } + + public LoadResult(bool success, LoadErrorEventData errorData = default) + { + Success = success; + ErrorData = errorData; + } + } + + private Artboard m_artboard; + private StateMachine m_stateMachine; + private File m_file; + private ArtboardRenderObject m_renderObject; + + private float originalArtboardWidth; + private float originalArtboardHeight; + + + private bool m_isLoaded = false; + + private List m_reportedEvents = new List(); + + + + public Artboard Artboard => m_artboard; + public StateMachine StateMachine => m_stateMachine; + + public File File { get => m_file; } + + public ArtboardRenderObject RenderObject => m_renderObject; + + public float OriginalArtboardWidth => originalArtboardWidth; + public float OriginalArtboardHeight => originalArtboardHeight; + public bool IsLoaded + { + get => m_isLoaded; + private set => m_isLoaded = value; + } + + + public delegate void RiveEventDelegate(ReportedEvent report); + public delegate void RiveLoadErrorDelegate(LoadErrorEventData eventData); + public delegate void RiveLoadCompleteDelegate(); + + public delegate void RiveRenderStateChangeDelegate(); + + public event RiveEventDelegate OnRiveEventReported; + + + + + + public LoadResult Load(File file, Fit fit, Alignment alignment, string artboardName, string stateMachineName, float scaleFactor, DataBindingLoadInfo bindingInfo) + { + CleanUpBeforeLoad(); + + if (file == null) + { + IsLoaded = false; + + return new LoadResult(false, new LoadErrorEventData(LoadErrorType.InvalidArguments, "File is null")); + } + + m_file = file; + m_artboard = string.IsNullOrEmpty(artboardName) ? m_file.Artboard(0) : m_file.Artboard(artboardName); + + if (m_artboard == null) + { + IsLoaded = false; + return new LoadResult(false, new LoadErrorEventData(LoadErrorType.ArtboardNotFound, $"Artboard {artboardName} not found in file")); + } + + originalArtboardWidth = m_artboard.Width; + originalArtboardHeight = m_artboard.Height; + + m_stateMachine = string.IsNullOrEmpty(stateMachineName) ? m_artboard.StateMachine(0) : m_artboard.StateMachine(stateMachineName); + + if (m_stateMachine == null) + { + IsLoaded = false; + return new LoadResult(false, new LoadErrorEventData(LoadErrorType.StateMachineNotFound, $"State machine {stateMachineName} not found in artboard {artboardName}")); + } + + var viewModelInstance = GetVmInstanceToApply(bindingInfo.BindingMode, m_artboard, bindingInfo.InstanceName); + if (viewModelInstance != null) + { + m_stateMachine.BindViewModelInstance(viewModelInstance); + } + + m_renderObject = CreateRenderObject(m_artboard, alignment, fit, scaleFactor); + + + IsLoaded = true; + + return new LoadResult(true); + } + + private ViewModelInstance GetVmInstanceToApply(RiveWidget.DataBindingMode bindingMode, Artboard artboard, string instanceName = null) + { + ViewModelInstance vmInstance = null; + switch (bindingMode) + { + case RiveWidget.DataBindingMode.Manual: + break; + case RiveWidget.DataBindingMode.AutoBindDefault: + vmInstance = artboard.DefaultViewModel?.CreateDefaultInstance(); + break; + case RiveWidget.DataBindingMode.AutoBindSelected: + vmInstance = artboard.DefaultViewModel?.CreateInstanceByName(instanceName); + + break; + default: + break; + } + return vmInstance; + } + + public void Tick(float deltaTime, RiveWidget.EventPoolingMode poolingMode, float speed) + { + if (m_stateMachine == null) + { + return; + } + + m_reportedEvents.Clear(); + + + m_stateMachine.ReportedEvents(m_reportedEvents); + + + for (int i = 0; i < m_reportedEvents.Count; i++) + { + var evt = m_reportedEvents[i]; + OnRiveEventReported?.Invoke(evt); + + // If pooling is enabled, auto-dispose the event + if (poolingMode == RiveWidget.EventPoolingMode.Enabled) + { + evt.Dispose(); + } + } + + m_stateMachine.Advance(deltaTime * speed); + + // Legacy callback propagation behavior + if (RiveWidget.PropertyCallbackApproach == RiveWidget.DataBindingPropertyCallbackApproach.Propagation) + { + m_stateMachine.ViewModelInstance?.HandleCallbacks(); + } + + } + + + + private ArtboardRenderObject CreateRenderObject(Artboard artboard, Alignment alignment, Fit fit, float scaleFactor) + { + ArtboardRenderObject existingRenderObject = m_renderObject as ArtboardRenderObject; + + if (existingRenderObject != null) + { + existingRenderObject.Init(artboard, alignment, fit, scaleFactor); + return existingRenderObject; + } + + return new ArtboardRenderObject(artboard, alignment, fit, scaleFactor); + } + + + private void CleanUpBeforeLoad() + { + m_stateMachine?.Dispose(); + m_stateMachine = null; + + m_artboard?.Dispose(); + m_artboard = null; + + // File ownership/lifecycle is managed by the caller (e.g., RiveWidget), so do not dispose it here. + m_file = null; + + } + + + /// + /// Calculates the effective scale factor based on the scaling mode and provided parameters. + /// + /// The scaling mode to use. + /// The scale factor to apply. + /// The original size of the artboard. + /// The frame rect where the artboard will be displayed. + /// The reference DPI to use for scaling. + /// The fallback DPI to use if the current screen DPI is not available. + /// The screen DPI to use for scaling. If not provided, Screen.dpi will be used. + public static float CalculateEffectiveScaleFactor( + LayoutScalingMode scalingMode, + float scaleFactor, + Vector2 originalArtboardSize, + Rect frameRect, + float referenceDPI, + float fallbackDPI = 96f, + float screenDPI = -1f + ) + { + + float originalWidth = originalArtboardSize.x; + float originalHeight = originalArtboardSize.y; + switch (scalingMode) + { + case LayoutScalingMode.ConstantPixelSize: + return scaleFactor; + + case LayoutScalingMode.ReferenceArtboardSize: + { + if (originalWidth <= 0 || originalHeight <= 0) + { + return 1.0f; + } + + float widthScale = frameRect.width / originalWidth; + float heightScale = frameRect.height / originalHeight; + + // Using the height scale gives us a match with the Rive Editor + float resolutionScale = heightScale; + + return scaleFactor * resolutionScale; + } + + case LayoutScalingMode.ConstantPhysicalSize: + { + float dpi = screenDPI > 0f ? screenDPI : Screen.dpi; + if (dpi <= 0f) + { + dpi = fallbackDPI; + } + + float devicePixelRatio = dpi / referenceDPI; + + return scaleFactor * devicePixelRatio; + } + + default: + return 1.0f; + } + } + + /// + /// Calculates the new artboard dimensions based on the frame rect and effective scale. + /// + /// Returns true if resize was successful, false if invalid values were encountered. + public static bool CalculateArtboardDimensionsForLayout( + Rect frameRect, + float effectiveScaleFactor, + out float newWidth, + out float newHeight + ) + { + newWidth = 0f; + newHeight = 0f; + + // Guard against invalid scale + if (effectiveScaleFactor <= 0 || float.IsNaN(effectiveScaleFactor) || float.IsInfinity(effectiveScaleFactor)) + { + DebugLogger.Instance.LogWarning($"Invalid effective scale: {effectiveScaleFactor}"); + return false; + } + + newWidth = frameRect.width / effectiveScaleFactor; + newHeight = frameRect.height / effectiveScaleFactor; + + // Guard against invalid dimensions + if (float.IsNaN(newWidth) || float.IsInfinity(newWidth) || + float.IsNaN(newHeight) || float.IsInfinity(newHeight)) + { + DebugLogger.Instance.LogWarning($"Invalid artboard dimensions calculated. Width: {newWidth}, Height: {newHeight}"); + return false; + } + + return true; + } + + public void Dispose() + { + CleanUpBeforeLoad(); + m_renderObject = null; + } + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Helpers/ArtboardLoadHelper.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/Helpers/ArtboardLoadHelper.cs.meta new file mode 100644 index 00000000..6df0bafb --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Helpers/ArtboardLoadHelper.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 4950c4239589747169f9e77df59d7b0e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Helpers/ArtboardLoadHelper.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Helpers/CameraHelper.cs b/Packages/app.rive.rive-unity/Runtime/Components/Helpers/CameraHelper.cs new file mode 100644 index 00000000..16a7106d --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Helpers/CameraHelper.cs @@ -0,0 +1,44 @@ +using UnityEngine; + +namespace Rive.Components +{ + + internal class CameraHelper + { + private static Camera[] s_camerasInScene; + + + /// + /// Gets a valid camera in the scene to submit command buffer commands with. + /// + /// A valid camera in the scene. + public static Camera GetRenderCameraInScene() + { + + Camera camera = Camera.main; + + if (camera != null) + { + return camera; + } + + int cameraCount = Camera.allCamerasCount; + + if (cameraCount == 0) + { + return null; + } + + if (s_camerasInScene == null || s_camerasInScene.Length < cameraCount) + { + s_camerasInScene = new Camera[cameraCount]; + } + + // This only returns enabled cameras + Camera.GetAllCameras(s_camerasInScene); + + return s_camerasInScene[0]; + + } + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Helpers/CameraHelper.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/Helpers/CameraHelper.cs.meta new file mode 100644 index 00000000..272bf52f --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Helpers/CameraHelper.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 8b7f883a10f2a444cb81e1e93f601754 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Helpers/CameraHelper.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Helpers/Orchestrator.cs b/Packages/app.rive.rive-unity/Runtime/Components/Helpers/Orchestrator.cs new file mode 100644 index 00000000..3eb67ba5 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Helpers/Orchestrator.cs @@ -0,0 +1,262 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Rive.Utils; +using UnityEngine; + +namespace Rive.Components +{ + /// + /// Central per-frame orchestrator for ticking panels/widgets and then processing databinding callbacks. + /// + /// This enables "command-server-like" batching: + /// - panels register/unregister with the orchestrator + /// - on each frame, auto panels are ticked + /// - manual ticks execute immediately and notify the orchestrator + /// - changed properties are triggered after all panels have been ticked. + /// + internal sealed class Orchestrator : MonoBehaviour + { + private static bool s_isDestroyed = false; + + private static Orchestrator s_instance; + + private static readonly List s_registeredRenderTargetStrategies = new List(); + + public static Orchestrator Instance + { + get + { + + if (s_isDestroyed) + { + return null; + } + + if (s_instance != null) + { + return s_instance; + } + + // Ensure the render pipeline handler exists; the orchestrator will be attached there. + var handler = RenderPipelineHelper.GetOrCreateHandler() as MonoBehaviour; + if (handler == null) + { + return null; + } + + s_instance = handler.GetComponent(); + if (s_instance == null) + { + s_instance = handler.gameObject.AddComponent(); + } + + return s_instance; + } + } + + private readonly HashSet m_registeredPanels = new HashSet(); + private readonly List m_panelTickList = new List(); // Used to store the panels to tick in the TickAutoPanels method to avoid modifying the HashSet while iterating. + private bool m_tickedThisFrame; + + internal event Action OnPostRenderPreparation; + + private void OnDestroy() + { + m_tickedThisFrame = false; + + if (s_instance == this && !s_isDestroyed) + { + s_instance = null; + s_isDestroyed = true; + } + } + + internal void RegisterPanel(RivePanel panel) + { + if (panel == null) + { + return; + } + m_registeredPanels.Add(panel); + } + + internal void UnregisterPanel(RivePanel panel) + { + if (panel == null) + { + return; + } + m_registeredPanels.Remove(panel); + } + + internal void NotifyManualTickOccurred(RivePanel panel) + { + if (panel == null) + { + return; + } + m_tickedThisFrame = true; + } + + internal static void RegisterRenderTargetStrategy(RenderTargetStrategy strategy) + { + if (strategy == null) + { + return; + } + + // Avoid duplicates. + for (int i = 0; i < s_registeredRenderTargetStrategies.Count; i++) + { + if (ReferenceEquals(s_registeredRenderTargetStrategies[i], strategy)) + { + return; + } + } + + s_registeredRenderTargetStrategies.Add(strategy); + } + + internal static void UnregisterRenderTargetStrategy(RenderTargetStrategy strategy) + { + if (strategy == null) + { + return; + } + + // We set to null rather than remove to avoid shifting indices during reverse iteration. + for (int i = s_registeredRenderTargetStrategies.Count - 1; i >= 0; i--) + { + if (ReferenceEquals(s_registeredRenderTargetStrategies[i], strategy)) + { + s_registeredRenderTargetStrategies[i] = null; + return; + } + } + } + + private static void PrepareRenderTargetsStrategies() + { + if (s_registeredRenderTargetStrategies.Count == 0) + { + return; + } + + // We iterate in reverse so removals are safe . + for (int i = s_registeredRenderTargetStrategies.Count - 1; i >= 0; i--) + { + var strategy = s_registeredRenderTargetStrategies[i]; + + // Accounting for Unity "fake null" when the strategy is destroyed. + if (strategy == null) + { + s_registeredRenderTargetStrategies.RemoveAt(i); + continue; + } + + strategy.PrepareRenderFromOrchestrator(); + } + } + + private bool TickAutoPanels() + { + // Panels with Auto update mode are ticked here. + if (m_registeredPanels.Count == 0) + { + return false; + } + + float deltaTime = Time.deltaTime; + bool tickedAny = false; + + m_panelTickList.Clear(); + m_panelTickList.AddRange(m_registeredPanels); + + for (int i = 0; i < m_panelTickList.Count; i++) + { + var panel = m_panelTickList[i]; + + if (panel == null || !panel.isActiveAndEnabled) + { + continue; + } + + if (panel.UpdateMode != RivePanel.PanelUpdateMode.Auto) + { + continue; + } + + tickedAny = true; + + try + { + panel.TickImmediate(deltaTime); + } + catch (System.Exception e) + { + DebugLogger.Instance.LogException(e); + } + } + + m_panelTickList.Clear(); + + return tickedAny; + } + + private void Update() + { + // We advance any Rive Panels set to Auto update mode. Manual panels notify the orchestrator when they tick via NotifyManualTickOccurred. + if (TickAutoPanels()) + { + m_tickedThisFrame = true; + } + + TriggerCallbacksForChangedProperties(); + + } + + /// + /// Captures changed properties and triggers the Unity callbacks. This only triggers/checks for properties the user has subscribed to in code. + /// + private void TriggerCallbacksForChangedProperties() + { + if (RiveWidget.PropertyCallbackApproach == RiveWidget.DataBindingPropertyCallbackApproach.Orchestrator && m_tickedThisFrame) + { + if (PropertyCallbacksHub.Instance.CaptureChanges()) + { + PropertyCallbacksHub.Instance.FlushCapturedCallbacks(); // This triggers the Unity callbacks. + } + + } + m_tickedThisFrame = false; + + } + + + + private void LateUpdate() + { + + // Prepare batched rendering after ticking panels. + // This is intentionally called every frame so batched render requests (e.g. from + // registration/size/layout changes) can be handled even when no panels ticked. + PrepareRenderTargetsStrategies(); + + OnPostRenderPreparation?.Invoke(); + + } + +#if UNITY_EDITOR + // We account for Domain Reload in the editor being disabled + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] + static void Init() + { + s_instance = null; + s_isDestroyed = false; + s_registeredRenderTargetStrategies.Clear(); + } +#endif + } +} + diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Helpers/Orchestrator.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/Helpers/Orchestrator.cs.meta new file mode 100644 index 00000000..01f8b14e --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Helpers/Orchestrator.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 0fd321108f718433cbc882286a89e2fc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Helpers/Orchestrator.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Helpers/RendererUtils.cs b/Packages/app.rive.rive-unity/Runtime/Components/Helpers/RendererUtils.cs new file mode 100644 index 00000000..2d5fe1c6 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Helpers/RendererUtils.cs @@ -0,0 +1,75 @@ +using System.Collections; +using UnityEngine; + +namespace Rive.Components.Utilities +{ + + internal class RendererUtils + { + static WaitForEndOfFrame s_waitForEndOfFrame = new WaitForEndOfFrame(); + + + /// + /// Creates a renderer without a backing render texture. + /// + /// The created renderer. + public static Renderer CreateRenderer() + { + RenderQueue renderQueue = new RenderQueue(null, true, RenderPipelineHelper.CurrentHandler as MonoBehaviour); // Use the current render pipeline handler as the coroutine helper since it already exists + + return renderQueue.Renderer(); + } + + /// + /// Creates a renderer with the given render texture. + /// + /// The render texture to use with the renderer. + /// The created renderer. + public static Renderer CreateRenderer(RenderTexture renderTexture) + { + RenderQueue renderQueue = new RenderQueue(renderTexture, true, RenderPipelineHelper.CurrentHandler as MonoBehaviour); // Use the current render pipeline handler as the coroutine helper since it already exists + + return renderQueue.Renderer(); + } + + /// + /// Releases the renderer, its underlying render queue, and its resources. + /// + /// The renderer to release. + public static void ReleaseRenderer(Renderer renderer) + { + + if (renderer?.RenderQueue == null) return; + + // We need a monobehaviour to start a coroutine , so we use the current handler + // We could also create a new GameObject to start the coroutine, but for now, we know that there's a handler already for each render pipeline so we use that + // In the future, we should consider making a dedicated GameObject for this. + MonoBehaviour coroutineHelper = RenderPipelineHelper.CurrentHandler as MonoBehaviour; + + if (Application.isPlaying && coroutineHelper != null) + { + coroutineHelper.StartCoroutine(DeferredRelease(renderer)); + } + else + { + // In edit mode, we can't use coroutines, so we release the renderer immediately. + renderer.RenderQueue.Dispose(); + } + + } + + + private static IEnumerator DeferredRelease(Renderer renderer) + { + // Wait for render thread to complete current frame to release the renderer + // This helps us avoid issues/crashes when disposing the native pointer before the camera is done rendering. + + yield return s_waitForEndOfFrame; + + if (renderer?.RenderQueue != null) + { + renderer.RenderQueue.Dispose(); + } + } + } +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Helpers/RendererUtils.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/Helpers/RendererUtils.cs.meta new file mode 100644 index 00000000..fb5b85ef --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Helpers/RendererUtils.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 25cae5878573444e4b5f71085a2dc2f7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Helpers/RendererUtils.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/InputProviders.meta b/Packages/app.rive.rive-unity/Runtime/Components/InputProviders.meta new file mode 100644 index 00000000..415573c9 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/InputProviders.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a97a371038ef24edcbe6ed38b9597d03 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Runtime/Components/InputProviders/CanvasPanelInputProvider.cs b/Packages/app.rive.rive-unity/Runtime/Components/InputProviders/CanvasPanelInputProvider.cs new file mode 100644 index 00000000..a8219fab --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/InputProviders/CanvasPanelInputProvider.cs @@ -0,0 +1,159 @@ +using System; +using System.Collections.Generic; +using Rive.Utils; +using UnityEngine; +using UnityEngine.EventSystems; + +namespace Rive.Components +{ + /// + /// Provides input to a RiveCanvasRenderer and the RivePanel it displays. + /// + internal class CanvasPanelInputProvider : MonoBehaviour, IPanelInputProvider, ICanvasRaycastFilter, IPointerDownHandler, IPointerUpHandler, IPointerMoveHandler, IPointerExitHandler, IPointerEnterHandler + { + + [HideInInspector] + [SerializeField] private RiveCanvasRenderer m_riveCanvasRenderer; + + private List m_RaycastResults = new List(); + + + + private IRivePanel RivePanel + { + get + { + if (m_riveCanvasRenderer == null) + { + return null; + } + return m_riveCanvasRenderer.RivePanel; + } + } + + public event Action PointerPressed; + public event Action PointerReleased; + public event Action PointerMoved; + public event Action PointerExited; + public event Action PointerEntered; + + void OnValidate() + { + FetchPanelRendererIfNeeded(); + + } + + + private void OnEnable() + { + FetchPanelRendererIfNeeded(); + + if (m_riveCanvasRenderer == null) + { + DebugLogger.Instance.LogWarning($"No {nameof(RiveCanvasRenderer)} component found on the GameObject - {gameObject.name}"); + } + } + + private void FetchPanelRendererIfNeeded() + { + if (m_riveCanvasRenderer == null || !ReferenceEquals(m_riveCanvasRenderer.gameObject, this.gameObject)) + { + m_riveCanvasRenderer = GetComponent(); + } + } + + private static bool TryGetScreenPointToNormalizedLocalPointInFrame(RectTransform rectTransform, Vector2 screenPoint, Camera eventCamera, out Vector2 normalizedLocalPointInFrame) + { + normalizedLocalPointInFrame = Vector2.zero; + + if (rectTransform == null) + { + return false; + } + + Vector2 localPoint; + if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, screenPoint, eventCamera, out localPoint)) + { + return false; + } + + + normalizedLocalPointInFrame = Rect.PointToNormalized(rectTransform.rect, localPoint); + + return true; + } + + // When used in a canvas, we don't want the panel raycast target to block raycasts if there are no widgets to hit so we filter out the raycasts in this case. + // This allows the raycasts to pass through to regular canvas raycast targets outside of the panel. + public bool IsRaycastLocationValid(Vector2 screenPosition, Camera eventCamera) + { + if (RivePanel == null || m_riveCanvasRenderer.PointerInputMode == PointerInputMode.DisablePointerInput) + { + return false; + } + + m_RaycastResults.Clear(); + Vector2 localNormalizedPointInPanel; + if (!TryGetScreenPointToNormalizedLocalPointInFrame(m_riveCanvasRenderer.RectTransform, screenPosition, eventCamera, out localNormalizedPointInPanel)) + { + return false; + } + + PanelRaycaster.RaycastAll(RivePanel, localNormalizedPointInPanel, m_RaycastResults); + + bool locationIsValid = m_RaycastResults.Count > 0; + + + return locationIsValid; + } + + + private void ProcessPointerEvent(PointerEventData eventData, Action pointerHandler) + { + if (pointerHandler == null) + { + return; + } + + if (RivePanel == null || m_riveCanvasRenderer.PointerInputMode == PointerInputMode.DisablePointerInput || !RivePanel.Enabled) + { + return; + } + + Vector2 canvasNormalizedPoint; + if (!TryGetScreenPointToNormalizedLocalPointInFrame(m_riveCanvasRenderer.RectTransform, eventData.position, eventData.enterEventCamera, out canvasNormalizedPoint)) + { + return; + } + + int pointerId = eventData.pointerId; + pointerHandler(new PanelPointerEvent(canvasNormalizedPoint, pointerId)); + } + + public void OnPointerDown(PointerEventData eventData) + { + ProcessPointerEvent(eventData, PointerPressed); + } + + public void OnPointerUp(PointerEventData eventData) + { + ProcessPointerEvent(eventData, PointerReleased); + + } + + public void OnPointerMove(PointerEventData eventData) + { + ProcessPointerEvent(eventData, PointerMoved); + } + + public void OnPointerExit(PointerEventData eventData) + { + ProcessPointerEvent(eventData, PointerExited); + } + + public void OnPointerEnter(PointerEventData eventData) + { + ProcessPointerEvent(eventData, PointerEntered); + } + } +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Runtime/Components/InputProviders/CanvasPanelInputProvider.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/InputProviders/CanvasPanelInputProvider.cs.meta new file mode 100644 index 00000000..8446afe5 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/InputProviders/CanvasPanelInputProvider.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: f0f89e8c33fdd4e5f8ec4f5e3e33bf03 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/InputProviders/CanvasPanelInputProvider.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/InputProviders/TexturePanelInputProvider.cs b/Packages/app.rive.rive-unity/Runtime/Components/InputProviders/TexturePanelInputProvider.cs new file mode 100644 index 00000000..d50374b5 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/InputProviders/TexturePanelInputProvider.cs @@ -0,0 +1,202 @@ +using System; +using Rive.Components; +using Rive.Utils; +using UnityEngine; +using UnityEngine.EventSystems; + +namespace Rive.Components +{ + /// + /// Provides input to a RiveTextureRenderer and the RivePanel it displays. + /// + internal class TexturePanelInputProvider : MonoBehaviour, IPanelInputProvider, IPointerDownHandler, IPointerUpHandler, IPointerMoveHandler, IPointerExitHandler, IPointerEnterHandler + { + + + [HideInInspector] + [SerializeField] private RiveTextureRenderer m_rivePanelTextureRenderer; + + private bool m_hasLoggedWrongColliderTypeError = false; + private Vector2 m_lastNormalizedLocalPointInPanel = Vector2.zero; + + public event Action PointerPressed; + public event Action PointerReleased; + public event Action PointerMoved; + public event Action PointerExited; + public event Action PointerEntered; + + private IRivePanel RivePanel + { + get + { + if (m_rivePanelTextureRenderer == null) + { + return null; + } + return m_rivePanelTextureRenderer.RivePanel; + } + } + + + + private bool IsSupportedCollider(Collider collider) + { + return collider is MeshCollider; + } + + void OnEnable() + { + if (m_rivePanelTextureRenderer == null) + { + m_rivePanelTextureRenderer = GetComponent(); + + if (m_rivePanelTextureRenderer == null) + { + DebugLogger.Instance.LogWarning($"No {nameof(RiveTextureRenderer)} component found on the GameObject - {gameObject.name}"); + } + } + } + + + + /// + /// Tries to get the normalized local point in the frame from the RaycastResult. + /// + /// The RaycastResult to get the normalized local point from. + /// The normalized local point in the frame. + /// True if the normalized local point was successfully retrieved, false otherwise. + private bool TryGetNormalizedLocalPointInPanel(RaycastResult raycastResult, out Vector2 normalizedLocalPointInFrame) + { + normalizedLocalPointInFrame = Vector2.zero; + + + if (RivePanel == null) + { + return false; + } + + + if (raycastResult.gameObject == null) + { + return false; + } + + Camera camera = raycastResult.module != null ? raycastResult.module.eventCamera : null; + if (camera == null) + { + return false; + } + + Ray ray = camera.ScreenPointToRay(raycastResult.screenPosition); + + if (!Physics.Raycast(ray, out RaycastHit hit)) + { + return false; + } + + + // Get the collider from the hit object. + Collider collider = hit.collider; + + if (collider == null) + { + DebugLogger.Instance.Log("Collider is null."); + return false; + } + + + Vector2 pixelUV; + + if (IsSupportedCollider(collider)) + { + // For mesh colliders, we can use the texture coordinates directly + pixelUV = hit.textureCoord; + + } + else + { + LogWrongColliderErrorIfNeeded(); + return false; + } + + normalizedLocalPointInFrame = pixelUV; + + + return true; + } + + private void LogWrongColliderErrorIfNeeded() + { + if (!m_hasLoggedWrongColliderTypeError) + { + DebugLogger.Instance.LogWarning($"Only MeshColliders are supported for pointer input on Rive Panels. Make sure the collider on the GameObject is a MeshCollider, or set the {nameof(PointerInputMode)} to {nameof(PointerInputMode.DisablePointerInput)} on the {nameof(RiveTextureRenderer)}."); + m_hasLoggedWrongColliderTypeError = true; + } + } + + private void ProcessEvent(PointerEventData eventData, Action pointerHandler) + { + if (pointerHandler == null) + { + return; + } + + if (RivePanel == null || m_rivePanelTextureRenderer.PointerInputMode == PointerInputMode.DisablePointerInput || !RivePanel.Enabled) + { + return; + } + + bool pointIsInPanel = TryGetNormalizedLocalPointInPanel(eventData.pointerCurrentRaycast, out Vector2 normalizedLocalPointInPanel); + + if (pointIsInPanel) + { + // Store the last known point in case we need to call the event with it later (like with OnPointerExit). + m_lastNormalizedLocalPointInPanel = normalizedLocalPointInPanel; + } + else + { + // This would be the case with OnPointerExit, because the raycast wouldn't have anything to hit, so we call the event with the last known point. + normalizedLocalPointInPanel = m_lastNormalizedLocalPointInPanel; + } + + int pointerId = eventData.pointerId; + pointerHandler?.Invoke(new PanelPointerEvent(normalizedLocalPointInPanel, pointerId)); + + } + + + public void OnPointerMove(PointerEventData eventData) + { + ProcessEvent(eventData, PointerMoved); + } + + public void OnPointerUp(PointerEventData eventData) + { + ProcessEvent(eventData, PointerReleased); + } + + public void OnPointerDown(PointerEventData eventData) + { + ProcessEvent(eventData, PointerPressed); + } + + public void OnPointerExit(PointerEventData eventData) + { + ProcessEvent(eventData, PointerExited); + } + + public void OnPointerEnter(PointerEventData eventData) + { + ProcessEvent(eventData, PointerEntered); + } + + void OnValidate() + { + if (m_rivePanelTextureRenderer == null) + { + m_rivePanelTextureRenderer = GetComponent(); + } + } + + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/Components/InputProviders/TexturePanelInputProvider.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/InputProviders/TexturePanelInputProvider.cs.meta new file mode 100644 index 00000000..cb3d52e1 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/InputProviders/TexturePanelInputProvider.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 4d5c455172690403b81ea6a542509e94 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/InputProviders/TexturePanelInputProvider.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/PanelVisibilityOptimizer.cs b/Packages/app.rive.rive-unity/Runtime/Components/PanelVisibilityOptimizer.cs new file mode 100644 index 00000000..a45a1582 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/PanelVisibilityOptimizer.cs @@ -0,0 +1,171 @@ +using Rive.Utils; +using UnityEngine; + +namespace Rive.Components +{ + + + /// + /// This hides and shows RivePanels based on the visibility of the mesh renderer. It should be attached to a GameObject with a Renderer component. + /// + [RequireComponent(typeof(Renderer))] + internal class PanelVisibilityOptimizer : MonoBehaviour + { + [SerializeField] private RiveTextureRenderer m_panelRenderer; + + [SerializeField] + [Tooltip("Determines whether to optimize rendering based on visibility or always render")] + private VisibilityOptimizationMode m_visibilityMode = VisibilityOptimizationMode.RenderWhenVisible; + + // We use this flag to prevent the component from handling changes before it is fully initialized. + // The Renderer.isVisible property seems to return false before Start() so we want to avoid hiding the object in that case if it is supposed to be visible or we'll get a flash. + private bool m_readyForRenderingControl = false; + + + private bool IsVisible + { + get + { + if (m_panelRenderer == null) + { + return false; + } + + return m_panelRenderer.Renderer.isVisible; + } + + } + + /// + /// Gets or sets the visibility mode. When set to AlwaysRender, the panel will render regardless of visibility. + /// + public VisibilityOptimizationMode VisibilityMode + { + get => m_visibilityMode; + set + { + if (m_visibilityMode != value) + { + m_visibilityMode = value; + HandleVisibility(); + } + } + } + + private void OnEnable() + { + if (m_panelRenderer == null) + { + m_panelRenderer = GetComponent(); + } + + if (m_panelRenderer == null) + { + DebugLogger.Instance.LogWarning($"No ${nameof(RiveTextureRenderer)} component found on the GameObject - " + gameObject.name); + return; + } + + HandleVisibility(); + SubscribeToRiveViewEvents(m_panelRenderer.RivePanel); + } + + + private void Start() + { + HandleVisibility(); + m_readyForRenderingControl = true; + } + + private void OnDisable() + { + UnsubscribeFromRivePanelEvents(m_panelRenderer.RivePanel); + } + + private void SubscribeToRiveViewEvents(IRivePanel rivePanel) + { + if (rivePanel != null) + { + rivePanel.OnRenderingStateChanged += HandleVisibility; + } + } + + private void UnsubscribeFromRivePanelEvents(IRivePanel rivePanel) + { + if (rivePanel != null) + { + rivePanel.OnRenderingStateChanged -= HandleVisibility; + } + } + + private bool m_handlingVisibility = false; + + + + /// + /// Handles the visibility state by starting or stopping rendering based on the current visibility. + /// + private void HandleVisibility() + { + // Prevent recursive calls + if (m_handlingVisibility) + { + return; + } + + m_handlingVisibility = true; + + try + { + if (!m_readyForRenderingControl || m_panelRenderer == null || m_panelRenderer.RivePanel == null || + m_panelRenderer.Renderer == null || (m_panelRenderer.RivePanel != null && !m_panelRenderer.RivePanel.Enabled)) + { + return; + } + + if (m_visibilityMode == VisibilityOptimizationMode.AlwaysRender) + { + if (!m_panelRenderer.RivePanel.IsRendering) + { + m_panelRenderer.RivePanel.StartRendering(); + } + return; + } + + if (IsVisible && !m_panelRenderer.RivePanel.IsRendering) + { + m_panelRenderer.RivePanel.StartRendering(); + } + else if (!IsVisible && m_panelRenderer.RivePanel.IsRendering) + { + m_panelRenderer.RivePanel.StopRendering(); + } + } + finally + { + m_handlingVisibility = false; + } + } + + + + private void OnBecameVisible() + { + HandleVisibility(); + } + + private void OnBecameInvisible() + { + HandleVisibility(); + } + + + + private void OnValidate() + { + if (m_panelRenderer == null) + { + m_panelRenderer = GetComponent(); + } + } + } +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Runtime/Components/PanelVisibilityOptimizer.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/PanelVisibilityOptimizer.cs.meta new file mode 100644 index 00000000..11d3c1cc --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/PanelVisibilityOptimizer.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 19d59cb231c6e4cb58100ffa095a03b1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/PanelVisibilityOptimizer.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Previews.meta b/Packages/app.rive.rive-unity/Runtime/Components/Previews.meta new file mode 100644 index 00000000..b1df3f98 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Previews.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 25c2f19ee2e6f46939e9d2dc734e048f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Previews/CanvasPanelPreview.cs b/Packages/app.rive.rive-unity/Runtime/Components/Previews/CanvasPanelPreview.cs new file mode 100644 index 00000000..dabf6a1e --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Previews/CanvasPanelPreview.cs @@ -0,0 +1,131 @@ +using UnityEngine; + +#if UNITY_EDITOR +using UnityEditor; +using UnityEditor.SceneManagement; +using UnityEngine.SceneManagement; +#endif + +namespace Rive.Components +{ + /// + /// Handles the preview rendering for the RiveCanvasPanel component in the editor. + /// + internal class CanvasPanelPreview : PanelPreview + { +#if UNITY_EDITOR + private CanvasRendererRawImage m_displayImage; + private Texture m_lastPreviewTexture; + private bool m_isUpdating; + + public CanvasPanelPreview(RivePanel panel) : base(panel) + { + m_displayImage = panel.GetComponent(); + } + + protected override void Initialize() + { + EditorSceneManager.sceneLoaded += OnSceneLoaded; + base.Initialize(); + } + + public override void Dispose() + { + EditorSceneManager.sceneLoaded -= OnSceneLoaded; + CleanupResources(); + base.Dispose(); + } + + private void OnSceneLoaded(Scene arg0, LoadSceneMode arg1) + { + UpdateEditorPreview(); + } + + protected override void CleanupResources() + { + base.CleanupResources(); + if (m_displayImage != null) + { + m_displayImage.CleanupEditorPreview(); + } + m_lastPreviewTexture = null; + m_isUpdating = false; + } + + protected override void UpdateEditorPreview() + { + // We want to prevent multiple calls to UpdateEditorPreview in the same frame + // as that can cause performance issues and glitches + if (!m_isUpdating && RivePanel != null && RivePanel.gameObject.activeInHierarchy && RivePanel.enabled) + { + DelayedUpdatePreview(); + } + + } + + private void DelayedUpdatePreview() + { + // If the scene is not loaded, we don't want to update the preview + // because it can cause issues when switching scenes + if (m_displayImage == null && RivePanel != null) + { + m_displayImage = RivePanel.GetComponent(); + } + + if (m_displayImage == null) + { + m_isUpdating = false; + return; + } + + if (!EditorSceneManager.GetActiveScene().isLoaded || + Application.isPlaying || + RivePanel == null || + m_displayImage == null) + { + m_isUpdating = false; + return; + } + + Texture previewTexture; + + if (RivePanel == null) + { + previewTexture = GetDefaultTexture(); + } + else + { + RenderTexture rt = RenderPreview(); + previewTexture = rt != null ? rt : GetDefaultTexture(); + } + + // Ensure correct color in Linear/Gamma space by using the decode UI material + var decodeMat = Rive.TextureHelper.GammaToLinearUIMaterial; + if (decodeMat != null && m_displayImage.material != decodeMat) + { + m_displayImage.material = decodeMat; + } + + if (previewTexture != m_lastPreviewTexture || m_displayImage.mainTexture != previewTexture) + { + m_displayImage.UpdateEditorPreview(previewTexture); + + m_lastPreviewTexture = previewTexture; + + // Update PreviewRenderTexture only if the new texture is a RenderTexture + if (previewTexture is RenderTexture) + { + PreviewRenderTexture = previewTexture as RenderTexture; + } + else + { + PreviewRenderTexture = null; + } + } + + m_isUpdating = false; + + } +#endif + } +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Previews/CanvasPanelPreview.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/Previews/CanvasPanelPreview.cs.meta new file mode 100644 index 00000000..2679d6de --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Previews/CanvasPanelPreview.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 17e1997b8c0174714944d4f6cb06ead1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Previews/CanvasPanelPreview.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Previews/PanelContextPreviewManager.cs b/Packages/app.rive.rive-unity/Runtime/Components/Previews/PanelContextPreviewManager.cs new file mode 100644 index 00000000..9ce351b1 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Previews/PanelContextPreviewManager.cs @@ -0,0 +1,143 @@ +using UnityEngine; + +#if UNITY_EDITOR +using UnityEditor; +#endif + +namespace Rive.Components +{ + /// + /// Manages the preview of the RivePanel depending on its context. e.g Within a Canvas or in World Space as a texture. + /// +#if UNITY_EDITOR + [ExecuteInEditMode] +#endif + internal class PanelContextPreviewManager : MonoBehaviour + { + private enum PanelContextOption + { + Unset = 0, + Canvas = 1, + World = 2 + } + + [HideInInspector] + [SerializeField] private RivePanel m_rivePanel; + +#if UNITY_EDITOR + private PanelContextOption m_panelContext; + private PanelPreview m_currentPreview; + + private PanelContextOption PanelContext + { + get => m_panelContext; + set + { + if (m_panelContext != value || m_currentPreview == null) + { + m_panelContext = value; + SpawnPreviewForContext(); + } + } + } + + private void OnEnable() + { + if (Application.isPlaying) + { + return; + } + + if (m_rivePanel == null) + { + m_rivePanel = GetComponent(); + } + CheckContext(); + } + + private void OnDisable() + { + if (Application.isPlaying) + { + return; + } + + + if (m_currentPreview != null) + { + m_currentPreview.Dispose(); + m_currentPreview = null; + } + } + + private void SpawnPreviewForContext() + { + if (Application.isPlaying || m_rivePanel == null) + { + return; + } + + // Cleanup existing preview + if (m_currentPreview != null) + { + m_currentPreview.Dispose(); + m_currentPreview = null; + } + + + // Create new preview based on context + if (PanelContext == PanelContextOption.Canvas) + { + m_currentPreview = new CanvasPanelPreview(m_rivePanel); + } + else if (PanelContext == PanelContextOption.World) + { + m_currentPreview = new WorldspacePanelPreview(m_rivePanel); + } + } + + private bool IsPanelInOrOnCanvas() + { + if (m_rivePanel == null) + { + return false; + } + + Canvas canvas = m_rivePanel.GetComponentInParent(); + return canvas != null; + } + + private void CheckContext() + { + if (m_rivePanel == null || Application.isPlaying) + { + return; + } + + PanelContext = IsPanelInOrOnCanvas() ? PanelContextOption.Canvas : PanelContextOption.World; + } + + private void OnTransformParentChanged() + { + CheckContext(); + } + + private void OnValidate() + { + if (m_rivePanel == null) + { + m_rivePanel = GetComponent(); + } + } + + void Reset() + { + // This is called as soon as component is added in inspector + // This component in particular seems to cause issues with the HideFlags when used with the HideComponentsAttribute in the RivePanel component. + // This is a workaround to ensure that the HideFlags are set correctly. + this.hideFlags = HideFlags.HideInInspector; + } + +#endif + } +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Previews/PanelContextPreviewManager.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/Previews/PanelContextPreviewManager.cs.meta new file mode 100644 index 00000000..2c98bcfb --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Previews/PanelContextPreviewManager.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: f654c708803f043dfb10eb862af9e868 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Previews/PanelContextPreviewManager.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Previews/PanelPreview.cs b/Packages/app.rive.rive-unity/Runtime/Components/Previews/PanelPreview.cs new file mode 100644 index 00000000..1f3b9f98 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Previews/PanelPreview.cs @@ -0,0 +1,671 @@ +using UnityEngine; +using Rive.Components.Utilities; +using Rive.Utils; + +#if UNITY_EDITOR +using System.Collections.Generic; +using System.Linq; +using UnityEditor; +#endif + +namespace Rive.Components +{ + /// + /// Base class for preview rendering of RivePanel components in the editor. + /// + internal abstract class PanelPreview + { +#if UNITY_EDITOR + private class WidgetState + { + private Asset m_lastAsset; + private File m_lastFile; + private Fit m_lastFit; + private Alignment m_lastAlignment; + private string m_lastArtboardName; + private string m_lastStateMachineName; + private Vector2 m_lastDimensions; + + private LayoutScalingMode m_lastScalingMode; + private float m_lastScaleFactor; + + private float m_lastReferenceDPI; + + private float m_lastFallbackDPI; + + private Vector2 m_lastScreenSize; + + private RiveWidget m_riveWidget; + + private ArtboardLoadHelper m_riveViewController; + + private RectTransform m_rectTransform; + + private RivePanel m_rivePanel; + private bool m_needsReload = true; + + private bool m_gameObjectActive; + + + + public WidgetState(RiveWidget riveWidget, ArtboardLoadHelper riveViewController, RivePanel rivePanel) + { + // Get the RectTransform of the widget because we don't know that it is populated yet on the RiveWidget + m_rectTransform = riveWidget.GetComponent(); + m_rivePanel = rivePanel; + + m_lastAsset = riveWidget.Asset; + m_lastFit = riveWidget.Fit; + m_lastAlignment = riveWidget.Alignment; + m_lastArtboardName = riveWidget.ArtboardName; + m_lastStateMachineName = riveWidget.StateMachineName; + m_lastDimensions = m_rectTransform.rect.size; + m_gameObjectActive = riveWidget.gameObject.activeInHierarchy; + + m_lastScalingMode = riveWidget.ScalingMode; + m_lastScaleFactor = riveWidget.ScaleFactor; + m_lastFallbackDPI = riveWidget.FallbackDPI; + m_lastReferenceDPI = riveWidget.ReferenceDPI; + + m_riveWidget = riveWidget; + m_riveViewController = riveViewController; + + // We track the screen size to detect changes when the user changes the resolution. This is important for layout scaling. + m_lastScreenSize = new Vector2(Screen.width, Screen.height); + + LoadIfNeeded(); + + } + + public IRenderObject ToRenderObject(RectTransform clonedRectTransform, RectTransform clonedPanelRectTransform) + { + if (m_riveViewController == null || m_riveWidget == null || m_riveWidget.Asset == null || !m_riveWidget.gameObject.activeInHierarchy || !m_riveWidget.enabled || m_riveWidget.RectTransform == null) + { + return null; + } + LoadIfNeeded(); + + if (clonedRectTransform != null && clonedPanelRectTransform != null) + { + m_riveViewController.RenderObject.RenderTransform = RenderTransform.FromRectTransform(clonedRectTransform, clonedPanelRectTransform); + } + + return m_riveViewController.RenderObject; + } + + private string GetValidArtboardName(RiveWidget widget) + { + if (widget.Asset == null) return null; + + var metadata = widget.Asset.EditorOnlyMetadata; + var artboardNames = metadata.GetArtboardNames(); + + // If no artboard name is specified or the specified one isn't valid, use the first available + if (string.IsNullOrEmpty(widget.ArtboardName) || !artboardNames.Contains(widget.ArtboardName)) + { + return artboardNames.Length > 0 ? artboardNames[0] : null; + } + + return widget.ArtboardName; + } + + private string GetValidStateMachineName(RiveWidget widget, string artboardName) + { + if (widget.Asset == null || string.IsNullOrEmpty(artboardName)) return null; + + var metadata = widget.Asset.EditorOnlyMetadata; + var stateMachineNames = metadata.GetStateMachineNames(artboardName); + + // If no state machine is specified or the specified one isn't valid, use the first available + if (string.IsNullOrEmpty(widget.StateMachineName) || !stateMachineNames.Contains(widget.StateMachineName)) + { + return stateMachineNames.Length > 0 ? stateMachineNames[0] : null; + } + + return widget.StateMachineName; + } + + + + private void LoadIfNeeded() + { + + if (m_needsReload && m_riveWidget.Asset != null && m_riveViewController != null) + { + if (m_lastFile != null) + { + m_lastFile.Dispose(); + } + + m_lastFile = File.Load(m_riveWidget.Asset); + + string validArtboardName = GetValidArtboardName(m_riveWidget); + string validStateMachineName = GetValidStateMachineName(m_riveWidget, validArtboardName); + + if (validArtboardName != null && validStateMachineName != null) + { + m_riveViewController.Load( + m_lastFile, + m_riveWidget.Fit, + m_riveWidget.Alignment, + validArtboardName, + validStateMachineName, + m_riveWidget.ScaleFactor, + new ArtboardLoadHelper.DataBindingLoadInfo(RiveWidget.DataBindingMode.Manual, null) + ); + + if (m_riveViewController.Artboard != null && m_riveWidget.Fit == Fit.Layout) + { + Vector2 originalArtboardSize = new Vector2(m_riveViewController.OriginalArtboardWidth, m_riveViewController.OriginalArtboardHeight); + float effectiveScaleFactor = ArtboardLoadHelper.CalculateEffectiveScaleFactor(m_riveWidget.ScalingMode, m_riveWidget.ScaleFactor, originalArtboardSize, m_riveWidget.RectTransform.rect, m_riveWidget.ReferenceDPI, m_riveWidget.FallbackDPI); + m_riveViewController.RenderObject.EffectiveLayoutScaleFactor = effectiveScaleFactor; + if (ArtboardLoadHelper.CalculateArtboardDimensionsForLayout(m_riveWidget.RectTransform.rect, effectiveScaleFactor, out float width, out float height)) + { + m_riveViewController.Artboard.Width = width; + m_riveViewController.Artboard.Height = height; + + } + + if (m_riveViewController.StateMachine != null) + { + // Seems like we need to do this again to have the layout show up correctly on the first frame + m_riveViewController.StateMachine.Advance(0f); + + } + + + } + if (m_riveViewController.StateMachine != null) + { + m_riveViewController.StateMachine.Advance(0f); + + } + } + m_needsReload = false; + } + } + + + + public bool HasChanged() + { + if (m_riveWidget == null) return false; + + var dimensions = m_rectTransform.rect.size; + + // These settings require a reload of the file + m_needsReload = m_lastAsset != m_riveWidget.Asset || + m_lastFit != m_riveWidget.Fit || + m_lastAlignment != m_riveWidget.Alignment || + m_lastArtboardName != m_riveWidget.ArtboardName || + m_lastStateMachineName != m_riveWidget.StateMachineName; + + // We reload the file if the scaling mode or scale factor changes + if (!m_needsReload && m_riveWidget.Fit == Fit.Layout) + { + m_needsReload = (m_lastScalingMode != m_riveWidget.ScalingMode || m_lastScaleFactor != m_riveWidget.ScaleFactor || m_lastReferenceDPI != m_riveWidget.ReferenceDPI || m_lastFallbackDPI != m_riveWidget.FallbackDPI || m_lastScreenSize != new Vector2(Screen.width, Screen.height)); + } + + + bool changed = m_needsReload || m_lastDimensions != dimensions || m_rectTransform.hasChanged || m_gameObjectActive != m_riveWidget.gameObject.activeInHierarchy; + + + + + if (changed) + { + + + m_lastAsset = m_riveWidget.Asset; + m_lastFit = m_riveWidget.Fit; + m_lastAlignment = m_riveWidget.Alignment; + m_lastArtboardName = m_riveWidget.ArtboardName; + m_lastStateMachineName = m_riveWidget.StateMachineName; + m_lastDimensions = dimensions; + m_gameObjectActive = m_riveWidget.gameObject.activeInHierarchy; + + m_lastScalingMode = m_riveWidget.ScalingMode; + m_lastScaleFactor = m_riveWidget.ScaleFactor; + m_lastFallbackDPI = m_riveWidget.FallbackDPI; + m_lastReferenceDPI = m_riveWidget.ReferenceDPI; + + m_lastScreenSize = new Vector2(Screen.width, Screen.height); + } + + if (m_rectTransform.hasChanged) + { + m_rectTransform.hasChanged = false; + } + + return changed; + } + + public void Cleanup() + { + if (m_lastFile != null) + { + m_lastFile.Dispose(); + } + m_lastFile = null; + m_riveViewController?.Dispose(); + } + + } + + protected readonly RivePanel m_rivePanel; + protected static Texture2D s_defaultTexture; + private RenderTexture m_previewRenderTexture; + private int m_lastPanelChildCount; + private Dictionary m_widgetStates = new Dictionary(); + private List m_disabledWidgets = new List(); + private int m_lastScreenWidth; + private int m_lastScreenHeight; + + private const float TARGET_EDITOR_FPS = 30f; + private float m_lastUpdateTime; + + + private Renderer m_renderer; + + + public RenderTexture PreviewRenderTexture + { + get => m_previewRenderTexture; + protected set => m_previewRenderTexture = value; + } + public RivePanel RivePanel => m_rivePanel; + + protected PanelPreview(RivePanel panel) + { + m_rivePanel = panel; + Initialize(); + } + + protected virtual void Initialize() + { + if (m_rivePanel == null) return; + + EditorApplication.update += OnEditorUpdate; + EditorApplication.playModeStateChanged += OnPlayModeStateChanged; + + UpdateEditorPreview(); + } + + public virtual void Dispose() + { + EditorApplication.update -= OnEditorUpdate; + EditorApplication.playModeStateChanged -= OnPlayModeStateChanged; + + CleanupResources(); + } + + private void OnPlayModeStateChanged(PlayModeStateChange state) + { + if (state == PlayModeStateChange.EnteredPlayMode) + { + CleanupResources(); + } + } + + protected virtual void CleanupResources() + { + CleanupPreviewRenderTexture(); + + foreach (var widgetState in m_widgetStates.Values) + { + widgetState?.Cleanup(); + } + m_widgetStates.Clear(); + m_disabledWidgets.Clear(); + + if (m_renderer != null) + { + m_renderer.RenderQueue.Dispose(); + m_renderer = null; + } + } + + private bool m_wasEditorPreviewDisabled = true; + + protected virtual void OnEditorUpdate() + { + if (m_rivePanel == null) return; + + if (m_rivePanel.DisableEditorPreview) + { + if (m_previewRenderTexture != null && !m_wasEditorPreviewDisabled) + { + Dispose(); + m_wasEditorPreviewDisabled = true; + + } + return; + } + else if (m_wasEditorPreviewDisabled && !m_rivePanel.DisableEditorPreview) + { + Initialize(); + m_wasEditorPreviewDisabled = false; + } + + if (!Application.isPlaying) + { + float currentTime = Time.realtimeSinceStartup; + if (currentTime - m_lastUpdateTime >= 1f / TARGET_EDITOR_FPS) + { + if (HasChanged()) + { + UpdateEditorPreview(); + m_lastUpdateTime = currentTime; + // We use this to force the editor to update the preview when any of the widget settings change. + // If we don't, the update might be delayed until the user interacts with the scene view or somewhere else in the editor. This might give the impression that the settings are not working. + EditorApplication.QueuePlayerLoopUpdate(); + } + } + + } + } + + + protected virtual bool HasChanged() + { + if (m_rivePanel == null) return false; + + bool sizeChanged = m_lastScreenWidth != Screen.width || m_lastScreenHeight != Screen.height; + if (sizeChanged) + { + m_lastScreenWidth = Screen.width; + m_lastScreenHeight = Screen.height; + return true; + } + + foreach (var widget in m_widgetStates) + { + if (widget.Value.HasChanged()) + { + return true; + } + } + + bool childCountChanged = m_lastPanelChildCount != m_rivePanel.transform.childCount; + if (childCountChanged) + { + m_lastPanelChildCount = m_rivePanel.transform.childCount; + return true; + } + + int disabledWidgetEnabledCount = 0; + if (m_disabledWidgets.Count > 0) + { + for (int i = m_disabledWidgets.Count - 1; i >= 0; i--) + { + if (m_disabledWidgets[i].gameObject.activeInHierarchy) + { + m_disabledWidgets.RemoveAt(i); + disabledWidgetEnabledCount++; + } + } + } + + return disabledWidgetEnabledCount > 0; + } + + protected abstract void UpdateEditorPreview(); + + private bool IsWidgetConfigurationValid(RiveWidget widget) + { + if (widget.Asset == null) return false; + + var metadata = widget.Asset.EditorOnlyMetadata; + var artboardNames = metadata.GetArtboardNames(); + + // Check if artboard name is valid + if (string.IsNullOrEmpty(widget.ArtboardName) || + !artboardNames.Contains(widget.ArtboardName)) + { + return false; + } + + // Check if state machine name is valid + var stateMachineNames = metadata.GetStateMachineNames(widget.ArtboardName); + if (string.IsNullOrEmpty(widget.StateMachineName) || + !stateMachineNames.Contains(widget.StateMachineName)) + { + return false; + } + + return true; + } + + private bool WidgetIsChildOfPanel(RiveWidget widget) + { + if (widget == null) + { + return false; + } + + + + return widget.transform.IsChildOf(m_rivePanel.transform); + } + + protected RenderTexture RenderPreview() + { + if (m_rivePanel == null || !m_rivePanel.enabled) + { + return null; + } + + + int width = (int)m_rivePanel.WidgetContainer.rect.width; + int height = (int)m_rivePanel.WidgetContainer.rect.height; + + if (width < 1 || height < 1) + { + return null; + } + + bool dimensionsChanged = m_previewRenderTexture == null || m_previewRenderTexture.width != width || m_previewRenderTexture.height != height; + + if (dimensionsChanged) + { + if (m_previewRenderTexture == null) + { + m_previewRenderTexture = CreateRenderTexture(width, height); + } + else + { + m_previewRenderTexture.Release(); + m_previewRenderTexture.width = width; + m_previewRenderTexture.height = height; + m_previewRenderTexture.Create(); + } + } + + List currentWidgets = new List(); + m_rivePanel.GetComponentsInChildren(currentWidgets); + + // Filter out widgets with invalid configurations + currentWidgets = currentWidgets.Where(widget => + widget != null && + widget.gameObject.activeInHierarchy && + widget.Asset != null && + IsWidgetConfigurationValid(widget) + ).ToList(); + + if (currentWidgets.Count == 0) + { + return null; + } + + + // Remove widget states for widgets that no longer exist + m_widgetStates.Keys.Where(widget => !currentWidgets.Contains(widget)).ToList().ForEach(widget => + { + m_widgetStates[widget].Cleanup(); + // If the widget is disabled and still a child of the panel, we need to keep it around for the next frame to check if it is enabled again + if (widget != null && !widget.gameObject.activeInHierarchy && WidgetIsChildOfPanel(widget) && !m_disabledWidgets.Contains(widget)) + { + m_disabledWidgets.Add(widget); + } + m_widgetStates.Remove(widget); + }); + + if (currentWidgets.All(widget => widget.gameObject.activeInHierarchy == false) || currentWidgets.All(widget => widget.Asset == null)) + { + return null; + } + + + + RenderTexture rt = dimensionsChanged ? CreateRenderTexture(width, height) : m_previewRenderTexture; + RenderTexture previousActive = RenderTexture.active; + RenderTexture.active = rt; + + + if (m_renderer != null) + { + // When using OpenGL in the Unity Editor, we get this error if we try to use the same renderer each time: OPENGL NATIVE PLUG-IN ERROR: GL_INVALID_OPERTATION: Operation Invalid in current state. + // Current workaround is to dispose the renderer and create a new one when needed. + if (TextureHelper.IsOpenGLPlatform()) + { + m_renderer.RenderQueue.Dispose(); + m_renderer = null; + } + else + { + // For other platforms, we clear the existing renderer to avoid rendering leftover data from the previous visual. + m_renderer.Clear(); + + } + } + + //var rq = new RenderQueue(SystemInfo.graphicsDeviceType == GraphicsDeviceType.Metal ? null : rt); <-- Doing this causes the Unity Editor to hang when the RivePanel game object is duplicated. + if (m_renderer == null) + { + var rq = new RenderQueue(rt); + + m_renderer = rq.Renderer(); + } + + if (!ReferenceEquals(m_renderer.RenderQueue.Texture, rt)) + { + m_renderer.RenderQueue.UpdateTexture(rt); + } + + + + + + for (int i = 0; i < currentWidgets.Count; i++) + { + var widget = currentWidgets[i]; + + if (widget == null) + { + continue; + } + + + + if (!m_widgetStates.TryGetValue(widget, out WidgetState widgetState)) + { + ArtboardLoadHelper riveViewController = new ArtboardLoadHelper(); + widgetState = new WidgetState(widget, riveViewController, m_rivePanel); + m_widgetStates.Add(widget, widgetState); + } + + IRenderObject renderObject = widgetState.ToRenderObject(widget.RectTransform, m_rivePanel.WidgetContainer); + + if (renderObject == null) + { + continue; + } + RenderContext renderContext = new RenderContext(RenderContext.ClippingModeSetting.CheckClipping); + RenderTargetStrategy.DrawRenderObject(m_renderer, renderObject, m_rivePanel, renderContext); + + } + + var cmb = m_renderer.ToCommandBuffer(); + + cmb.SetRenderTarget(rt); + m_renderer.AddToCommandBuffer(cmb); + + + Graphics.ExecuteCommandBuffer(cmb); + + GL.InvalidateState(); + + cmb.Clear(); + + + RenderTexture.active = previousActive; + + return rt; + } + + protected void CleanupPreviewRenderTexture() + { + if (m_previewRenderTexture != null) + { + RenderTexture activeRT = RenderTexture.active; + if (activeRT == m_previewRenderTexture) + { + RenderTexture.active = null; + } + ReleaseRenderTexture(m_previewRenderTexture); + m_previewRenderTexture = null; + } + } + + protected RenderTexture CreateRenderTexture(int width, int height) + { + var descriptor = TextureHelper.Descriptor(width, height); + RenderTexture rt = new RenderTexture(descriptor); + + rt.Create(); + + return rt; + } + + protected void ReleaseRenderTexture(RenderTexture rt) + { + + if (rt != null) + { + rt.Release(); + } + + } + + protected Texture2D GetDefaultTexture() + { + if (s_defaultTexture == null) + { + string iconPath = "Packages/app.rive.rive-unity/Editor/Images/rive-preview-image.png"; + s_defaultTexture = AssetDatabase.LoadAssetAtPath(iconPath); + + if (s_defaultTexture == null) + { + DebugLogger.Instance.LogWarning($"Failed to load default texture from {iconPath}. Creating a plain colored texture instead."); + s_defaultTexture = new Texture2D(1600, 900, TextureFormat.RGBA32, false); + UnityEngine.Color darkGrey = new UnityEngine.Color(0.2f, 0.2f, 0.2f, 1f); + UnityEngine.Color[] colors = new UnityEngine.Color[1600 * 900]; + for (int i = 0; i < colors.Length; i++) + { + colors[i] = darkGrey; + } + s_defaultTexture.SetPixels(colors); + s_defaultTexture.Apply(); + } + else + { + s_defaultTexture.wrapMode = TextureWrapMode.Clamp; + s_defaultTexture.filterMode = FilterMode.Bilinear; + } + } + + return s_defaultTexture; + } +#endif + } +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Previews/PanelPreview.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/Previews/PanelPreview.cs.meta new file mode 100644 index 00000000..960817fb --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Previews/PanelPreview.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 9410f690dabce4a2ab400bad8a3e3e50 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Previews/PanelPreview.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Previews/WorldspacePanelPreview.cs b/Packages/app.rive.rive-unity/Runtime/Components/Previews/WorldspacePanelPreview.cs new file mode 100644 index 00000000..4623fc78 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Previews/WorldspacePanelPreview.cs @@ -0,0 +1,245 @@ +using UnityEngine; +using System.Collections; + +#if UNITY_EDITOR + +using UnityEditor; +using UnityEditor.SceneManagement; + +#endif + +namespace Rive.Components +{ + + /// + /// Handles the preview rendering for the RivePanel component in the scene when in Edit mode. + /// + internal class WorldspacePanelPreview : PanelPreview + { +#if UNITY_EDITOR + private Texture m_lastPreviewTexture; + private GameObject m_previewQuad; + private Material m_previewMaterial; + private bool m_isUpdating; + private Coroutine m_updateCoroutine; + + public WorldspacePanelPreview(RivePanel panel) : base(panel) { } + + protected override void Initialize() + { + base.Initialize(); + SceneView.duringSceneGui += OnSceneGUI; + CreatePreviewQuad(); + } + + public override void Dispose() + { + if (m_updateCoroutine != null && RivePanel != null) + { + RivePanel.StopCoroutine(m_updateCoroutine); + m_updateCoroutine = null; + } + SceneView.duringSceneGui -= OnSceneGUI; + DestroyPreviewQuad(); + base.Dispose(); + } + + protected override void OnEditorUpdate() + { + base.OnEditorUpdate(); + + if ((!SceneViewIsVisible() || !IsRelevantObjectSelected()) && m_previewQuad != null) + { + m_previewQuad.SetActive(false); + } + } + + private bool IsRelevantObjectSelected() + { + if (Selection.activeGameObject == null) return false; + + if (RivePanel == null) return false; + + // We only want to show the preview if the selected object is the panel itself + if (Selection.activeGameObject == RivePanel.gameObject) return true; + + // Or if the selected object is a child widget of the panel + return Selection.activeGameObject.transform.IsChildOf(RivePanel.transform); + } + + private bool SceneViewIsVisible() + { + return EditorWindow.focusedWindow != null && + (EditorWindow.focusedWindow.GetType().Name == "SceneView" || + EditorWindow.focusedWindow.titleContent.text == "Scene"); + } + + protected override void UpdateEditorPreview() + { + if (!m_isUpdating && RivePanel.gameObject.activeInHierarchy && RivePanel.enabled) + { + // So we use a coroutine here instead of immediate execution because the preview quad's material needs to be updated in a specific timing relative to + // Unity's render pipeline otherwise the graphic won't show up. The 'yield return null' in the coroutine ensures that our texture update happens at the right moment in the frame, preventing visual artifacts like white/blank textures that can happen with immediate execution. + // Technically, we could use EditorApplication.delayCall here, but that introduces a visual delay which is not ideal. + if (m_updateCoroutine == null) + { + m_updateCoroutine = RivePanel.StartCoroutine(UpdatePreviewCoroutine()); + } + } + } + + private IEnumerator UpdatePreviewCoroutine() + { + m_isUpdating = true; + yield return null; + + if (!EditorSceneManager.GetActiveScene().isLoaded || Application.isPlaying || RivePanel == null) + { + m_isUpdating = false; + m_updateCoroutine = null; + yield break; + } + + Texture previewTexture; + if (RivePanel == null) + { + previewTexture = GetDefaultTexture(); + } + else + { + RenderTexture rt = RenderPreview(); + previewTexture = rt != null ? rt : GetDefaultTexture(); + } + + // Apply color correction in both Linear and Gamma color spaces for correct preview display + // We also do this for Gamma to address issues with premultiplied alpha textures appearing incorrectly. + // The scene view renders 3D objects normally, so we need to use a material that decodes + // Rive's gamma output to linear for the scene view to display correctly. + var decodeMat = Rive.TextureHelper.GammaToLinearUIMaterial; + if (decodeMat != null && m_previewMaterial != null && m_previewMaterial.shader != decodeMat.shader) + { + m_previewMaterial.shader = decodeMat.shader; + } + + if (previewTexture != m_lastPreviewTexture) + { + if (m_previewMaterial != null) + { + m_previewMaterial.mainTexture = previewTexture; + } + + m_lastPreviewTexture = previewTexture; + PreviewRenderTexture = previewTexture as RenderTexture; + } + + m_isUpdating = false; + m_updateCoroutine = null; + } + + private void OnSceneGUI(SceneView sceneView) + { + if (m_previewQuad != null && m_lastPreviewTexture != null && IsRelevantObjectSelected()) + { + AlignPreviewQuad(); + m_previewQuad.SetActive(true); + } + } + + private void CreatePreviewQuad() + { + if (m_previewQuad == null) + { + m_previewQuad = new GameObject("RivePreviewQuad"); + m_previewQuad.hideFlags = HideFlags.HideAndDontSave; + + MeshFilter mf = m_previewQuad.AddComponent(); + MeshRenderer mr = m_previewQuad.AddComponent(); + + Mesh mesh = new Mesh + { + vertices = new Vector3[] + { + new Vector3(-0.5f, -0.5f, 0), + new Vector3(0.5f, -0.5f, 0), + new Vector3(-0.5f, 0.5f, 0), + new Vector3(0.5f, 0.5f, 0) + }, + uv = new Vector2[] + { + new Vector2(0, 0), + new Vector2(1, 0), + new Vector2(0, 1), + new Vector2(1, 1) + }, + triangles = new int[] + { + // Front face + 0, 2, 1, + 2, 3, 1, + + // Back face + 1, 2, 0, + 1, 3, 2 + } + }; + mf.mesh = mesh; + + // We use the transparent shader (instead of something like "Unlit/Texture") to make sure Rive files with transparency are displayed correctly in the scene view + Shader previewShader = Shader.Find("Unlit/Transparent"); + m_previewMaterial = new Material(previewShader); + m_previewMaterial.renderQueue = 3000; + + m_previewMaterial = new Material(previewShader); + mr.material = m_previewMaterial; + + if (SceneViewIsVisible()) + { + m_previewQuad.SetActive(true); + } + else + { + m_previewQuad.SetActive(false); + } + } + } + + private void DestroyPreviewQuad() + { + if (m_previewQuad != null) + { + Object.DestroyImmediate(m_previewQuad); + } + if (m_previewMaterial != null) + { + Object.DestroyImmediate(m_previewMaterial); + } + } + + private void AlignPreviewQuad() + { + RectTransform rectTransform = RivePanel.transform as RectTransform; + if (rectTransform == null || m_previewQuad == null) + return; + + // Match the position and rotation of the RectTransform + m_previewQuad.transform.position = rectTransform.position; + m_previewQuad.transform.rotation = rectTransform.rotation; + + Vector2 size = rectTransform.rect.size; + Vector3 rectScale = rectTransform.lossyScale; + m_previewQuad.transform.localScale = new Vector3(size.x * rectScale.x, size.y * rectScale.y, 1); + + // Ensure the quad is slightly in front of the actual object + m_previewQuad.transform.position += m_previewQuad.transform.forward * 0.01f; + } + + protected override void CleanupResources() + { + base.CleanupResources(); + DestroyPreviewQuad(); + m_lastPreviewTexture = null; + m_isUpdating = false; + } +#endif + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Previews/WorldspacePanelPreview.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/Previews/WorldspacePanelPreview.cs.meta new file mode 100644 index 00000000..00f95bf7 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Previews/WorldspacePanelPreview.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 5297c15f4f9524c60aa1bc8f6c0ecd5e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Previews/WorldspacePanelPreview.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public.meta new file mode 100644 index 00000000..51e19ec8 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f264a7577b7ec403b9cf06b578373b90 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/Audio.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/Audio.meta new file mode 100644 index 00000000..cf468e97 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/Audio.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f4709e04b56d74c2f9fae090677e96d2 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/Audio/AudioProvider.cs b/Packages/app.rive.rive-unity/Runtime/Components/Public/Audio/AudioProvider.cs new file mode 100644 index 00000000..407ba6b8 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/Audio/AudioProvider.cs @@ -0,0 +1,120 @@ +using Rive.Utils; +using UnityEngine; + +namespace Rive.Components +{ + /// + /// Provides audio playback functionality for Rive Widgets. + /// This component is not supported in WebGL builds; on that platform, system audio is used instead of routing through Unity's AudioSource. + /// + [RequireComponent(typeof(AudioSource))] + public class AudioProvider : MonoBehaviour + { + private AudioEngine m_audioEngine; + private AudioSource m_audioSource; + private bool m_isDestroyed = false; + + + /// + /// The Rive Audio Engine instance used by this AudioProvider. + /// + internal AudioEngine AudioEngine + { + get + { + if (m_audioEngine == null && !m_isDestroyed) + { + m_audioEngine = InitEngine(); + } + return m_audioEngine; + } + } + + /// + /// The AudioSource component used for audio playback. + /// + public AudioSource AudioSource + { + get + { + return m_audioSource; + } + } + + + private void Awake() + { + LogWebGLWarningIfNeeded(); + m_audioSource = GetComponent(); + + if (m_audioSource == null) + { + DebugLogger.Instance.LogError($"AudioProvider component is missing an AudioSource component on the same game object."); + return; + } + + // On iOS and Android, audio doesn't start automatically unless we call manually Play() here. + // It works fine in the Unity Editor and standalone PC/Mac builds without this, though. + // For consistency, we call Play() here always until we find a better solution. + if (!m_audioSource.isPlaying) + { + m_audioSource.Play(); + } + } + + + void OnAudioFilterRead(float[] data, int channels) + { + if (m_audioEngine == null) + { + return; + } + m_audioEngine.Sum(data, channels); + + } + + private AudioEngine InitEngine() + { + int channelCount = 1; + switch (AudioSettings.speakerMode) + { + case AudioSpeakerMode.Mono: + channelCount = 1; + break; + case AudioSpeakerMode.Stereo: + channelCount = 2; + break; + case AudioSpeakerMode.Quad: + channelCount = 4; + break; + case AudioSpeakerMode.Surround: + channelCount = 5; + break; + case AudioSpeakerMode.Mode5point1: + channelCount = 6; + break; + case AudioSpeakerMode.Mode7point1: + channelCount = 8; + break; + case AudioSpeakerMode.Prologic: + channelCount = 2; + break; + } + + return Rive.AudioEngine.Make(channelCount, AudioSettings.outputSampleRate); + } + + private void LogWebGLWarningIfNeeded() + { +#if UNITY_WEBGL && !UNITY_EDITOR + DebugLogger.Instance.LogWarning($"The {nameof(AudioProvider)} component is not supported in WebGL builds. System audio will be used instead of routing audio through Unity's AudioSource."); +#endif + } + + + private void OnDestroy() + { + m_isDestroyed = true; + } + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/Audio/AudioProvider.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/Audio/AudioProvider.cs.meta new file mode 100644 index 00000000..24bfc240 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/Audio/AudioProvider.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 3a93fce690c804e7b829dd9d62ca1ecd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/Audio/AudioProvider.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/HitTesting.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/HitTesting.meta new file mode 100644 index 00000000..6e38ad0b --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/HitTesting.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 776aac42a40774462ad1eda3d1abf7de +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/HitTesting/HitTestBehavior.cs b/Packages/app.rive.rive-unity/Runtime/Components/Public/HitTesting/HitTestBehavior.cs new file mode 100644 index 00000000..b148c267 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/HitTesting/HitTestBehavior.cs @@ -0,0 +1,33 @@ +using System; + +namespace Rive.Components +{ + /// + /// The hit test behavior of a RiveWidget in relation to other elements. + /// + public enum HitTestBehavior + { + + /// + /// The bounds of the RiveWidget will consume all hits, even if there is no listener (hit area) at the target point. Content behind the RiveWidget will not receive hits. + /// + Opaque = 0, + + /// + /// The RiveWidget will only consume hits where there is a listener (hit area) at the target point. Content behind the RiveWidget will only receive hits if no listener was hit. + /// + Translucent = 1, + + + /// + /// All hits will pass through the RiveWidget, regardless of whether a Rive listener was hit. Rive listeners will still receive hits. + /// + [Obsolete("Transparent hit testing is deprecated, please use Translucent instead.")] + Transparent = 2, + + /// + /// No hit testing will be performed on the RiveWidget. + /// + None = 3 + } +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/HitTesting/HitTestBehavior.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/HitTesting/HitTestBehavior.cs.meta new file mode 100644 index 00000000..e88e0932 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/HitTesting/HitTestBehavior.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 70f512ba226594a9da0ac89681b3070a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/HitTesting/HitTestBehavior.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/HitTesting/IPanelInputProvider.cs b/Packages/app.rive.rive-unity/Runtime/Components/Public/HitTesting/IPanelInputProvider.cs new file mode 100644 index 00000000..68b23c2b --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/HitTesting/IPanelInputProvider.cs @@ -0,0 +1,42 @@ +using System; +using UnityEngine; + +namespace Rive.Components +{ + /// + /// Interface for providing input events to a RivePanel. + /// + public interface IPanelInputProvider + { + /// + /// Event fired when a pointer is pressed. The Vector2 parameter represents the normalized local point in the panel, + /// where coordinates are in the range [0,1] with (0,0) at bottom-left and (1,1) at top-right. + /// + event Action PointerPressed; + + /// + /// Event fired when a pointer is released. The Vector2 parameter represents the normalized local point in the panel, + /// where coordinates are in the range [0,1] with (0,0) at bottom-left and (1,1) at top-right. + /// + event Action PointerReleased; + + /// + /// Event fired when a pointer is moved. The Vector2 parameter represents the normalized local point in the panel, + /// where coordinates are in the range [0,1] with (0,0) at bottom-left and (1,1) at top-right. + /// + event Action PointerMoved; + + + /// + /// Event fired when a pointer exits the panel. The Vector2 parameter represents the normalized local point in the panel, + /// where coordinates are in the range [0,1] with (0,0) at bottom-left and (1,1) at top-right. + /// + event Action PointerExited; + + /// + /// Event fired when a pointer enters the panel. The Vector2 parameter represents the normalized local point in the panel, + /// where coordinates are in the range [0,1] with (0,0) at bottom-left and (1,1) at top-right. + /// + event Action PointerEntered; + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/HitTesting/IPanelInputProvider.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/HitTesting/IPanelInputProvider.cs.meta new file mode 100644 index 00000000..017f8e1b --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/HitTesting/IPanelInputProvider.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 7db5fdfddda6b4de1afcb3f3f7437ea1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/HitTesting/IPanelInputProvider.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/HitTesting/PanelPointerEvent.cs b/Packages/app.rive.rive-unity/Runtime/Components/Public/HitTesting/PanelPointerEvent.cs new file mode 100644 index 00000000..fa6578bd --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/HitTesting/PanelPointerEvent.cs @@ -0,0 +1,27 @@ +using UnityEngine; + +namespace Rive.Components +{ + /// + /// Pointer data delivered by input providers and propagated through the panel/widget pipeline. + /// + public readonly struct PanelPointerEvent + { + public readonly Vector2 Position; + public readonly int PointerId; + /// + /// Creates a new pointer event for panel input propagation. + /// + /// + /// The normalized point in panel space [0,1] where (0,0) is bottom-left and (1,1) is top-right. + /// + /// The unique id for the active pointer/touch. + public PanelPointerEvent(Vector2 position, int pointerId) + { + Position = position; + PointerId = pointerId; + } + } +} + + diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/HitTesting/PanelPointerEvent.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/HitTesting/PanelPointerEvent.cs.meta new file mode 100644 index 00000000..cc52688c --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/HitTesting/PanelPointerEvent.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: bfb74b0293d1b4c07922c10574a0abd4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/HitTesting/PanelPointerEvent.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/HitTesting/PanelRaycaster.cs b/Packages/app.rive.rive-unity/Runtime/Components/Public/HitTesting/PanelRaycaster.cs new file mode 100644 index 00000000..fb2578c5 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/HitTesting/PanelRaycaster.cs @@ -0,0 +1,140 @@ +using System.Collections.Generic; +using Rive.Utils; +using UnityEngine; + +namespace Rive.Components +{ + /// + /// Utility class for performing hit testing (raycasting) on RivePanels to detect which widgets are under a given point. + /// This is used to handle input events and determine which widgets should receive pointer interactions. + /// + public class PanelRaycaster + { + /// + /// Populates the raycastResults list with the widgets in a RivePanel that are hit by the given normalized local point in the panel. + /// + /// The RivePanel to check for hit widgets. + /// The normalized local point in the panel to check for hit widgets. The coordinates are in the range [0,1] where (0,0) is the bottom-left corner and (1,1) is the top-right corner. + /// The camera used by the event system or canvas + /// The list to populate with hit widgets. + public static void RaycastAll(IRivePanel rivePanel, Vector2 normalizedPointInPanel, List raycastResults) + { + RectTransform panelRectTransform = rivePanel.WidgetContainer; + if (panelRectTransform == null) + { + DebugLogger.Instance.LogError("Panel RectTransform is null."); + return; + } + + + + for (int i = rivePanel.Widgets.Count - 1; i >= 0; i--) + { + var widget = rivePanel.Widgets[i]; + if (widget == null || !widget.Enabled || widget.RenderObject == null || widget.HitTestBehavior == HitTestBehavior.None) + continue; + + Vector2 normalizedWidgetPoint; + bool isWithinWidgetBounds = TryGetNormalizedPointInWidget(rivePanel, normalizedPointInPanel, widget, out normalizedWidgetPoint); + + if (ProcessHitTestBehavior(widget, normalizedWidgetPoint, raycastResults, isWithinWidgetBounds)) + { + return; + } + + + } + } + + + /// + /// Processes the hit test behavior of a widget and adds it to the raycastResults list if it should be hit. + /// + /// The widget to process. + /// The normalized point in the widget's rect to check for a hit. The coordinates are in the range [0,1] where (0,0) is the bottom-left corner and (1,1) is the top-right corner. + /// The list to populate with hit widgets. + /// True if should should block other widgets from being hit, false otherwise. + private static bool ProcessHitTestBehavior(IRiveWidget widget, Vector2 normalizedPointInWidgetRect, List raycastResults, bool isWithinWidgetBounds) + { + switch (widget.HitTestBehavior) + { + case HitTestBehavior.Opaque: + + raycastResults.Add(widget); + // Block other widgets from being hit if the pointer is within the widget + return isWithinWidgetBounds; + case HitTestBehavior.Translucent: + bool foundHit = widget.HitTest(normalizedPointInWidgetRect); + + if (foundHit) + { + raycastResults.Add(widget); + return isWithinWidgetBounds; + } + break; +#pragma warning disable CS0618 // Transparent hit testing is deprecated but kept for backward compatibility + case HitTestBehavior.Transparent: + raycastResults.Add(widget); + // Continue checking other widgets + return false; +#pragma warning restore CS0618 + case HitTestBehavior.None: + // Do not add to raycastResults + return false; + } + + return false; + } + + /// + /// Tries to get the normalized local point in the widget from the normalized local point in the panel. + /// + /// The RivePanel that contains the widget. + /// The normalized local point in the panel. The coordinates are in the range [0,1] where (0,0) is the bottom-left corner and (1,1) is the top-right corner. + /// The widget to get the normalized local point in. + /// The normalized point in the widget's rect. + /// True if the normalized local point is within the widget's bounds, false otherwise. + public static bool TryGetNormalizedPointInWidget(IRivePanel rivePanel, Vector2 normalizedPointInPanel, IRiveWidget widget, out Vector2 normalizedWidgetPoint) + { + normalizedWidgetPoint = Vector2.zero; + + RectTransform panelRectTransform = rivePanel.WidgetContainer; + if (panelRectTransform == null) + { + DebugLogger.Instance.LogError("Panel RectTransform is null."); + return false; + } + + var panelRect = panelRectTransform.rect; + if (panelRect.width <= 0f || panelRect.height <= 0f) + { + return false; + } + + // We need to turn the normalized point (0..1) into a local point on the panel. + // Unity’s RectTransform coordinates are based on the pivot, not always the center. + // So when the pivot changes, the rect’s xMin/yMin shift too. If we ignore that, input gets offset. + // Using xMin/yMin + (normalized * size) lets us rebuild the original local point again, so everything stays lined up. + Vector2 panelLocalPoint = new Vector2( + panelRect.xMin + (normalizedPointInPanel.x * panelRect.width), + panelRect.yMin + (normalizedPointInPanel.y * panelRect.height) + ); + + Vector3 worldPoint = panelRectTransform.TransformPoint(panelLocalPoint); + + Vector3 widgetLocalPoint = widget.RectTransform.InverseTransformPoint(worldPoint); + + normalizedWidgetPoint = new Vector2( + (widgetLocalPoint.x - widget.RectTransform.rect.xMin) / widget.RectTransform.rect.width, + (widgetLocalPoint.y - widget.RectTransform.rect.yMin) / widget.RectTransform.rect.height + ); + + if (widget.RectTransform.rect.Contains(widgetLocalPoint)) + { + return true; + } + + return false; + } + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/HitTesting/PanelRaycaster.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/HitTesting/PanelRaycaster.cs.meta new file mode 100644 index 00000000..92383ebf --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/HitTesting/PanelRaycaster.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: cc94d7864e5db458e990e4d9fdd933d3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/HitTesting/PanelRaycaster.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/PanelRenderers.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/PanelRenderers.meta new file mode 100644 index 00000000..a1d44de1 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/PanelRenderers.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 51375317c51824332852b94a7ec337c8 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/PanelRenderers/PanelRenderer.cs b/Packages/app.rive.rive-unity/Runtime/Components/Public/PanelRenderers/PanelRenderer.cs new file mode 100644 index 00000000..0cae0286 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/PanelRenderers/PanelRenderer.cs @@ -0,0 +1,139 @@ +using Rive.EditorTools; +using Rive.Utils; +using UnityEngine; + +namespace Rive.Components +{ + /// + /// The PointerInputMode determines whether the panel will receive pointer input events. + /// + public enum PointerInputMode + { + /// + /// The panel will receive pointer input events. + /// + EnablePointerInput = 0, + + /// + /// The panel will not receive pointer input events. + /// + DisablePointerInput = 1 + } + + [DisallowMultipleComponent] + public abstract class PanelRenderer : MonoBehaviour + { + +#if UNITY_EDITOR + [OnValueChanged(nameof(HandlePointerInputModeChanged))] +#endif + [Tooltip("Determines whether the panel will receive pointer input events from this renderer.")] + [SerializeField] private PointerInputMode m_pointerInputMode = PointerInputMode.EnablePointerInput; + + + + /// + /// The RivePanel that this renderer is associated with. + /// + public abstract IRivePanel RivePanel { get; internal set; } + + /// + /// The PointerInputMode determines whether the panel render will pass pointer input events to the RivePanel. + /// + public PointerInputMode PointerInputMode + { + get => m_pointerInputMode; set + { + if (m_pointerInputMode == value) { return; } + m_pointerInputMode = value; HandlePointerInputModeChanged(); + } + } + + + protected void SubscribeToPanelEvents() + { + if (RivePanel == null) + { + DebugLogger.Instance.LogWarning($"No {nameof(RivePanel)} component found for this {nameof(PanelRenderer)} - {gameObject.name}"); + return; + } + + RivePanel.OnRenderingStateChanged += OnRenderingStateChanged; + RivePanel.OnRenderTargetUpdated += HandleRenderTargetUpdated; + } + + protected void UnsubscribeFromPanelEvents() + { + if (RivePanel == null) + { + return; + } + RivePanel.OnRenderingStateChanged -= OnRenderingStateChanged; + RivePanel.OnRenderTargetUpdated -= HandleRenderTargetUpdated; + } + + + + protected virtual void OnEnable() + { + + if (RivePanel == null) + { + return; + } + + + + if (RivePanel.IsRendering) + { + UpdateVisualTarget(); + } + SubscribeToPanelEvents(); + } + + + + protected virtual void OnDisable() + { + if (RivePanel == null) + { + return; + } + UnsubscribeFromPanelEvents(); + } + + protected void HandleRenderTargetUpdated() + { + UpdateVisualTarget(); + + } + + private void OnRenderingStateChanged() + { + UpdateVisualTarget(); + } + + + /// + /// Use this method to reflect the Rive visual on the target where the Rive graphic is being displayed. This is called when the render target is updated or when the panel detects it might need to update the targets using the render texture. + /// + protected abstract void UpdateVisualTarget(); + + + protected virtual void HandlePointerInputModeChanged() + { + + } + + + + /// + /// This method is called when the script is loaded or a value is changed in the inspector (Called in the editor only). + /// + protected virtual void OnValidate() + { + + + } + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/PanelRenderers/PanelRenderer.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/PanelRenderers/PanelRenderer.cs.meta new file mode 100644 index 00000000..9a79cb29 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/PanelRenderers/PanelRenderer.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 86bfe1bae01fc421390c0d36814b3a74 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/PanelRenderers/PanelRenderer.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/PanelRenderers/RiveCanvasRenderer.cs b/Packages/app.rive.rive-unity/Runtime/Components/Public/PanelRenderers/RiveCanvasRenderer.cs new file mode 100644 index 00000000..a6c8184c --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/PanelRenderers/RiveCanvasRenderer.cs @@ -0,0 +1,334 @@ +using Rive.EditorTools; +using Rive.Utils; +using Rive; +using UnityEngine; + +namespace Rive.Components +{ +#if UNITY_EDITOR + [HelpURL(InspectorDocLinks.RiveCanvasRenderer)] +#endif + [AddComponentMenu("Rive/Rive Canvas Renderer")] + [HideComponents(hideFlags: HideFlags.HideInInspector, typeof(CanvasRendererRawImage), typeof(CanvasPanelInputProvider))] + [RequireComponent(typeof(CanvasRendererRawImage), typeof(IRivePanel))] + public class RiveCanvasRenderer : PanelRenderer + { + [Tooltip("The RiveRawImage to display the Rive content.")] + [HideInInspector] + [SerializeField] + private CanvasRendererRawImage m_displayImage; + + // We hide the RivePanel field because we want to use the RivePanel on the GameObject that this component is attached to. + [HideInInspector] + [Tooltip("The RivePanel to display")] + [SerializeField] private RivePanel m_initialRivePanel; + + [Tooltip("A custom UI material to use when rendering the Rive graphic.")] + [SerializeField] private Material m_customMaterial; + + [Tooltip("Whether to match the canvas resolution to the RivePanel's resolution. \n\nThis is useful for keeping the Rive graphic crisp when using a Canvas Scaler. By default, the RivePanel resolution is defined by it's rect transform's width and height. Setting this to true will cause the RivePanel to be rendered at a higher resolution than the panel's rect transform's size if needed.\n\nThis feature is currently only supported when the RivePanel uses the SimpleRenderTargetStrategy, which is the default strategy used if none is provided.")] + [SerializeField] private bool m_matchCanvasResolution = false; + + + private IRivePanel m_rivePanel; + + internal CanvasRendererRawImage DisplayImage => m_displayImage; + + [HideInInspector] + [SerializeField] private CanvasPanelInputProvider m_inputProvider; + + public Canvas Canvas => DisplayImage == null ? null : DisplayImage.canvas; + + public RectTransform RectTransform => DisplayImage == null ? null : DisplayImage.rectTransform; + + public override IRivePanel RivePanel { get => m_rivePanel; internal set => m_rivePanel = value; } + + /// + /// The custom material to use when rendering the Rive graphic. + /// + public Material CustomMaterial + { + get => m_customMaterial; + set + { + m_customMaterial = value; + UpdateCustomMaterial(); + } + } + + public bool MatchCanvasResolution + { + get => m_matchCanvasResolution; + set + { + if (m_matchCanvasResolution != value) + { + m_matchCanvasResolution = value; + AttachCanvasProviders(RivePanel); + + RivePanel rPanel = RivePanel as RivePanel; + if (rPanel != null) + { + rPanel.SetDirty(); // Force a redraw to apply the new resolution. + } + } + } + } + + protected override void OnEnable() + { + Setup(); + base.OnEnable(); + + + if (m_matchCanvasResolution) AttachCanvasProviders(RivePanel); + + if (m_inputProvider != null && RivePanel != null) + { + RivePanel.RegisterInputProvider(m_inputProvider); + + } + } + + protected override void OnDisable() + { + base.OnDisable(); + + if (m_inputProvider != null && RivePanel != null) + { + RivePanel.UnregisterInputProvider(m_inputProvider); + + } + } + + /// + /// Supersampling multiplier for the RenderTexture only. + /// + private float m_renderScale = 1f; + + + /// + /// Attach providers that the strategy can call to (1) size the RT and (2) pick draw scale. + /// This keeps strategies/panels canvas-agnostic and lets other renderers (UITK, material) + /// provide their own sizing rules or none at all. + /// + /// + private void AttachCanvasProviders(IRivePanel panel) + { + var concretePanel = panel as RivePanel; + if (concretePanel == null) return; + + var strategy = concretePanel.RenderTargetStrategy as RenderTargetStrategy; + if (strategy == null) return; + + if (!m_matchCanvasResolution) + { + // Explicitly clear to legacy behavior + strategy.ExternalPixelSizeProvider = null; + strategy.ExternalDrawScaleProvider = null; + return; + } + + strategy.ExternalPixelSizeProvider = ComputeCanvasPixelSize; + strategy.ExternalDrawScaleProvider = ComputeCanvasDrawScale; + } + + + /// + /// Computes the pixel size of the canvas. Determines the size of the render texture based on the canvas scale factor and the local scale of the widget container. + /// We do this because the Canvas Scaler (especially when set to "Scale With Screen Size") changes how many pixels each UI unit occupies on screen. Allocating the RT at that pixel size keeps Rive crisp. + /// + /// The panel to compute the pixel size for. + /// The pixel size of the canvas. + private Vector2Int ComputeCanvasPixelSize(IRivePanel p) + { + var rt = p.WidgetContainer; + var canvas = DisplayImage != null ? DisplayImage.canvas : null; + if (rt == null || canvas == null) return new Vector2Int(1, 1); + + float canvasScale = canvas.scaleFactor; + + // Include local UI scale so “manually scaled” panels (e.g. 1080×2340 at 0.3333) resolve to the same on-screen pixels + float uiW = rt.rect.width * Mathf.Abs(rt.localScale.x); + float uiH = rt.rect.height * Mathf.Abs(rt.localScale.y); + + int w = Mathf.Max(1, Mathf.CeilToInt(uiW * canvasScale * m_renderScale)); + int h = Mathf.Max(1, Mathf.CeilToInt(uiH * canvasScale * m_renderScale)); + return new Vector2Int(w, h); + } + + + /// + /// Computes the draw scale of the canvas. Used to ensure the graphics are drawn at the correct scale and position within the render texture. + /// + /// The panel to compute the draw scale for. + /// The draw scale of the canvas. + private Vector2 ComputeCanvasDrawScale(IRivePanel p) + { + var rt = p.WidgetContainer; + var canvas = DisplayImage != null ? DisplayImage.canvas : null; + if (rt == null || canvas == null) return Vector2.one; + + float canvasScale = canvas.scaleFactor; + + float sx = canvasScale * Mathf.Abs(rt.localScale.x); + float sy = canvasScale * Mathf.Abs(rt.localScale.y); + return new Vector2(sx, sy); + } + + private void Setup() + { + if (m_rivePanel == null) + { + m_rivePanel = m_initialRivePanel; + + } + + if (m_rivePanel == null) + { + m_rivePanel = GetComponent(); + + } + if (m_displayImage == null) + { + if (!TryGetComponent(out m_displayImage)) + { + m_displayImage = gameObject.AddComponent(); + } + } + + // We need to make sure the RivePanel's RawImage is a raycast target, otherwise we won't get any pointer input. + if (!m_displayImage.raycastTarget) + { + m_displayImage.raycastTarget = true; + + } + + if (m_inputProvider == null && !TryGetComponent(out m_inputProvider)) + { + m_inputProvider = gameObject.AddComponent(); + } + + + + + // Initialize the input mode, in case it was not set. + HandlePointerInputModeChanged(); + + if (m_rivePanel == null) + { + DebugLogger.Instance.LogWarning($"No {nameof(RivePanel)} component found for this {nameof(RiveCanvasRenderer)} - {gameObject.name}"); + } + } + + + + private void LogInputErrorWarningsIfNeeded() + { + if (PointerInputMode == PointerInputMode.DisablePointerInput) + { + return; + } + // If there's no event system in the scene, we log a warning. + if (UnityEngine.EventSystems.EventSystem.current == null) + { + DebugLogger.Instance.LogWarning($"No EventSystem found in the scene. Please add an EventSystem to the scene to receive pointer input events. If you don't want to receive pointer input events, set the {nameof(PointerInputMode)} to {PointerInputMode.DisablePointerInput}."); + } + + // If there's no GraphicRaycaster in the scene, we log a warning. + if (DisplayImage != null && !DisplayImage.canvas.TryGetComponent(out _)) + { + DebugLogger.Instance.LogWarning($"No GraphicRaycaster found in the scene. Please add a GraphicRaycaster to the scene to receive pointer input events. If you don't want to receive pointer input events, set the {nameof(PointerInputMode)} to {PointerInputMode.DisablePointerInput}."); + } + } + + private void Start() + { + LogInputErrorWarningsIfNeeded(); + + UpdateCustomMaterial(); + + } + + private void UpdateCustomMaterial() + { + if (DisplayImage == null) + { + return; + } + + Material materialToApply = m_customMaterial; + + if (materialToApply == null && Application.isPlaying) + { + materialToApply = TextureHelper.GammaToLinearUIMaterial; + } + + DisplayImage.material = materialToApply; + } + + + protected override void UpdateVisualTarget() + { + if (RivePanel == null) + { + return; + } + var renderTexture = RivePanel.RenderTexture; + if (renderTexture == null) + { + return; + } + + m_displayImage.texture = renderTexture; + + Vector2 offset = RivePanel.OffsetInRenderTexture; + Vector2 scale = RivePanel.ScaleInRenderTexture; + + + m_displayImage.uvRect = new Rect(offset, scale); + } + + + + protected override void OnValidate() + { + base.OnValidate(); + + if (m_initialRivePanel == null) + { + m_initialRivePanel = GetComponent(); + } + + if (m_displayImage == null) + { + m_displayImage = GetComponent(); + } + + if (m_inputProvider == null) + { + m_inputProvider = GetComponent(); + } + } + + + protected override void HandlePointerInputModeChanged() + { + if (m_displayImage == null) + { + return; + } + + if (PointerInputMode == PointerInputMode.EnablePointerInput && !m_displayImage.raycastTarget) + { + m_displayImage.raycastTarget = true; + } + else if (PointerInputMode == PointerInputMode.DisablePointerInput && m_displayImage.raycastTarget) + { + m_displayImage.raycastTarget = false; + } + } + + + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/PanelRenderers/RiveCanvasRenderer.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/PanelRenderers/RiveCanvasRenderer.cs.meta new file mode 100644 index 00000000..fa8eec9c --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/PanelRenderers/RiveCanvasRenderer.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: d4b4a2d64b69b4c0bbdc2f768c08b799 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: f377684eb5623462e80ebba320696f74, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/PanelRenderers/RiveCanvasRenderer.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/PanelRenderers/RiveTextureRenderer.cs b/Packages/app.rive.rive-unity/Runtime/Components/Public/PanelRenderers/RiveTextureRenderer.cs new file mode 100644 index 00000000..5a53b7dd --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/PanelRenderers/RiveTextureRenderer.cs @@ -0,0 +1,532 @@ +using System; +using System.Collections.Generic; +using Rive.EditorTools; +using Rive.Utils; +using UnityEngine; +using UnityEngine.Serialization; + +namespace Rive.Components +{ + /// + /// Renders a RivePanel to a texture. This component should be attached to a GameObject that has a Renderer component. + /// +#if UNITY_EDITOR + [HelpURL(InspectorDocLinks.RiveTextureRenderer)] +#endif + [AddComponentMenu("Rive/Rive Texture Renderer")] +#if UNITY_EDITOR + [InspectorSection(InspectorSections.RendererSettings, "Renderer Settings", startExpanded: true)] + [HideComponents(hideFlags: HideFlags.HideInInspector, typeof(TexturePanelInputProvider), typeof(PanelVisibilityOptimizer))] +#endif + public class RiveTextureRenderer : PanelRenderer + { + private static class InspectorSections + { + + public const string RendererSettings = "RendererSettings"; + } + + public enum TextureAssignmentMode + { + /// + /// Sets the texture to the main texture of the material. + /// + MainTexture = 0, + + /// + /// Sets the texture to the specified material properties. + /// + TextureProperties = 1 + } + + [Tooltip("The RivePanel to display")] + [InspectorField(displayName: "Rive Panel")] + [SerializeField] private RivePanel m_initialRivePanel; + + private IRivePanel m_rivePanel; + + [InspectorField(InspectorSections.RendererSettings, displayName: "Mesh Renderer")] + [Tooltip("The MeshRenderer that will display the Rive graphic.")] + [SerializeField] private UnityEngine.Renderer m_objectRenderer; + + [InspectorField(InspectorSections.RendererSettings)] + [Tooltip("Determines how the texture is set on the material. If set to MainTexture, the texture is set to the main texture of the material. If set to TextureProperties, the texture is set to the specified material properties.")] + [SerializeField] private TextureAssignmentMode m_textureAssignmentMode = TextureAssignmentMode.MainTexture; + + + [Tooltip("Determines the RivePanel will automatically stop rendering when the mesh is not visible to the camera.")] + [SerializeField] private VisibilityOptimizationMode m_visibilityOptimization = VisibilityOptimizationMode.AlwaysRender; + + private Material[] m_materials; + + + private PanelVisibilityOptimizer m_visibilityOptimizer; + + private TexturePanelInputProvider m_inputProvider; + + + + /// + /// Inherits from SerializedDictionary to store the material property names. This is needed because Unity does not properly serialize Lists within Lists in the SerializedDictionary. + /// + [System.Serializable] + internal class SerializedDictionary_Material_ListString : SerializedDictionary + { + + } + // We use a custom editor to display the material property names in a more user-friendly way + + // We use a holder class to store the list of property names for each material because Unity does not properly serialize Lists within Lists in the SerializedDictionary. + [System.Serializable] + internal class PropertyNameListHolder + { + [SerializeField] + List m_propertyNames = new List(); + + + private List m_propertyIDs; + public List PropertyNames => m_propertyNames; + + public List PropertyIDs + { + get + { + if (m_propertyIDs == null || m_propertyIDs.Count != m_propertyNames.Count) + { + UpdatePropertyIDs(); + } + return m_propertyIDs; + } + } + + public void UpdatePropertyIDs() + { + if (m_propertyIDs == null) + { + m_propertyIDs = new List(); + } + m_propertyIDs.Clear(); + for (int i = 0; i < m_propertyNames.Count; i++) + { + m_propertyIDs.Add(Shader.PropertyToID(m_propertyNames[i])); + } + } + +#if UNITY_EDITOR + public static string BindingPath_PropertyNames => nameof(m_propertyNames); +#endif + } + + +#if UNITY_EDITOR + [ShowIf(nameof(ShouldShowMaterialPropertyNames))] + [InspectorField(InspectorSections.RendererSettings)] + [Tooltip("The material properties to set the texture to.")] +#if UNITY_6000_3_OR_NEWER + [MaterialProperties(nameof(GetRendererMaterials), UnityEngine.Rendering.ShaderPropertyType.Texture)] +#else + [MaterialProperties(nameof(GetRendererMaterials), UnityEditor.ShaderUtil.ShaderPropertyType.TexEnv)] +#endif +#endif + [SerializeField] + private SerializedDictionary_Material_ListString m_materialPropertyNameData = new SerializedDictionary_Material_ListString(); + + +#if UNITY_EDITOR + + private Material[] GetRendererMaterials() + { + if (m_objectRenderer == null) + { + return new Material[0]; + } + + return m_objectRenderer.sharedMaterials; + } + + private bool ShouldShowMaterialPropertyNames => m_textureAssignmentMode == TextureAssignmentMode.TextureProperties; + + + protected override void OnValidate() + { + base.OnValidate(); + + if (m_objectRenderer == null || !ReferenceEquals(m_objectRenderer.gameObject, this.gameObject)) + { + m_objectRenderer = GetComponent(); + } + } + + +#endif + + // Perform one-time conversion of default pipeline materials when the component is first added or Reset is invoked. + void Reset() + { +#if UNITY_EDITOR + + if (m_objectRenderer == null) + { + m_objectRenderer = GetComponent(); + + if (m_objectRenderer == null) + { + return; + } + } + + MaterialConversionUtility.EnsureRiveMaterialsOnRenderer(m_objectRenderer); +#endif + } + + + + + /// + /// Returns the Renderer component that is used to render the Rive graphic. + /// + public UnityEngine.Renderer Renderer => m_objectRenderer; + + /// + /// The mode of setting the material texture. Use this to determine how the texture is set on the material. + /// + public TextureAssignmentMode MaterialTextureAssignmentMode + { + get => m_textureAssignmentMode; + set + { + m_textureAssignmentMode = value; + } + } + + + /// + /// Determines if the RivePanel should stop rendering when the mesh is not visible to the camera. + /// + public VisibilityOptimizationMode VisibilityOptimization + { + get + { + if (m_visibilityOptimizer != null) + { + return m_visibilityOptimizer.VisibilityMode; + } + + return m_visibilityOptimization; + } + set + { + m_visibilityOptimization = value; + if (m_visibilityOptimizer != null) + { + m_visibilityOptimizer.VisibilityMode = value; + } + } + } + + /// + /// Gets the number of materials that have property names assigned. + /// + public int MaterialPropertyCount => m_materialPropertyNameData.Count; + + + public override IRivePanel RivePanel + { + get + { + // Outside of play mode, we want to reference the serialized field. + if (!Application.isPlaying) + { + return m_initialRivePanel; + } + return m_rivePanel; + } + internal set + { + + m_initialRivePanel = value as RivePanel; + } + } + + public Action OnPanelChanged; + + /// + /// Sets the RivePanel that this renderer will render. + /// + /// + public void SetPanel(IRivePanel panel) + { + if (ReferenceEquals(m_rivePanel, panel)) + { + return; + } + + if (m_rivePanel != null) + { + m_rivePanel.UnregisterInputProvider(m_inputProvider); + + UnsubscribeFromPanelEvents(); + } + m_rivePanel = panel; + + if (m_rivePanel != null) + { + if (m_inputProvider != null) + { + m_rivePanel.RegisterInputProvider(m_inputProvider); + + } + SubscribeToPanelEvents(); + } + + UpdateVisualTarget(); + + OnPanelChanged?.Invoke(); + } + + protected override void OnEnable() + { + Setup(); + base.OnEnable(); + + if (m_rivePanel != null && m_inputProvider != null) + { + RivePanel.RegisterInputProvider(m_inputProvider); + } + } + + protected override void OnDisable() + { + base.OnDisable(); + + if (m_rivePanel != null && m_inputProvider != null) + { + m_rivePanel.UnregisterInputProvider(m_inputProvider); + } + + } + + private void LogInputErrorWarningsIfNeeded() + { + if (PointerInputMode == PointerInputMode.DisablePointerInput) + { + return; + } + // If there's no event system in the scene, we log a warning. + if (UnityEngine.EventSystems.EventSystem.current == null) + { + DebugLogger.Instance.LogWarning($"No EventSystem found in the scene. Please add an {nameof(UnityEngine.EventSystems.EventSystem)} to the scene to receive pointer input events."); + } + +#if UNITY_EDITOR + var camera = Camera.main; + if (camera != null && camera.gameObject.GetComponent() == null) + { + DebugLogger.Instance.LogWarning($"No {nameof(UnityEngine.EventSystems.PhysicsRaycaster)} found on the main camera. Please add a {nameof(UnityEngine.EventSystems.PhysicsRaycaster)} component to the main camera to receive pointer input events. Or set the {nameof(PointerInputMode)} to {nameof(PointerInputMode.DisablePointerInput)}."); + } + +#endif + + } + + private void Start() + { + LogInputErrorWarningsIfNeeded(); + } + + + + private void SpawnVisibilityOptimizerIfNeeded() + { + if (m_objectRenderer == null || m_visibilityOptimizer != null) + { + return; + } + + + + if (!m_objectRenderer.TryGetComponent(out m_visibilityOptimizer)) + { + // We add the component to the GameObject that has the Renderer component because we can't be certain that it's the same GameObject as the RivePanel. + m_visibilityOptimizer = m_objectRenderer.gameObject.AddComponent(); + } + + m_visibilityOptimizer.VisibilityMode = m_visibilityOptimization; + } + + public IEnumerable GetMaterialPropertyNames(int materialIndex) + { + return m_materialPropertyNameData.TryGetValue(materialIndex, out var holder) + ? holder.PropertyNames + : Array.Empty(); + } + + public void SetMaterialPropertyNames(int materialIndex, IEnumerable propertyNames) + { + if (!m_materialPropertyNameData.TryGetValue(materialIndex, out var holder)) + { + holder = new PropertyNameListHolder(); + m_materialPropertyNameData[materialIndex] = holder; + } + holder.PropertyNames.Clear(); + holder.PropertyNames.AddRange(propertyNames); + + // Force recreation of property IDs on next use + holder.UpdatePropertyIDs(); + } + + public void ClearMaterialPropertyNames() + { + m_materialPropertyNameData.Clear(); + } + + + + + /// + /// Checks if a material index has any property names assigned. + /// + public bool HasPropertyNames(int materialIndex) => m_materialPropertyNameData.ContainsKey(materialIndex); + + + private void SetMaterialTexture(RenderTexture texture, Vector2 offset, Vector2 scale) + { + if (m_objectRenderer == null) + { + return; + } + // We loop through all the material properties and set the texture to all of them. + // We do this because the material might have multiple textures that we want to update. + // We also need to account for there being multiple materials on the renderer. + + for (int i = 0; i < m_materials.Length; i++) + { + var material = m_materials[i]; + if (material == null) + { + continue; + } + + if (m_textureAssignmentMode == TextureAssignmentMode.MainTexture) + { + material.mainTexture = texture; + material.mainTextureOffset = offset; + material.mainTextureScale = scale; + } + else if (m_textureAssignmentMode == TextureAssignmentMode.TextureProperties) + { + if (m_materialPropertyNameData.TryGetValue(i, out var holder)) + { + var propertyIDs = holder.PropertyIDs; + for (int g = 0; g < propertyIDs.Count; g++) + { + material.SetTexture(propertyIDs[g], texture); + material.SetTextureOffset(propertyIDs[g], offset); + material.SetTextureScale(propertyIDs[g], scale); + } + } + } + } + } + + private void Setup() + { + if (m_objectRenderer == null) + { + m_objectRenderer = GetComponent(); + } + + if (m_objectRenderer == null) + { + DebugLogger.Instance.Log($"No {nameof(UnityEngine.Renderer)} found. Please assign a renderer to the {nameof(RiveTextureRenderer)}."); + return; + } + + if (m_rivePanel == null) + { + m_rivePanel = m_initialRivePanel; + } + + // Cache the materials so we can set the texture on them later + m_materials = m_objectRenderer.materials; + + + SpawnVisibilityOptimizerIfNeeded(); + + SpawnInputProviderIfNeeded(); + + + } + + /// + /// Spawns the input provider on the game object that has the MeshRenderer and collider. The input provider receives IPointer events from the Unity Event System and forwards them to the RiveWidgets, so it needs to be attached to the same GameObject that receives the events, which is the Render game object with the collider. + /// + private void SpawnInputProviderIfNeeded() + { + if (m_objectRenderer == null) + { + return; + } + + if (m_inputProvider != null) + { + return; + } + + if (!m_objectRenderer.gameObject.TryGetComponent(out m_inputProvider)) + { + m_inputProvider = m_objectRenderer.gameObject.AddComponent(); + } + + } + + + protected override void UpdateVisualTarget() + { + var renderTexture = RivePanel.RenderTexture; + + + Vector2 offset = RivePanel.OffsetInRenderTexture; + Vector2 scale = RivePanel.ScaleInRenderTexture; + + SetMaterialTexture(renderTexture, offset, scale); + + } + + /// + /// Refreshes the materials on the renderer. This method should be called after changing the materials on the renderer. + /// + public void RefreshMaterials() + { + m_materials = m_objectRenderer.materials; + + UpdateVisualTarget(); + } + + void OnDestroy() + { + + if (m_materials == null) + { + return; + } + // Destroy the materials that we instantiated. + for (int i = m_materials.Length - 1; i >= 0; i--) + { + var material = m_materials[i]; + + if (material == null) + { + continue; + } + Destroy(material); + } + + + + } + + + + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/PanelRenderers/RiveTextureRenderer.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/PanelRenderers/RiveTextureRenderer.cs.meta new file mode 100644 index 00000000..31fd5109 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/PanelRenderers/RiveTextureRenderer.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 6fef7631bb6fb4a2ebebe7bfce6ea442 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: f377684eb5623462e80ebba320696f74, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/PanelRenderers/RiveTextureRenderer.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/PanelRenderers/VisibilityOptimizationMode.cs b/Packages/app.rive.rive-unity/Runtime/Components/Public/PanelRenderers/VisibilityOptimizationMode.cs new file mode 100644 index 00000000..a7d1913e --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/PanelRenderers/VisibilityOptimizationMode.cs @@ -0,0 +1,18 @@ +namespace Rive.Components +{ + /// + /// Determines how the visibility optimization should behave + /// + public enum VisibilityOptimizationMode + { + /// + /// Only renders when the gameobject is rendering + /// + RenderWhenVisible = 0, + + /// + /// Always renders regardless of gameobject's visibility + /// + AlwaysRender = 1 + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/PanelRenderers/VisibilityOptimizationMode.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/PanelRenderers/VisibilityOptimizationMode.cs.meta new file mode 100644 index 00000000..185d8948 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/PanelRenderers/VisibilityOptimizationMode.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 1c5802ebe74ae402c96d5bf58ce00d71 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/PanelRenderers/VisibilityOptimizationMode.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/Panels.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/Panels.meta new file mode 100644 index 00000000..585aaa67 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/Panels.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b3db1d726c1be4ea7be4e02876ad6803 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/Panels/IRivePanel.cs b/Packages/app.rive.rive-unity/Runtime/Components/Public/Panels/IRivePanel.cs new file mode 100644 index 00000000..e22cda33 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/Panels/IRivePanel.cs @@ -0,0 +1,105 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace Rive.Components +{ + /// + /// Represents a panel that can be rendered by a Rive Renderer. + /// + public interface IRivePanel + { + /// + /// The RectTransform of the panel. It holds the widgets that the panel manages. + /// + RectTransform WidgetContainer { get; } + + /// + /// A list of widgets that the panel manages. The list is sorted in the order that the widgets should be rendered in. For example, the back-most widget should be at index 0 and the front-most widget should be at the highest index. + /// + IReadOnlyList Widgets { get; } + + /// + /// Whether the panel is currently rendering to a render target. + /// + bool IsRendering { get; } + + /// + /// Whether the panel is enabled and its GameObject is active in the hierarchy. + /// + bool Enabled { get; } + + + /// + /// The RenderTexture that this panel renders to. + /// + RenderTexture RenderTexture { get; } + + /// + /// The scale of the panel within its RenderTexture. + /// + Vector2 ScaleInRenderTexture { get; } + + /// + /// The offset of the panel within its RenderTexture. + /// + Vector2 OffsetInRenderTexture { get; } + + /// + /// Controls how often this panel's render target should be updated. + /// + DrawOptimizationOptions DrawOptimization { get; } + + + + /// + /// Starts rendering the panel to its Render Target. + /// + /// True if the panel was successfully started rendering, false otherwise. + bool StartRendering(); + + /// + /// Stops rendering the panel to its Render Target. + /// + /// True if the panel was successfully stopped rendering, false otherwise. + bool StopRendering(); + + /// + /// Registers an input provider for this panel. + /// + /// The input provider to register. + public void RegisterInputProvider(IPanelInputProvider inputProvider); + + /// + /// Unregisters an input provider from this panel. + /// + /// The input provider to unregister. + public void UnregisterInputProvider(IPanelInputProvider inputProvider); + + /// + /// Event that is triggered when a widget is added to the panel. + /// + event Action OnWidgetAdded; + + /// + /// Event that is triggered when a widget is removed from the panel. + /// + event Action OnWidgetRemoved; + + /// + /// Event that is triggered when the panel's rendering state changes (starts/stops rendering). + /// + event Action OnRenderingStateChanged; + + /// + /// Event that is triggered when the panel's render target strategy changes. + /// + event Action OnRenderTargetStrategyChanged; + + /// + /// Event that is triggered when the panel's render target is updated. + /// + event Action OnRenderTargetUpdated; + + } +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/Panels/IRivePanel.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/Panels/IRivePanel.cs.meta new file mode 100644 index 00000000..e2151000 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/Panels/IRivePanel.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 24b997c8d927740068e1eb5905b2e928 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/Panels/IRivePanel.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/Panels/RivePanel.cs b/Packages/app.rive.rive-unity/Runtime/Components/Public/Panels/RivePanel.cs new file mode 100644 index 00000000..f49453d2 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/Panels/RivePanel.cs @@ -0,0 +1,1057 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Rive.EditorTools; +using Rive.Utils; +using UnityEngine; +using UnityEngine.Pool; + +namespace Rive.Components +{ + + /// + /// RivePanels are responsible for displaying and updating a collection of RiveWidgets. The panel represents a viewport within which the widgets are displayed and rendered to a single Render Target. + /// +#if UNITY_EDITOR + [HelpURL(InspectorDocLinks.RivePanel)] +#endif + [AddComponentMenu("Rive/Rive Panel")] + [DisallowMultipleComponent] + [InspectorSection(RivePanelInspectorSections.Advanced, "Advanced", order: 1, style: SectionStyle.Foldout)] + [InspectorSection(RivePanelInspectorSections.Events, "Events", order: 2, style: SectionStyle.Foldout)] + +#if UNITY_EDITOR + // Since it is a required component, we only want to hide the PanelContextPreviewManager component. We still want it to be serialized so that it isn't constantly recreated when entering and exiting play mode + [HideComponents(hideFlags: HideFlags.HideInInspector, typeof(PanelContextPreviewManager))] + [RequireComponent(typeof(PanelContextPreviewManager))] +#endif + [RequireComponent(typeof(RectTransform))] + public sealed class RivePanel : MonoBehaviour, IRivePanel + { + /// + /// Controls whether the panel processes multiple pointers concurrently or collapses all input to a single pointer (legacy behavior). + /// + public enum MultiTouchSupport + { + Disabled = 0, + Enabled = 1 + } + /// + /// The mode for updating the panel. + /// + public enum PanelUpdateMode + { + /// + /// The panel and its widgets will be tick automatically. + /// + Auto = 0, + + /// + /// The panel and its widgets will tick only when explicitly called. + /// + Manual = 1 + } + + private static class RivePanelInspectorSections + { + + public const string Events = "events"; + public const string Advanced = "advanced"; + } + + private class WidgetMetadata + { + public Action SiblingIndexChangedAction; + public Action ParentChangedAction; + + public void Reset() + { + SiblingIndexChangedAction = null; + ParentChangedAction = null; + + } + } + + Comparer m_widgetComparer; + + private IRenderTargetStrategy m_renderTargetStrategy; + +#if UNITY_EDITOR + [InspectorField(RivePanelInspectorSections.Advanced, "Custom Render Target Strategy", helpUrl: InspectorDocLinks.RenderTargetStrategies)] +#endif + [Tooltip("The RenderTargetStrategy to use for rendering the panel. By default, each panel renders to a single RenderTexture that matches the panel's RectTransform dimensions. However, you can pass in a different strategy to render to a pool of RenderTextures or to a single RenderTexture that is shared between multiple panels.")] + [SerializeField] private RenderTargetStrategy m_customRenderTargetStrategy; + + [Tooltip("Determines how the panel will update its widgets. In Auto mode, the panel will tick its widgets every frame. In Manual mode, the panel will only update and advance its widgets when you explictly call the panel's Tick() method. This is useful if you want to control how often the panel updates its widgets.")] + [SerializeField] private PanelUpdateMode m_updateMode = PanelUpdateMode.Auto; + + [InspectorField(RivePanelInspectorSections.Advanced)] + [Tooltip("Determines whether the panel will be rendered in the Edit mode.")] + [SerializeField] private bool m_disableEditorPreview = false; + + [InspectorField(RivePanelInspectorSections.Advanced)] + [Tooltip("Controls how often this panel's render target should be updated.\n\n- Always Draw: redraw every frame.\n- Draw When Changed: redraw only when the underlying artboards report changes, or when Unity triggers a redraw (layout/size/etc).")] + [SerializeField] private DrawOptimizationOptions m_drawOptimization = DrawOptimizationOptions.DrawWhenChanged; + + [InspectorField(RivePanelInspectorSections.Advanced, "Multitouch Support")] + [Tooltip("When Disabled, the panel collapses all input to a single pointer for legacy behavior. When Enabled, multiple pointers are tracked independently.")] + [SerializeField] private MultiTouchSupport m_multiTouchSupport = MultiTouchSupport.Enabled; + + + private List m_sortedWidgets = new List(); + private Dictionary widgetMetadata = new Dictionary(); + + + private List m_panelInputProviders = new List(); + + + private List m_raycastResults = new List(); + private Coroutine m_sortWidgetsCoroutine; + + private readonly Action m_pointerDownHandler = (widget, localPoint, evt) => widget.OnPointerDown(localPoint, evt.PointerId); + private readonly Action m_pointerUpHandler = (widget, localPoint, evt) => widget.OnPointerUp(localPoint, evt.PointerId); + private readonly Action m_pointerMoveHandler = (widget, localPoint, evt) => widget.OnPointerMove(localPoint, evt.PointerId); + + private readonly Action m_pointerExitHandler = (widget, localPoint, evt) => widget.OnPointerExit(localPoint, evt.PointerId); + + private readonly Action m_pointerEnterHandler = (widget, localPoint, evt) => widget.OnPointerEnter(localPoint, evt.PointerId); + + + private static int DefaultEventHandlersPoolCapacity => 1; + + + private static ObjectPool s_handlersPool; + private static ObjectPool EventHandlerPool + { + get + { + if (s_handlersPool == null) + { + s_handlersPool = new ObjectPool( + createFunc: () => new WidgetMetadata(), + actionOnRelease: (handlers) => handlers.Reset(), + collectionCheck: true, + defaultCapacity: DefaultEventHandlersPoolCapacity + ); + } + return s_handlersPool; + } + } + + + + /// + /// Used to track if the panel is dirty outside of widget updates. + /// + private bool m_isDirty = false; + + /// + /// Used to track if the panel needs to be redrawn due to a resize. + /// + private bool m_pendingResizeRedraw; + /// + /// Used to track the frame when the resize redraw was requested. + /// + private int m_resizeRedrawRequestedFrame = -1; + + /// + /// Sets the panel dirty. This will cause the panel to be redrawn on the next frame. + /// + internal void SetDirty() + { + if (WidgetContainer == null) + { + return; + } + m_isDirty = true; + } + + /// + /// The RectTransform that holds the panel's widgets. + /// + public RectTransform WidgetContainer => this.transform as RectTransform; + + public IReadOnlyList Widgets + { + get + { + return m_sortedWidgets; + } + } + + public IRenderTargetStrategy RenderTargetStrategy + { + get + { + return m_renderTargetStrategy; + } + set + { + if (ReferenceEquals(m_renderTargetStrategy, value)) + { + return; + } + + bool wasRegisteredInOldStrategy = m_renderTargetStrategy != null && m_renderTargetStrategy.IsPanelRegistered(this); + + + + UnsubscribeFromRenderTargetStrategyEvents(); + if (m_renderTargetStrategy != null && wasRegisteredInOldStrategy) + { + m_renderTargetStrategy.UnregisterPanel(this); + } + + m_renderTargetStrategy = value; + + if (m_renderTargetStrategy != null && wasRegisteredInOldStrategy) + { + m_renderTargetStrategy.RegisterPanel(this); + // The new strategy will have a different RenderTexture, so we need to let consumers know that the RenderTexture has changed + HandleRenderTargetUpdated(this); + } + + SubscribeToRenderTargetStrategyEvents(); + + + OnRenderTargetStrategyChanged?.Invoke(); + } + } + + + public PanelUpdateMode UpdateMode + { + get + { + return m_updateMode; + } + set + { + m_updateMode = value; + } + } + + + public bool DisableEditorPreview + { + get + { + return m_disableEditorPreview; + } + set + { + m_disableEditorPreview = value; + } + } + + public DrawOptimizationOptions DrawOptimization + { + get => m_drawOptimization; + set + { + if (m_drawOptimization == value) + { + return; + } + m_drawOptimization = value; + SetDirty(); + } + } + + public RenderTexture RenderTexture + { + get + { + if (RenderTargetStrategy == null) + { + return null; + } + return RenderTargetStrategy.GetRenderTexture(this); + } + } + + public Vector2 ScaleInRenderTexture + { + get + { + if (RenderTargetStrategy == null) + { + return Vector2.one; + } + return RenderTargetStrategy.GetPanelScale(this); + } + } + + public Vector2 OffsetInRenderTexture + { + get + { + if (RenderTargetStrategy == null) + { + return Vector2.zero; + } + return RenderTargetStrategy.GetPanelOffset(this); + } + } + + /// + /// Whether the panel supports multiple touches. When disabled, the panel collapses all input to a single pointer for legacy behavior. When enabled, multiple pointers are tracked independently. + /// + public MultiTouchSupport MultiTouch + { + get => m_multiTouchSupport; + set => m_multiTouchSupport = value; + } + + public event Action OnWidgetAdded; + + public event Action OnWidgetRemoved; + + public event Action OnRenderingStateChanged; + + public event Action OnRenderTargetStrategyChanged; + + public event Action OnRenderTargetUpdated; + + + + + public bool IsRendering => RenderTargetStrategy == null ? false : RenderTargetStrategy.IsPanelRegistered(this); + + public bool Enabled => this != null && this.enabled && this.gameObject != null && this.gameObject.activeInHierarchy; + + private void InitializeDefaultRenderTargetStrategyIfNeeded() + { + if (m_renderTargetStrategy != null) + { + return; + } + + if (m_customRenderTargetStrategy != null) + { + m_renderTargetStrategy = m_customRenderTargetStrategy; + return; + } + + + + if (!gameObject.TryGetComponent(out var strategy)) + { + strategy = gameObject.AddComponent(); + } + m_renderTargetStrategy = strategy; + } + + private void SubscribeToRenderTargetStrategyEvents() + { + if (m_renderTargetStrategy != null) + { + m_renderTargetStrategy.OnRenderTargetUpdated += HandleRenderTargetUpdated; + m_renderTargetStrategy.OnPanelRegistered += HandlePanelRegistrationStateChange; + m_renderTargetStrategy.OnPanelUnregistered += HandlePanelRegistrationStateChange; + } + } + + private void UnsubscribeFromRenderTargetStrategyEvents() + { + if (m_renderTargetStrategy != null) + { + m_renderTargetStrategy.OnRenderTargetUpdated -= HandleRenderTargetUpdated; + m_renderTargetStrategy.OnPanelRegistered -= HandlePanelRegistrationStateChange; + m_renderTargetStrategy.OnPanelUnregistered -= HandlePanelRegistrationStateChange; + } + } + + + + void OnEnable() + { + Orchestrator.Instance?.RegisterPanel(this); + + InitializeDefaultRenderTargetStrategyIfNeeded(); + + + if (!RenderTargetStrategy.IsPanelRegistered(this)) + { + RegisterPanelAndUpdateTarget(); + + } + + + if (m_sortedWidgets.Count > 0) + { + RedrawIfNeeded(); + } + + + SubscribeToRenderTargetStrategyEvents(); + + + } + + private void HandlePanelRegistrationStateChange(IRivePanel panel) + { + if (ReferenceEquals(panel, this)) + { + OnRenderingStateChanged?.Invoke(); + } + } + + void Start() + { + RedrawIfNeeded(); + } + + void OnDisable() + { + Orchestrator.Instance?.UnregisterPanel(this); + + UnsubscribeFromRenderTargetStrategyEvents(); + + if (RenderTargetStrategy != null && RenderTargetStrategy.IsPanelRegistered(this)) + { + UnregisterAndTriggerEventIfNeeded(); + } + + + + } + + public static void ClearWidgetEventPool() + { + s_handlersPool?.Clear(); + s_handlersPool = null; + } + + private bool UnregisterAndTriggerEventIfNeeded() + { + if (RenderTargetStrategy.IsPanelRegistered(this)) + { + bool wasUnregistered = RenderTargetStrategy.UnregisterPanel(this); + + if (wasUnregistered) + { + OnRenderingStateChanged?.Invoke(); + } + + return wasUnregistered; + } + + return false; + } + + + private void SubscribeToWidgetEvents(WidgetBehaviour widget) + { + var metadata = EventHandlerPool.Get(); + metadata.SiblingIndexChangedAction = () => HandleWidgetSiblingIndexChanged(widget); + metadata.ParentChangedAction = () => HandleWidgetHierarchyChanged(widget); + + widgetMetadata[widget] = metadata; + + widget.OnSiblingIndexChanged += metadata.SiblingIndexChangedAction; + widget.OnParentChanged += metadata.ParentChangedAction; + } + + private void UnsubscribeFromWidgetEvents(WidgetBehaviour widget) + { + + if (widgetMetadata.TryGetValue(widget, out var metadata)) + { + widget.OnSiblingIndexChanged -= metadata.SiblingIndexChangedAction; + widget.OnParentChanged -= metadata.ParentChangedAction; + EventHandlerPool.Release(metadata); + widgetMetadata.Remove(widget); + } + } + + private void HandleWidgetSiblingIndexChanged(WidgetBehaviour widget) + { + SortWidgetsIfNeeded(); + } + + private void HandleWidgetHierarchyChanged(WidgetBehaviour widget) + { + + SortWidgetsIfNeeded(); + + } + + /// + /// Registers a widget with the panel. The widget will be added to the panel's list of widgets and will be rendered to the panel's Render Target + /// + /// + internal void RegisterWidgetForRendering(WidgetBehaviour widget) + { + InitializeDefaultRenderTargetStrategyIfNeeded(); + + + + if (widget == null) + { + DebugLogger.Instance.LogWarning("Cannot add widget that is not a RiveWidgetBase."); + return; + } + + if (!widget.transform.IsChildOf(this.transform)) + { + DebugLogger.Instance.LogWarning("Cannot add widget that is not a child of this panel."); + return; + } + + + if (!m_sortedWidgets.Contains(widget)) + { + InsertSorted(widget); + + + RedrawIfNeeded(); + SubscribeToWidgetEvents(widget); + + OnWidgetAdded?.Invoke(widget); + } + } + + + + /// + /// Removes a widget from the panel. The widget will be removed from the panel's list of widgets and will no longer be rendered to the panel's Render Target. + /// + /// + internal void UnregisterWidgetFromRendering(WidgetBehaviour widget) + { + + if (widget == null) + { + DebugLogger.Instance.LogWarning("Cannot remove widget that is not a RiveWidgetBase."); + return; + } + + if (m_sortedWidgets.Contains(widget)) + { + m_sortedWidgets.Remove(widget); + + SortWidgetsIfNeeded(); + RedrawIfNeeded(); + UnsubscribeFromWidgetEvents(widget); + + OnWidgetRemoved?.Invoke(widget); + } + } + + /// + /// Adds a widget to the panel's hierarchy. The widget will be a child of the panel's RectTransform. + /// + /// + public void AddToHierarchy(WidgetBehaviour widget) + { + if (widget == null) + { + DebugLogger.Instance.LogWarning("Cannot add null widget to hierarchy."); + return; + } + + if (widget.transform.IsChildOf(this.transform)) + { + DebugLogger.Instance.LogWarning("Widget is already a child of this panel."); + return; + } + + widget.transform.SetParent(this.transform, false); + } + + /// + /// Removes a widget from the panel's hierarchy. The widget will no longer be a child of the panel's RectTransform. + /// + /// + public void RemoveFromHierarchy(WidgetBehaviour widget) + { + if (widget == null) + { + DebugLogger.Instance.LogWarning("Cannot remove null widget from hierarchy."); + return; + } + + if (!widget.transform.IsChildOf(this.transform)) + { + DebugLogger.Instance.LogWarning("Widget is not a child of this panel."); + return; + } + + widget.transform.SetParent(null, false); + } + + public bool ContainsWidget(WidgetBehaviour widget) + { + return m_sortedWidgets.Contains(widget); + } + + + + private void InsertSorted(WidgetBehaviour riveWidget) + { + + + if (m_widgetComparer == null) + { + m_widgetComparer = Comparer.Create(CompareWidgets); + } + + + int index = m_sortedWidgets.BinarySearch(riveWidget, m_widgetComparer); + // We find the correct insertion point for the new widget + // If index >= 0, an exact match was found, so we insert at that index + // If index < 0, no exact match was found. In this case, the binary search returns the bitwise complement of the index where the element should be inserted. + // We use -(index + 1) to decode this and get the actual insertion point. + if (index < 0) + { + index = -(index + 1); + } + m_sortedWidgets.Insert(index, riveWidget); + } + + + + private int CompareWidgets(IRiveWidget a, IRiveWidget b) + { + var widgetA = a as WidgetBehaviour; + var widgetB = b as WidgetBehaviour; + + if (IsDescendantOf(widgetA.transform, widgetB.transform)) + { + // If A is a descendant of B, A should be rendered after (on top of) B + return 1; + } + if (IsDescendantOf(widgetB.transform, widgetA.transform)) + { + // If B is a descendant of A, B should be rendered after (on top of) A + return -1; + } + + Transform commonAncestor = FindCommonAncestor(widgetA.transform, widgetB.transform); + + // Get the first children of the common ancestor that are ancestors of A and B + Transform childA = GetFirstChildInPath(commonAncestor, widgetA.transform); + Transform childB = GetFirstChildInPath(commonAncestor, widgetB.transform); + + // Compare the sibling indices of these children to determine rendering order + if (childA != null && childB != null) + { + return childA.GetSiblingIndex().CompareTo(childB.GetSiblingIndex()); + } + + // We fallback to depth comparison if something went wrong + return GetDepth(widgetA.transform).CompareTo(GetDepth(widgetB.transform)); + } + + + private Transform FindCommonAncestor(Transform a, Transform b) + { + if (a == b) return a; + + // First, find depth of both transforms + int depthA = 0, depthB = 0; + Transform currentA = a, currentB = b; + + while (currentA != null) + { + depthA++; + currentA = currentA.parent; + } + + while (currentB != null) + { + depthB++; + currentB = currentB.parent; + } + + // Reset to start + currentA = a; + currentB = b; + + // Move deeper transform up until both are at same depth + while (depthA > depthB) + { + currentA = currentA.parent; + depthA--; + } + + while (depthB > depthA) + { + currentB = currentB.parent; + depthB--; + } + + // Move up both transforms until we find common ancestor + while (currentA != currentB) + { + currentA = currentA.parent; + currentB = currentB.parent; + + // If we reached the root without finding common ancestor + if (currentA == null || currentB == null) + return null; + } + + return currentA; + } + + private Transform GetFirstChildInPath(Transform ancestor, Transform descendant) + { + if (ancestor == null || descendant == null) return null; + + Transform current = descendant; + Transform previous = null; + + while (current != ancestor && current != null) + { + previous = current; + current = current.parent; + } + + return previous; + } + + private void OnTransformChildrenChanged() + { + SortWidgetsIfNeeded(); + + } + + + + + private IEnumerator SortAndRedrawWidgets() + { + yield return null; + if (m_sortedWidgets.Count > 1) + { + m_sortedWidgets.Sort(m_widgetComparer); + RedrawIfNeeded(); + } + + m_sortWidgetsCoroutine = null; + } + + private void SortWidgetsIfNeeded() + { + if (m_sortWidgetsCoroutine != null) + { + return; + } + if (m_sortedWidgets.Count > 1 && this.gameObject.activeInHierarchy) + { + m_sortWidgetsCoroutine = StartCoroutine(SortAndRedrawWidgets()); + } + } + + + private bool IsDescendantOf(Transform descendant, Transform ancestor) + { + Transform parent = descendant.parent; + while (parent != null && parent != this.transform) + { + if (parent == ancestor) + { + return true; + } + parent = parent.parent; + } + return false; + } + + + private int GetDepth(Transform t) + { + int depth = 0; + while (t.parent != this.transform && t.parent != null) + { + depth++; + t = t.parent; + } + return depth; + } + + + /// + /// Called when the RectTransform dimensions change. We resize the RenderTexture to match the new dimensions. + /// + private void OnRectTransformDimensionsChange() + { + if (WidgetContainer == null || !WidgetContainer.gameObject.activeInHierarchy) + { + return; + } + + + // OnRectTransformDimensionsChange can fire mid-layout during GameView resizes or + // canvas rebuilds. If we call RedrawIfNeeded() immediately, we may capture transient + // widget sizes/positions before Unity's layout pass completes. With DrawWhenChanged + // optimization, rendering with incorrect sizes can leave the texture blank (if artboards + // have no dirt, we won't redraw again). Deferring the redraw until the Tick() method ensures all RectTransforms + // have settled and are processed at the same time before redrawing. + m_pendingResizeRedraw = true; + m_resizeRedrawRequestedFrame = Time.frameCount; + } + + + private void RedrawIfNeeded() + { + + if (!gameObject.activeInHierarchy || !this.enabled) + { + return; + } + + InitializeDefaultRenderTargetStrategyIfNeeded(); + + if (!RenderTargetStrategy.IsPanelRegistered(this)) + { + return; + } + + + RenderTargetStrategy.DrawPanel(this); + + + + } + + private bool RegisterPanelAndUpdateTarget() + { + if (RenderTargetStrategy == null) + { + return false; + } + bool wasRegistered = RenderTargetStrategy.RegisterPanel(this); + + if (wasRegistered) + { + OnRenderingStateChanged?.Invoke(); + } + return wasRegistered; + } + + + + private void HandleRenderTargetUpdated(IRivePanel panel) + { + if (ReferenceEquals(panel, this)) + { + OnRenderTargetUpdated?.Invoke(); + } + } + /// + /// When in `Manual` update mode, call this method every frame to advance the widgets managed by this panel. + /// + /// The time since the last frame. + public void Tick(float deltaTime) + { + if (!isActiveAndEnabled) + { + return; + } + + // Manual ticks execute immediately. Orchestrator is only notified so databinding + // callbacks can be triggered as expected. + TickImmediate(deltaTime); + Orchestrator.Instance?.NotifyManualTickOccurred(this); + } + + /// + /// Called every frame to update the widgets. This is where the widgets should update their visuals based on their state. + /// + /// The time since the last frame. + internal void TickImmediate(float deltaTime) + { + bool widgetNeedsRedraw = false; + + // We go through the widgets in reverse order to avoid issues with potentially removing widgets while iterating + for (int i = m_sortedWidgets.Count - 1; i >= 0; i--) + { + var widget = m_sortedWidgets[i]; + if (widget != null) + { + bool currentWidgetNeedsRedraw = widget.Tick(deltaTime); + + if (!widgetNeedsRedraw && currentWidgetNeedsRedraw) + { + widgetNeedsRedraw = true; + } + + } + } + + + bool resizeRedrawDue = m_pendingResizeRedraw && Time.frameCount > m_resizeRedrawRequestedFrame; + bool shouldRedraw = widgetNeedsRedraw || m_isDirty || resizeRedrawDue; + + if (shouldRedraw) + { + if (resizeRedrawDue) + { + m_pendingResizeRedraw = false; + } + + m_isDirty = false; + RedrawIfNeeded(); + } + } + + + + public bool StartRendering() + { + if (!this.enabled || !this.gameObject.activeInHierarchy) + { + DebugLogger.Instance.LogWarning("Cannot start rendering on a disabled or inactive panel."); + return false; + } + + if (RenderTargetStrategy == null) + { + DebugLogger.Instance.LogWarning("Cannot start rendering on a panel with no RenderTargetStrategy set."); + return false; + } + + if (!IsRendering) + { + return RegisterPanelAndUpdateTarget(); + } + + return false; + + } + + public bool StopRendering() + { + if (RenderTargetStrategy == null) + { + DebugLogger.Instance.LogWarning("Cannot stop rendering on a panel with no RenderTargetStrategy set."); + return false; + } + + if (IsRendering) + { + return UnregisterAndTriggerEventIfNeeded(); + } + + return false; + } + + /// + /// Sets the width and height of the panel. + /// + /// The new dimensions of the panel. + public void SetDimensions(Vector2 dimensions) + { + if (WidgetContainer == null) + { + return; + } + + // Make sure the dimensions are valid + if (dimensions.x <= 0 || dimensions.y <= 0 || float.IsNaN(dimensions.x) || float.IsNaN(dimensions.y) || float.IsInfinity(dimensions.x) || float.IsInfinity(dimensions.y)) + { + DebugLogger.Instance.LogWarning($"Invalid dimensions for panel. Width: {dimensions.x}, Height: {dimensions.y}"); + return; + } + + WidgetContainer.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, dimensions.x); + WidgetContainer.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, dimensions.y); + } + + // Input + + + private void HandlePointerDown(PanelPointerEvent evt) + { + ProcessPointerEvent(evt, m_pointerDownHandler); + } + + private void HandlePointerUp(PanelPointerEvent evt) + { + ProcessPointerEvent(evt, m_pointerUpHandler); + } + + private void HandlePointerMove(PanelPointerEvent evt) + { + ProcessPointerEvent(evt, m_pointerMoveHandler); + } + + private void HandlePointerExit(PanelPointerEvent evt) + { + ProcessPointerEvent(evt, m_pointerExitHandler); + } + + private void HandlePointerEnter(PanelPointerEvent evt) + { + ProcessPointerEvent(evt, m_pointerEnterHandler); + } + + private void ProcessPointerEvent(PanelPointerEvent evt, Action handler) + { + m_raycastResults.Clear(); + PanelRaycaster.RaycastAll(this, evt.Position, m_raycastResults); + + for (int i = m_raycastResults.Count - 1; i >= 0; i--) + { + var widget = m_raycastResults[i]; + + if (widget == null) + { + continue; + } + + Vector2 normalizedWidgetPoint; + + PanelRaycaster.TryGetNormalizedPointInWidget( + this, evt.Position, widget, out normalizedWidgetPoint); + + + // Preserve legacy single-pointer behavior when multitouch is disabled by + // collapsing all pointer ids to 0. + var effectiveEvent = m_multiTouchSupport == MultiTouchSupport.Enabled + ? evt + : new PanelPointerEvent(evt.Position, 0); + + handler(widget, normalizedWidgetPoint, effectiveEvent); + + } + } + + + public void RegisterInputProvider(IPanelInputProvider inputProvider) + { + if (inputProvider == null || m_panelInputProviders.Contains(inputProvider)) + { + return; + } + + inputProvider.PointerPressed += HandlePointerDown; + inputProvider.PointerReleased += HandlePointerUp; + inputProvider.PointerMoved += HandlePointerMove; + inputProvider.PointerExited += HandlePointerExit; + inputProvider.PointerEntered += HandlePointerEnter; + + m_panelInputProviders.Add(inputProvider); + } + + public void UnregisterInputProvider(IPanelInputProvider inputProvider) + { + if (inputProvider == null || !m_panelInputProviders.Contains(inputProvider)) + { + return; + } + + inputProvider.PointerPressed -= HandlePointerDown; + inputProvider.PointerReleased -= HandlePointerUp; + inputProvider.PointerMoved -= HandlePointerMove; + inputProvider.PointerExited -= HandlePointerExit; + inputProvider.PointerEntered -= HandlePointerEnter; + + m_panelInputProviders.Remove(inputProvider); + + } + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/Panels/RivePanel.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/Panels/RivePanel.cs.meta new file mode 100644 index 00000000..890434d6 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/Panels/RivePanel.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: f980c8c19ea824215be0686df1b90726 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: f377684eb5623462e80ebba320696f74, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/Panels/RivePanel.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects.meta new file mode 100644 index 00000000..a3339c1c --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0adb775af750e437cb088d9685819a45 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/ArtboardRenderObject.cs b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/ArtboardRenderObject.cs new file mode 100644 index 00000000..2a51cf85 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/ArtboardRenderObject.cs @@ -0,0 +1,137 @@ +using UnityEngine; + +namespace Rive.Components +{ + + /// + /// Represents a render object that has an artboard. + /// + public class ArtboardRenderObject : RenderObject + { + + + private Artboard m_artboard; + + private Alignment m_alignment; + private Path m_clipPath; + + /// + /// The fit of the artboard. + /// + private Fit m_fit; + + /// + /// The scale factor to use when drawing the artboard when using the Layout fit mode. + /// + private float m_scaleFactor = 1.0f; + + + /// + /// The Artboard to render. + /// + public Artboard Artboard => m_artboard; + + /// + /// The alignment of the artboard within the frame. + /// + public Alignment Alignment { get => m_alignment; set => m_alignment = value; } + + /// + /// The fit of the artboard within the frame. + /// + public Fit Fit { get => m_fit; set => m_fit = value; } + + /// + /// The actual scale factor to use when drawing the artboard when using the Layout fit mode, after accounting for any additional calculations based on the scale mode. + /// + public float EffectiveLayoutScaleFactor { get => m_scaleFactor; set => m_scaleFactor = value; } + + + + public override void DrawContent(IRenderer renderer, AABB frame, RenderContext renderContext) + { + if (renderContext.ClippingMode == RenderContext.ClippingModeSetting.CheckClipping) + { + ClipIfNeeded(renderer, frame); + } + + float scaleFactor = 1.0f; + + if (Fit == Fit.Layout) + { + scaleFactor = EffectiveLayoutScaleFactor; + } + + renderer.Align(Fit, Alignment, Artboard, frame, scaleFactor); + + renderer.Draw(m_artboard); + + + + } + + private void ClipIfNeeded(IRenderer renderer, AABB frame) + { + Rect rect = new Rect(frame.minY, frame.minY, frame.maxX, frame.maxY); + + // Determine if clipping is necessary + // We do this for performance (as clipping can be expensive), so we only clip if the render object overflows the frame + Vector2 artboardSize = new Vector2(m_artboard.Width, m_artboard.Height); + bool needsClipping = NeedsClipping(this.Fit, artboardSize, new Vector2(rect.width, rect.height)); + + if (needsClipping) + { + if (m_clipPath == null) + { + m_clipPath = new Path(); + } + ClippingPathHelper.ConfigureClippingPath(m_clipPath, rect.width, rect.height); + + renderer.Clip(m_clipPath); + } + } + + internal void Init(Artboard artboard, Alignment alignment, Fit fit, float scaleFactor) + { + m_artboard = artboard; + m_alignment = alignment; + m_fit = fit; + m_scaleFactor = scaleFactor; + } + public ArtboardRenderObject(Artboard artboard, Alignment alignment, Fit fit, float scaleFactor) + { + Init(artboard, alignment, fit, scaleFactor); + } + + + + + internal static bool NeedsClipping(Fit fit, Vector2 artboardSize, Vector2 frameSize) + { + float widthRatio = frameSize.x / artboardSize.x; + float heightRatio = frameSize.y / artboardSize.y; + + switch (fit) + { + case Fit.Fill: + return false; // Fill always fits exactly, no clipping needed + case Fit.Contain: + return false; // Contain always fits within the frame, no clipping needed + case Fit.Cover: + return widthRatio != heightRatio; // Only clip if aspect ratios don't match + case Fit.FitHeight: + return widthRatio < heightRatio; // Clip if width overflows after fitting height + case Fit.FitWidth: + return heightRatio < widthRatio; // Clip if height overflows after fitting width + case Fit.None: + return artboardSize.x > frameSize.x || artboardSize.y > frameSize.y; + case Fit.ScaleDown: + return artboardSize.x > frameSize.x || artboardSize.y > frameSize.y; + case Fit.Layout: + return false; // Layout resizes the artboard to fit the frame. + default: + return false; // Default to not clipping if we don't know the fit + } + } + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/ArtboardRenderObject.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/ArtboardRenderObject.cs.meta new file mode 100644 index 00000000..6e08cc94 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/ArtboardRenderObject.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 68b76aab5efce4023b7874464aa918e2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/ArtboardRenderObject.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/IRenderObject.cs b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/IRenderObject.cs new file mode 100644 index 00000000..fda9deae --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/IRenderObject.cs @@ -0,0 +1,47 @@ +namespace Rive.Components +{ + public struct RenderContext + { + public enum ClippingModeSetting + { + /// + /// Check if clipping is needed and apply if necessary. + /// + CheckClipping = 0, + + /// + /// Skip clipping checks since render target bounds will handle it. + /// + SkipClipping = 1, + } + + + + public ClippingModeSetting ClippingMode { get; private set; } + + + public RenderContext(ClippingModeSetting clippingMode) + { + ClippingMode = clippingMode; + } + } + + /// + /// The IRenderObject interface. This interface should be implemented by classes that want to be rendered within a RiveView. + /// + public interface IRenderObject + { + /// + /// The transform data for the render object. Use this to provide the position, size, rotation, scale, and pivot of the render object. + /// + RenderTransform RenderTransform { get; set; } + + /// + /// This renders the content of the render object to the given frame. + /// + /// The Rive renderer to use to draw the content. + /// The frame to draw the content within. + void DrawContent(IRenderer renderer, AABB frame, RenderContext renderContext); + + } +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/IRenderObject.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/IRenderObject.cs.meta new file mode 100644 index 00000000..830489cf --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/IRenderObject.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 3994cebdef7244cf6bda52efc7725ed4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/IRenderObject.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/LayoutScalingMode.cs b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/LayoutScalingMode.cs new file mode 100644 index 00000000..56e986d2 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/LayoutScalingMode.cs @@ -0,0 +1,23 @@ +namespace Rive.Components +{ + /// + /// Defines how the artboard should be scaled within the frame when using the Layout fit mode. + /// + public enum LayoutScalingMode + { + /// + /// This mode will keep the artboard at a constant pixel size, regardless of screen resolution. This means that the artboard may appear larger or smaller depending on the screen resolution. + /// + ConstantPixelSize = 0, + + /// + /// This mode will scale the artboard to maintain the same relative size as the original artboard dimensions across different resolutions. This means that the artboard will always appear the same size relative to the screen. + /// + ReferenceArtboardSize = 1, + + /// + /// Maintains consistent physical size (in inches) across different devices by accounting for screen DPI. On higher DPI displays, content will appear larger to maintain consistent physical dimensions. + /// + ConstantPhysicalSize = 2, + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/LayoutScalingMode.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/LayoutScalingMode.cs.meta new file mode 100644 index 00000000..cf27d1cd --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/LayoutScalingMode.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 00af82da0e07448279d5639768b2517f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/LayoutScalingMode.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/Procedural.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/Procedural.meta new file mode 100644 index 00000000..0cb07fdf --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/Procedural.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1e74ca1de2fe9485b8331701b8af8b04 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/Procedural/IProceduralDrawing.cs b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/Procedural/IProceduralDrawing.cs new file mode 100644 index 00000000..5255cfb9 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/Procedural/IProceduralDrawing.cs @@ -0,0 +1,89 @@ +using UnityEngine; + +namespace Rive.Components +{ + /// + /// Interface for a procedural drawing that can be used to draw a procedural graphic within a ProceduralRiveWidget. + /// + public interface IProceduralDrawing + { + /// + /// This should pass the procedural graphic using the given renderer. This might be called multiple times during the lifetime of the object, such as when the render texture is redrawn. + /// + /// The Rive renderer to use to draw the procedural graphic. + /// The frame to draw the procedural visual within. + /// Provides additional context to consider when drawing the procedural graphic. + void Draw(IRenderer renderer, AABB frame, RenderContext renderContext); + + /// + /// This should update the procedural graphic. Use this to update the procedural drawing changes over time. + /// + /// The time since the last update. + /// True if the procedural graphic has changed, false otherwise. + bool Advance(float deltaTime); + + /// + /// Tests if a given local position within the widget's rectangle hits any interactive elements. + /// + /// + /// The normalized point of the pointer position in the rectangle. The coordinates are in the range [0,1] where (0,0) is the bottom-left corner and (1,1) is the top-right corner. + /// + /// + /// The rectangle to test the hit against. + /// + /// + /// Returns true if the position hits an interactive element; otherwise, false. + /// + bool HitTest(Vector2 point, Rect rect); + + /// + /// Responds to a pointer press event within the procedural graphic in the given rect. + /// + /// + /// The normalized point of the pointer position in the rectangle. The coordinates are in the range [0,1] where (0,0) is the bottom-left corner and (1,1) is the top-right corner. + /// + /// + /// The rectangle to reference for the pointer down event. + /// + /// Returns true if the pointer down event was handled; otherwise, false. + bool HandlePointerDown(Vector2 point, Rect rect); + + /// + /// Responds to a pointer up event within the procedural graphic in the given rect. + /// + /// + /// The normalized point of the pointer position in the rectangle. The coordinates are in the range [0,1] where (0,0) is the bottom-left corner and (1,1) is the top-right corner. + /// + /// + /// The rectangle to reference for the pointer up event. + /// + /// Returns true if the pointer up event was handled; otherwise, false. + bool HandlePointerUp(Vector2 point, Rect rect); + + /// + /// Responds to a pointer move event within the procedural graphic in the given rect. + /// + /// + /// The normalized point of the pointer position in the rectangle. The coordinates are in the range [0,1] where (0,0) is the bottom-left corner and (1,1) is the top-right corner. + /// + /// + /// The rectangle to reference for the pointer move event. + /// + /// Returns true if the pointer move event was handled; otherwise, false. + bool HandlePointerMove(Vector2 point, Rect rect); + + + + /// + /// Responds to a pointer exit event within the procedural graphic in the given rect. + /// + /// + /// The normalized point of the pointer position in the rectangle. The coordinates are in the range [0,1] where (0,0) is the bottom-left corner and (1,1) is the top-right corner. + /// + /// + /// The rectangle to reference for the pointer exit event. + /// + /// Returns true if the pointer exit event was handled; otherwise, false. + bool HandlePointerExit(Vector2 point, Rect rect); + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/Procedural/IProceduralDrawing.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/Procedural/IProceduralDrawing.cs.meta new file mode 100644 index 00000000..f7161ec8 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/Procedural/IProceduralDrawing.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: c55edd77bca1e4ecaac8e11665bc4258 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/Procedural/IProceduralDrawing.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/Procedural/ProceduralDrawing.cs b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/Procedural/ProceduralDrawing.cs new file mode 100644 index 00000000..7113e1a6 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/Procedural/ProceduralDrawing.cs @@ -0,0 +1,44 @@ +using UnityEngine; + +namespace Rive.Components +{ + /// + /// Represents a procedural drawing that can be rendered within a ProceduralRiveWidget. Implement this class to create custom procedural graphics. + /// + public abstract class ProceduralDrawing : MonoBehaviour, IProceduralDrawing + { + + public abstract void Draw(IRenderer renderer, AABB frame, RenderContext renderContext); + + public virtual bool Advance(float deltaTime) + { + return false; + } + + + public virtual bool HitTest(Vector2 point, Rect rect) + { + return false; + } + + public virtual bool HandlePointerDown(Vector2 point, Rect rect) + { + return false; + } + + public virtual bool HandlePointerUp(Vector2 point, Rect rect) + { + return false; + } + + public virtual bool HandlePointerMove(Vector2 point, Rect rect) + { + return false; + } + + public bool HandlePointerExit(Vector2 point, Rect rect) + { + return false; + } + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/Procedural/ProceduralDrawing.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/Procedural/ProceduralDrawing.cs.meta new file mode 100644 index 00000000..e91ec9fd --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/Procedural/ProceduralDrawing.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 4f2a4f8c7fdf944e19e6462afd9f177e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/Procedural/ProceduralDrawing.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/ProceduralRenderObject.cs b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/ProceduralRenderObject.cs new file mode 100644 index 00000000..3a9985bb --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/ProceduralRenderObject.cs @@ -0,0 +1,57 @@ +using System; + +namespace Rive.Components +{ + /// + /// This represents a procedural render object that can be rendered within a RiveWidget. + /// + public class ProceduralRenderObject : RenderObject + { + private ProceduralDrawing m_drawing; + + /// + /// The procedural drawing to render. + /// + public ProceduralDrawing Drawing { get => m_drawing; } + + + public override void DrawContent(IRenderer renderer, AABB frame, RenderContext renderContext) + { + if (Drawing == null) + { + return; + } + + + + if (RenderTargetStrategy.ProceduralDrawingRequiresRotationCorrection()) + { + renderer.Save(); + // When the drawing is rotated by 90 degrees, it appears offset by the width of the frame, so we translate it back by that amount + // The order of operations is important here, so we first translate by the width of the frame, then rotate by 90 degrees, otherwise the translation will be incorrect + renderer.Transform(System.Numerics.Matrix3x2.CreateTranslation(frame.maxX, 0)); + + //Rotate the drawing by 90 degrees + renderer.Transform(System.Numerics.Matrix3x2.CreateRotation((float)Math.PI / 2)); + + Drawing.Draw(renderer, frame, renderContext); + renderer.Restore(); + return; + } + + + Drawing.Draw(renderer, frame, renderContext); + } + + /// + /// Creates a new procedural render object with the given drawing. + /// + /// The procedural drawing to render. + public ProceduralRenderObject(ProceduralDrawing drawing) + { + m_drawing = drawing; + } + + + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/ProceduralRenderObject.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/ProceduralRenderObject.cs.meta new file mode 100644 index 00000000..631f8486 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/ProceduralRenderObject.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 6b93f6ee1b5a54a279bdc304efcfa216 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/ProceduralRenderObject.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/RenderObject.cs b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/RenderObject.cs new file mode 100644 index 00000000..38a351bd --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/RenderObject.cs @@ -0,0 +1,22 @@ +namespace Rive.Components +{ + /// + /// This represents an object that can be rendered within a RivePanel. + /// + public abstract class RenderObject : IRenderObject + { + /// + /// The transform data for the render object. Use this to get or update the position, size, rotation, scale, and pivot of the render object. + /// + public RenderTransform RenderTransform { get; set; } + + /// + /// This should draw the content of the render object to the given frame using the given renderer. + /// + /// The renderer to use to draw the content. + /// The frame to draw the content within. + public abstract void DrawContent(IRenderer renderer, AABB frame, RenderContext renderContext); + + + } +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/RenderObject.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/RenderObject.cs.meta new file mode 100644 index 00000000..7042d202 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/RenderObject.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 76e1006156bff4d7fb5d399bfcb353e6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/RenderObject.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/RenderTransform.cs b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/RenderTransform.cs new file mode 100644 index 00000000..9833e935 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/RenderTransform.cs @@ -0,0 +1,195 @@ +using Rive.Utils; +using UnityEngine; + +namespace Rive.Components +{ + /// + /// Holds the data for a render object's transform in Rive coordinates. Rive uses a cartesian coordinate system where the positive x-axis extends towards the right, and the positive y-axis extends towards the bottom of the screen. The origin (0,0) is located at the top left corner of the screen. + /// + public struct RenderTransform + { + private Vector2 m_position; + private Vector2 m_size; + private float m_rotation; + private Vector2 m_scale; + private Vector2 m_pivot; + + private static readonly Vector3[] s_widgetCorners = new Vector3[4]; + private static readonly Vector3[] s_panelCorners = new Vector3[4]; + + + // Top-left corner in Rive coordinates + + /// + /// The position of the Transform in Rive coordinates within it's panel + /// + public Vector2 Position => m_position; + + /// + /// The dimensions of the Transform; + /// + public Vector2 Size => m_size; + + /// + /// The rotation of the Transform in degrees + /// + public float Rotation => m_rotation; + + /// + /// The scale of the Transform within it's parent panel + /// + public Vector2 Scale => m_scale; + + /// + /// The pivot point of the Transform + /// + public Vector2 Pivot => m_pivot; + + /// + /// Creates a new RenderTransform with the given position, size, rotation, scale, and pivot. + /// + /// The position of the Transform in Rive coordinates within it's panel. + /// The dimensions of the Transform. + /// The rotation of the Transform in degrees. + /// The scale of the Transform within it's parent panel. + /// The pivot point of the Transform. + public RenderTransform(Vector2 position, Vector2 size, float rotation, Vector2 scale, Vector2 pivot) + { + m_position = position; + m_size = size; + m_rotation = rotation; + m_scale = scale; + m_pivot = pivot; + } + + + + /// + /// Creates a new RenderTransform from the given RectTransform. This method will convert the RectTransform's position, size, rotation, scale, and pivot to Rive coordinates. + /// + /// The RectTransform to create the RenderTransform from. + /// A new RenderTransform with the given RectTransform's data. + public static RenderTransform FromRectTransform(RectTransform rectTransform, RectTransform panelRectTransform) + { + if (rectTransform == null || panelRectTransform == null) + { + DebugLogger.Instance.LogError("FromRectTransform called with null rectTransform or panelRectTransform"); + return default; + } + + // Calculate adjusted data if pivot is not (0,0) + RectTransformPivotUtility.RectTransformData adjustedData = rectTransform.pivot != Vector2.zero + ? RectTransformPivotUtility.CalculatePivotChange(rectTransform, Vector2.zero) + : new RectTransformPivotUtility.RectTransformData(rectTransform.pivot, rectTransform.anchoredPosition, rectTransform.localPosition); + + Vector2 size = rectTransform.rect.size; + bool shouldFlip = TextureHelper.ShouldFlipTexture(); + + Matrix4x4 parentMatrix = panelRectTransform.localToWorldMatrix; + Matrix4x4 inverseParentMatrix = parentMatrix.inverse; + Matrix4x4 childMatrix = rectTransform.localToWorldMatrix; + + Matrix4x4 relativeMatrix = inverseParentMatrix * childMatrix; + + // Get the world position of the widget and panel corners + // We use world positions for our calculations to account for the rect transform being in a complicated heirarchy + // Before we pass the transform info to the Rive renderer, we essentially flatten the hierarchy and render the widgets in absolute space to simplify the matrix calculations. + + rectTransform.GetWorldCorners(s_widgetCorners); + panelRectTransform.GetWorldCorners(s_panelCorners); + + Vector3 widgetWorldPosTL = s_widgetCorners[1]; + Vector3 panelWorldPosTL = s_panelCorners[1]; + + // Calculate relative position in world space + Vector3 relativeWorldPos = widgetWorldPosTL - panelWorldPosTL; + + // Convert world space difference to panel's local space + Vector3 relativeLocalPos = inverseParentMatrix.MultiplyVector(relativeWorldPos); + + Vector2 position = new Vector2(relativeLocalPos.x, relativeLocalPos.y); + + // Adjust Y position if flipping is required based on the texture coordinate system + if (shouldFlip) + { + position.y = panelRectTransform.rect.size.y + position.y + rectTransform.rect.height; + } + else + { + position.y = panelRectTransform.rect.size.y - position.y - panelRectTransform.rect.height; + } + + // Extract rotation (in radians) from the relative matrix + float rotation = Mathf.Atan2(relativeMatrix.m01, relativeMatrix.m00); + + // Extract scale from the relative matrix + Vector2 scale = new Vector2( + new Vector2(relativeMatrix.m00, relativeMatrix.m01).magnitude, + new Vector2(relativeMatrix.m10, relativeMatrix.m11).magnitude + ); + + Vector2 pivot = adjustedData.Pivot; + + return new RenderTransform(position, size, rotation, scale, pivot); + } + + } + + + /// + /// We use this to calculate pivot changes for RectTransforms while maintaining the world position. + /// + internal class RectTransformPivotUtility + { + public struct RectTransformData + { + public Vector2 Pivot; + public Vector2 AnchoredPosition; + public Vector3 LocalPosition; + + public RectTransformData(Vector2 pivot, Vector2 anchoredPosition, Vector3 localPosition) + { + Pivot = pivot; + AnchoredPosition = anchoredPosition; + LocalPosition = localPosition; + } + } + + public static RectTransformData CalculatePivotChange(RectTransform rectTransform, Vector2 newPivot) + { + Vector2 size = rectTransform.rect.size; + + // Get the offset in anchored position + Vector2 pivotDelta = newPivot - rectTransform.pivot; + Vector2 positionDelta = new Vector2( + pivotDelta.x * size.x, + pivotDelta.y * size.y + ); + + Vector2 newAnchoredPosition = rectTransform.anchoredPosition - positionDelta; + + // Calculate new local position (to maintain world position) + Vector3 localPositionDelta = rectTransform.localRotation * new Vector3(positionDelta.x, positionDelta.y, 0); + Vector3 newLocalPosition = rectTransform.localPosition + localPositionDelta; + + return new RectTransformData(newPivot, newAnchoredPosition, newLocalPosition); + } + + public static void ApplyPivotChange(RectTransform rectTransform, RectTransformData data) + { + rectTransform.pivot = data.Pivot; + rectTransform.anchoredPosition = data.AnchoredPosition; + rectTransform.localPosition = data.LocalPosition; + } + + public static void SetPivot(RectTransform rectTransform, Vector2 newPivot) + { + RectTransformData newData = CalculatePivotChange(rectTransform, newPivot); + ApplyPivotChange(rectTransform, newData); + } + } + + + + +} diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/RenderTransform.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/RenderTransform.cs.meta new file mode 100644 index 00000000..7baea14d --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/RenderTransform.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 5ca8cee21a473467fbf14ab5848f5c50 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/RenderObjects/RenderTransform.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines.meta new file mode 100644 index 00000000..b06dd204 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2f437edf6d779460d84a3481ab744045 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/BuiltIn.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/BuiltIn.meta new file mode 100644 index 00000000..8485d891 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/BuiltIn.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3a2dac9051eee44959bb7d7871c53dab +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/BuiltIn/BuiltInRenderPipelineHandler.cs b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/BuiltIn/BuiltInRenderPipelineHandler.cs new file mode 100644 index 00000000..313fb113 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/BuiltIn/BuiltInRenderPipelineHandler.cs @@ -0,0 +1,435 @@ +#if !RIVE_USING_URP && !RIVE_USING_HDRP + +using System.Collections; +using System.Collections.Generic; +using Rive.Utils; +using UnityEngine; +using UnityEngine.Rendering; +using UnityEngine.SceneManagement; + + +namespace Rive.Components.BuiltIn +{ + public class BuiltInRenderPipelineHandler : MonoBehaviour, IRenderPipelineHandler + { + + private Dictionary m_activeRenderCommandBuffers = new Dictionary(); + + + [Tooltip("The cameras that will render the Rive content. If not provided, the main camera will be used.")] + [SerializeField] private Camera m_renderCamera; + + private CommandBufferPool m_commandBufferPool; + + [SerializeField] + private CameraEvent m_cameraEvent = CameraEvent.AfterEverything; + + private Coroutine m_setNewRenderCameraCoroutine; + + private List m_rendererCleanupList = new List(); + + private bool m_isDestroyed = false; + + private bool m_registeredWithOrchestrator = false; + + private Camera[] m_camerasInScene; + + + /// + /// The default capacity of the render pass pool. + /// + public int CommandBufferPoolDefaultCapacity { get; set; } = 5; + + /// + /// The maximum size of the render pass pool. + /// + public int CommandBufferPoolMaxSize { get; set; } = 10000; + + + /// + /// The camera that will render the Rive content. + /// + public Camera RenderCamera + { + get + { + return m_renderCamera; + } + set => SetRenderCamera(value); + } + + /// + /// The current instance of the BuiltInRenderPipelineHandler in the scene. + /// + public static BuiltInRenderPipelineHandler Instance + { + get + { + return RenderPipelineHelper.CurrentHandler as BuiltInRenderPipelineHandler; + } + } + + + protected virtual void OnEnable() + { + SceneManager.activeSceneChanged += ChangedActiveScene; + TrySubscribeToOrchestrator(); + } + + protected virtual void OnDisable() + { + SceneManager.activeSceneChanged -= ChangedActiveScene; + UnsubscribeFromOrchestrator(); + } + + private void TrySubscribeToOrchestrator() + { + if (m_registeredWithOrchestrator || !isActiveAndEnabled || m_activeRenderCommandBuffers.Count == 0) + { + return; + } + + var orchestrator = Orchestrator.Instance; + if (orchestrator != null) + { + orchestrator.OnPostRenderPreparation += ValidateRenderCamera; + m_registeredWithOrchestrator = true; + } + } + + private void UnsubscribeFromOrchestrator() + { + if (!m_registeredWithOrchestrator) + { + return; + } + + var orchestrator = Orchestrator.Instance; + if (orchestrator != null) + { + orchestrator.OnPostRenderPreparation -= ValidateRenderCamera; + } + m_registeredWithOrchestrator = false; + } + + private void ValidateRenderCamera() + { + if (m_renderCamera != null && !m_renderCamera.isActiveAndEnabled) + { + Camera newCamera = GetRenderCameraInScene(); + if (newCamera != null) + { + RenderCamera = newCamera; + } + } + } + + private void ChangedActiveScene(Scene arg0, Scene arg1) + { + // If the scene changes, it's likely the main camera was destroyed, we need to wait until there's one + // This is also called on initial scene load when entering play mode + if (m_setNewRenderCameraCoroutine == null) + { + m_setNewRenderCameraCoroutine = StartCoroutine(SetNewRenderCamera()); + } + + + } + + private IEnumerator SetNewRenderCamera() + { + + // Wait until the scene is loaded + while (!SceneManager.GetActiveScene().isLoaded) + { + yield return null; + } + + if (m_renderCamera == null) + { + // Wait until there's a main camera in the scene + Camera camera = null; + while (camera == null) + { + camera = GetRenderCameraInScene(); + + if (camera == null) + { + yield return null; + } + + } + + RenderCamera = camera; + } + + + m_setNewRenderCameraCoroutine = null; + + } + + public virtual RenderTexture AllocateRenderTexture(int width, int height) + { + RenderTextureDescriptor descriptor = TextureHelper.Descriptor(width, height); + RenderTexture renderTexture = new RenderTexture(descriptor); + return renderTexture; + } + + + + /// + /// Looks for the main camera in the scene to render the Rive content. + /// + /// + private Camera GetRenderCameraInScene() + { + return CameraHelper.GetRenderCameraInScene(); + } + + + private void SetRenderCamera(Camera camera) + { + if (ReferenceEquals(m_renderCamera, camera)) + { + return; + + } + + // If we have a previous camera, remove the command buffers from it + if (m_renderCamera != null) + { + + foreach (var kvp in m_activeRenderCommandBuffers) + { + SafeRemoveCommandBuffer(m_renderCamera, kvp.Value); + } + } + + m_renderCamera = camera; + + if (m_renderCamera != null) + { + + // Add existing command buffers to the new camera + foreach (var kvp in m_activeRenderCommandBuffers) + { + AddCommandBufferToCamera(m_renderCamera, kvp.Value); + } + + } + + } + + private void InitCommandBufferPoolIfNeeded() + { + if (m_commandBufferPool == null) + { + m_commandBufferPool = new CommandBufferPool(CommandBufferPoolDefaultCapacity, CommandBufferPoolMaxSize); + } + } + + public virtual void Register(IRenderer renderer) + { + if (m_isDestroyed) + { + return; + } + + InitCommandBufferPoolIfNeeded(); + + if (renderer == null) + { + DebugLogger.Instance.LogWarning("Trying to register a null renderer."); + return; + } + + if (m_activeRenderCommandBuffers.ContainsKey(renderer)) + { + DebugLogger.Instance.LogWarning("Trying to register the same renderer twice."); + return; + } + + CommandBuffer commandBuffer = m_commandBufferPool.Get("RiveRenderPass"); + + + + renderer.AddToCommandBuffer(commandBuffer); + + + + + m_activeRenderCommandBuffers.Add(renderer, commandBuffer); + TrySubscribeToOrchestrator(); + + if (renderer is Renderer r && r.RenderQueue != null && r.RenderQueue.Texture != null) + { + InternalSetRenderTargetToCommandBufferIfNeeded(commandBuffer, r.RenderQueue.Texture); + } + + Camera cameraToUse = RenderCamera; + + if (cameraToUse == null) + { + cameraToUse = GetRenderCameraInScene(); + + if (cameraToUse != null) + { + // If we found a camera in the scene, set it as the render camera + // We do this immediately, instead of waiting for the coroutine to finish because we want the visuals to show up on the initial frame + RenderCamera = cameraToUse; + } + else + { + // Schedule the camera to be set when available in the scene + if (m_setNewRenderCameraCoroutine == null) + { + m_setNewRenderCameraCoroutine = StartCoroutine(SetNewRenderCamera()); + } + } + } + else + { + // If we already have a camera, add the new command buffer to it + AddCommandBufferToCamera(cameraToUse, commandBuffer); + } + + } + + public void SetRendererTexture(IRenderer renderer, RenderTexture renderTexture) + { + if (renderer == null) + { + DebugLogger.Instance.LogError("Cannot set texture on a null renderer."); + return; + } + + Renderer riveRenderer = renderer as Renderer; + + if (riveRenderer == null) + { + DebugLogger.Instance.LogError("Cannot set texture on a non-Rive renderer."); + return; + } + + + riveRenderer.RenderQueue.UpdateTexture(renderTexture); + + + + if (m_activeRenderCommandBuffers.TryGetValue(renderer, out var commandBuffer)) + { + InternalSetRenderTargetToCommandBufferIfNeeded(commandBuffer, renderTexture); + } + } + + private void InternalSetRenderTargetToCommandBufferIfNeeded(CommandBuffer commandBuffer, RenderTexture renderTexture) + { + if (commandBuffer == null || renderTexture == null) + { + return; + } + + if (TextureHelper.NeedsRenderTargetSetOnCommandBuffer()) + { + commandBuffer.SetRenderTarget(renderTexture); + } + + } + + public virtual void Unregister(IRenderer renderer) + { + if (renderer == null) + { + return; + } + + if (m_activeRenderCommandBuffers.TryGetValue(renderer, out var commandBuffer)) + { + + + SafeRemoveCommandBuffer(m_renderCamera, commandBuffer); + + m_activeRenderCommandBuffers.Remove(renderer); + m_commandBufferPool.Release(commandBuffer); + + if (m_activeRenderCommandBuffers.Count == 0) + { + UnsubscribeFromOrchestrator(); + } + } + } + + private void SafeRemoveCommandBuffer(Camera camera, CommandBuffer commandBuffer) + { + if (camera != null && commandBuffer != null) + { + camera.RemoveCommandBuffer(m_cameraEvent, commandBuffer); + } + } + + private void AddCommandBufferToCamera(Camera camera, CommandBuffer commandBuffer) + { + if (camera != null && commandBuffer != null) + { + camera.AddCommandBuffer(m_cameraEvent, commandBuffer); + } + } + + private void Cleanup() + { + m_isDestroyed = true; + UnsubscribeFromOrchestrator(); + + if (m_setNewRenderCameraCoroutine != null) + { + StopCoroutine(m_setNewRenderCameraCoroutine); + m_setNewRenderCameraCoroutine = null; + } + + m_rendererCleanupList.Clear(); + m_rendererCleanupList.AddRange(m_activeRenderCommandBuffers.Keys); + + for (int i = 0; i < m_rendererCleanupList.Count; i++) + { + Unregister(m_rendererCleanupList[i]); + } + + } + + protected virtual void OnDestroy() + { + Cleanup(); + } + + public bool IsRendererRegistered(IRenderer renderer) + { + return m_activeRenderCommandBuffers.ContainsKey(renderer); + } + + public void ReleaseRenderTexture(RenderTexture renderTexture) + { + if (renderTexture != null) + { + renderTexture.Release(); + } + } + + public RenderTexture ResizeRenderTexture(RenderTexture renderTexture, int width, int height) + { + if (renderTexture == null) + { + DebugLogger.Instance.LogError("Cannot resize a null render texture."); + return null; + } + + renderTexture.Release(); + renderTexture.width = width; + renderTexture.height = height; + renderTexture.Create(); + + + return renderTexture; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/BuiltIn/BuiltInRenderPipelineHandler.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/BuiltIn/BuiltInRenderPipelineHandler.cs.meta new file mode 100644 index 00000000..b9724c79 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/BuiltIn/BuiltInRenderPipelineHandler.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 40d769d00dbbd4fd4b5e3af185d03e1f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/BuiltIn/BuiltInRenderPipelineHandler.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/BuiltIn/CommandBufferPool.cs b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/BuiltIn/CommandBufferPool.cs new file mode 100644 index 00000000..fcc85552 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/BuiltIn/CommandBufferPool.cs @@ -0,0 +1,59 @@ +using UnityEngine.Rendering; + +namespace Rive.Components.BuiltIn +{ + internal class CommandBufferPool + { + private UnityEngine.Pool.ObjectPool m_pool; + + public CommandBufferPool(int defaultCapacity = 10, int maxSize = 100) + { + m_pool = new UnityEngine.Pool.ObjectPool( + createFunc: CreateCommandBuffer, + actionOnGet: null, + actionOnRelease: OnReleaseCommandBuffer, + actionOnDestroy: OnDestroyCommandBuffer, + collectionCheck: true, + defaultCapacity: defaultCapacity, + maxSize: maxSize + ); + } + + public CommandBuffer Get() + { + return m_pool.Get(); + } + + public CommandBuffer Get(string name) + { + var commandBuffer = m_pool.Get(); + commandBuffer.name = name; + return commandBuffer; + } + + public void Release(CommandBuffer commandBuffer) + { + m_pool.Release(commandBuffer); + } + + private CommandBuffer CreateCommandBuffer() + { + return new CommandBuffer(); + } + + private void OnReleaseCommandBuffer(CommandBuffer commandBuffer) + { + commandBuffer.Clear(); + } + + private void OnDestroyCommandBuffer(CommandBuffer commandBuffer) + { + commandBuffer.Dispose(); + } + + public void Clear() + { + m_pool.Clear(); + } + } +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/BuiltIn/CommandBufferPool.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/BuiltIn/CommandBufferPool.cs.meta new file mode 100644 index 00000000..a5ebc5db --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/BuiltIn/CommandBufferPool.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 112f248369cd642e6ba7cc96e14f2908 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/BuiltIn/CommandBufferPool.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/BuiltIn/Shaders.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/BuiltIn/Shaders.meta new file mode 100644 index 00000000..a015cf09 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/BuiltIn/Shaders.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2e8493f6b43b2497c8a39a658918727f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/BuiltIn/Shaders/Lit.shadergraph b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/BuiltIn/Shaders/Lit.shadergraph new file mode 100644 index 00000000..7a5e0cae --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/BuiltIn/Shaders/Lit.shadergraph @@ -0,0 +1,1993 @@ +{ + "m_SGVersion": 3, + "m_Type": "UnityEditor.ShaderGraph.GraphData", + "m_ObjectId": "4098f6a1a61540a389a7bd043c203452", + "m_Properties": [ + { + "m_Id": "2a0fc11ff11745fbae58a8e255270113" + }, + { + "m_Id": "81ca8a168f9c4e17b490fd23d29bfec5" + }, + { + "m_Id": "8c2ee6de8ac44969afc807897aec8963" + }, + { + "m_Id": "e540e490b602446c82e9bc1e1de48847" + }, + { + "m_Id": "c639c3809c6f4963b3aa7422aa39259f" + }, + { + "m_Id": "a0a1a7b3ccf149bf9fab4f25cbf04621" + }, + { + "m_Id": "0b563b81796b44489ab147673a69538d" + } + ], + "m_Keywords": [ + { + "m_Id": "d09ad266770042b783f41774f95255a0" + } + ], + "m_Dropdowns": [], + "m_CategoryData": [ + { + "m_Id": "48d1691978ed405387844998eb582a38" + } + ], + "m_Nodes": [ + { + "m_Id": "9f2fe456fc3b4ebb9a19c3045d7ca0db" + }, + { + "m_Id": "a878504fb615472bbc92981bc85f2022" + }, + { + "m_Id": "48602648207f44cba0b1494f9cde4496" + }, + { + "m_Id": "179a2a6df6064ef69f4aa621baad2d2e" + }, + { + "m_Id": "e8449ac4440842089ed71d24ae1abbdc" + }, + { + "m_Id": "2ce12b55d78441a3aedf83368b0eaeb2" + }, + { + "m_Id": "588955e76cd0400088929404da30207c" + }, + { + "m_Id": "ce79319b1f18421c8a11de70d1616779" + }, + { + "m_Id": "02f2af5cbb1a45f9a0af7b0b4cdc862d" + }, + { + "m_Id": "579f39a209ac4a00be6e05f7b10e188c" + }, + { + "m_Id": "01d2d5ea9fbc4b179f32a0927a47c850" + }, + { + "m_Id": "921a017b3b77432f928fd08d62758430" + }, + { + "m_Id": "7e7f3c2a0a59469e9f8da0fef2c555ab" + }, + { + "m_Id": "a6611900bc41403e8cadb05d29d07447" + }, + { + "m_Id": "f7b5dc0511224e8597b295ae31b079e8" + }, + { + "m_Id": "cdc2a37a66084667be8fa90fd47552a0" + }, + { + "m_Id": "11ebbe5ac2bc47918e9c37323e419f7a" + }, + { + "m_Id": "828d5b03117e4ec091f676889638d4be" + }, + { + "m_Id": "2d09cfbcb6d24c4f9c46dfe49d14b1f0" + }, + { + "m_Id": "006a0310de774ad9888bec215ae3fa75" + }, + { + "m_Id": "8f7b504968c94a8e97b294b8cf6817cf" + } + ], + "m_GroupDatas": [ + { + "m_Id": "826bd371d8994a52b649a0d87cc81f81" + }, + { + "m_Id": "761963ffa72d42e180a4200f889aa3bc" + } + ], + "m_StickyNoteDatas": [], + "m_Edges": [ + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "006a0310de774ad9888bec215ae3fa75" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "a6611900bc41403e8cadb05d29d07447" + }, + "m_SlotId": -1281716962 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "11ebbe5ac2bc47918e9c37323e419f7a" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "2ce12b55d78441a3aedf83368b0eaeb2" + }, + "m_SlotId": 0 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "2d09cfbcb6d24c4f9c46dfe49d14b1f0" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "a6611900bc41403e8cadb05d29d07447" + }, + "m_SlotId": -680323842 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "7e7f3c2a0a59469e9f8da0fef2c555ab" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "ce79319b1f18421c8a11de70d1616779" + }, + "m_SlotId": 0 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "828d5b03117e4ec091f676889638d4be" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "588955e76cd0400088929404da30207c" + }, + "m_SlotId": 0 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "8f7b504968c94a8e97b294b8cf6817cf" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "01d2d5ea9fbc4b179f32a0927a47c850" + }, + "m_SlotId": 0 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "921a017b3b77432f928fd08d62758430" + }, + "m_SlotId": 1 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "179a2a6df6064ef69f4aa621baad2d2e" + }, + "m_SlotId": 0 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "921a017b3b77432f928fd08d62758430" + }, + "m_SlotId": 2 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "579f39a209ac4a00be6e05f7b10e188c" + }, + "m_SlotId": 0 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "a6611900bc41403e8cadb05d29d07447" + }, + "m_SlotId": 1 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "7e7f3c2a0a59469e9f8da0fef2c555ab" + }, + "m_SlotId": 1 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "cdc2a37a66084667be8fa90fd47552a0" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "921a017b3b77432f928fd08d62758430" + }, + "m_SlotId": 1190027673 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "f7b5dc0511224e8597b295ae31b079e8" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "921a017b3b77432f928fd08d62758430" + }, + "m_SlotId": 1334702512 + } + } + ], + "m_VertexContext": { + "m_Position": { + "x": 0.0, + "y": 0.0 + }, + "m_Blocks": [ + { + "m_Id": "9f2fe456fc3b4ebb9a19c3045d7ca0db" + }, + { + "m_Id": "a878504fb615472bbc92981bc85f2022" + }, + { + "m_Id": "48602648207f44cba0b1494f9cde4496" + } + ] + }, + "m_FragmentContext": { + "m_Position": { + "x": 0.0, + "y": 200.0 + }, + "m_Blocks": [ + { + "m_Id": "179a2a6df6064ef69f4aa621baad2d2e" + }, + { + "m_Id": "e8449ac4440842089ed71d24ae1abbdc" + }, + { + "m_Id": "2ce12b55d78441a3aedf83368b0eaeb2" + }, + { + "m_Id": "588955e76cd0400088929404da30207c" + }, + { + "m_Id": "ce79319b1f18421c8a11de70d1616779" + }, + { + "m_Id": "02f2af5cbb1a45f9a0af7b0b4cdc862d" + }, + { + "m_Id": "579f39a209ac4a00be6e05f7b10e188c" + }, + { + "m_Id": "01d2d5ea9fbc4b179f32a0927a47c850" + } + ] + }, + "m_PreviewData": { + "serializedMesh": { + "m_SerializedMesh": "{\"mesh\":{\"instanceID\":0}}", + "m_Guid": "" + }, + "preventRotation": false + }, + "m_Path": "Rive/Built-in Render Pipeline", + "m_GraphPrecision": 1, + "m_PreviewMode": 2, + "m_OutputNode": { + "m_Id": "" + }, + "m_SubDatas": [], + "m_ActiveTargets": [ + { + "m_Id": "0e7c1f51af3f48cd9eec29075fed4974" + } + ] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.PropertyNode", + "m_ObjectId": "006a0310de774ad9888bec215ae3fa75", + "m_Group": { + "m_Id": "761963ffa72d42e180a4200f889aa3bc" + }, + "m_Name": "Property", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -1172.5, + "y": 682.0, + "width": 151.00006103515626, + "height": 34.0 + } + }, + "m_Slots": [ + { + "m_Id": "0f7829720fdb4f488b38729be88e5ab2" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_Property": { + "m_Id": "2a0fc11ff11745fbae58a8e255270113" + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "01d2d5ea9fbc4b179f32a0927a47c850", + "m_Group": { + "m_Id": "" + }, + "m_Name": "SurfaceDescription.AlphaClipThreshold", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "ba21ea3ac7184ac7934508c7644d50f9" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "SurfaceDescription.AlphaClipThreshold" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "02f2af5cbb1a45f9a0af7b0b4cdc862d", + "m_Group": { + "m_Id": "" + }, + "m_Name": "SurfaceDescription.Occlusion", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "cfa87eff0748450d848f35fa65cee7a5" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "SurfaceDescription.Occlusion" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector3MaterialSlot", + "m_ObjectId": "05d4cc6185954d34a644d234a88e432a", + "m_Id": 1, + "m_DisplayName": "Out_BaseColor", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out_BaseColor", + "m_StageCapability": 2, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 1, + "m_Type": "UnityEditor.ShaderGraph.Internal.Vector1ShaderProperty", + "m_ObjectId": "0b563b81796b44489ab147673a69538d", + "m_Guid": { + "m_GuidSerialized": "51187f8e-b3b7-4dee-84d9-503c4a4fd1df" + }, + "m_Name": "Cutoff", + "m_DefaultRefNameVersion": 1, + "m_RefNameGeneratedByDisplayName": "Cutoff", + "m_DefaultReferenceName": "_Cutoff", + "m_OverrideReferenceName": "", + "m_GeneratePropertyBlock": true, + "m_UseCustomSlotLabel": false, + "m_CustomSlotLabel": "", + "m_DismissedVersion": 0, + "m_Precision": 0, + "overrideHLSLDeclaration": false, + "hlslDeclarationOverride": 0, + "m_Hidden": false, + "m_Value": 0.5, + "m_FloatType": 1, + "m_RangeValues": { + "x": 0.0, + "y": 1.0 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "0c040165ab8a4d0b9b56ef516551b901", + "m_Id": 0, + "m_DisplayName": "Metallic", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out", + "m_StageCapability": 3, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 2, + "m_Type": "UnityEditor.Rendering.BuiltIn.ShaderGraph.BuiltInTarget", + "m_ObjectId": "0e7c1f51af3f48cd9eec29075fed4974", + "m_ActiveSubTarget": { + "m_Id": "194d445a943740fb8d358e46a7fda29d" + }, + "m_AllowMaterialOverride": true, + "m_SurfaceType": 1, + "m_ZWriteControl": 0, + "m_ZTestMode": 4, + "m_AlphaMode": 0, + "m_RenderFace": 2, + "m_AlphaClip": false, + "m_CustomEditorGUI": "" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector4MaterialSlot", + "m_ObjectId": "0f7829720fdb4f488b38729be88e5ab2", + "m_Id": 0, + "m_DisplayName": "EmissionColor", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out", + "m_StageCapability": 3, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.PropertyNode", + "m_ObjectId": "11ebbe5ac2bc47918e9c37323e419f7a", + "m_Group": { + "m_Id": "" + }, + "m_Name": "Property", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -604.1569213867188, + "y": 293.6661376953125, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "0c040165ab8a4d0b9b56ef516551b901" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_Property": { + "m_Id": "e540e490b602446c82e9bc1e1de48847" + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector4MaterialSlot", + "m_ObjectId": "121e4df78be441dea07c0e2b2a2863bb", + "m_Id": 0, + "m_DisplayName": "BaseColor", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out", + "m_StageCapability": 3, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "179a2a6df6064ef69f4aa621baad2d2e", + "m_Group": { + "m_Id": "" + }, + "m_Name": "SurfaceDescription.BaseColor", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "1ea7d6272fed4651b5ffbf5c2c55dfab" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "SurfaceDescription.BaseColor" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.NormalMaterialSlot", + "m_ObjectId": "18bfde8172d449f5b47af1d451333d37", + "m_Id": 0, + "m_DisplayName": "Normal", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Normal", + "m_StageCapability": 1, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [], + "m_Space": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.Rendering.BuiltIn.ShaderGraph.BuiltInLitSubTarget", + "m_ObjectId": "194d445a943740fb8d358e46a7fda29d", + "m_WorkflowMode": 1, + "m_NormalDropOffSpace": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.ColorRGBMaterialSlot", + "m_ObjectId": "1ea7d6272fed4651b5ffbf5c2c55dfab", + "m_Id": 0, + "m_DisplayName": "Base Color", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "BaseColor", + "m_StageCapability": 2, + "m_Value": { + "x": 0.5, + "y": 0.5, + "z": 0.5 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [], + "m_ColorMode": 0, + "m_DefaultColor": { + "r": 0.5, + "g": 0.5, + "b": 0.5, + "a": 1.0 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.ColorRGBMaterialSlot", + "m_ObjectId": "289471af076c4276ae3beaafae636092", + "m_Id": 0, + "m_DisplayName": "Emission", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Emission", + "m_StageCapability": 2, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [], + "m_ColorMode": 1, + "m_DefaultColor": { + "r": 0.0, + "g": 0.0, + "b": 0.0, + "a": 1.0 + } +} + +{ + "m_SGVersion": 3, + "m_Type": "UnityEditor.ShaderGraph.Internal.ColorShaderProperty", + "m_ObjectId": "2a0fc11ff11745fbae58a8e255270113", + "m_Guid": { + "m_GuidSerialized": "e8d32507-0585-4165-b689-0e786c71e23b" + }, + "m_Name": "EmissionColor", + "m_DefaultRefNameVersion": 1, + "m_RefNameGeneratedByDisplayName": "EmissionColor", + "m_DefaultReferenceName": "_EmissionColor", + "m_OverrideReferenceName": "", + "m_GeneratePropertyBlock": true, + "m_UseCustomSlotLabel": false, + "m_CustomSlotLabel": "", + "m_DismissedVersion": 0, + "m_Precision": 0, + "overrideHLSLDeclaration": false, + "hlslDeclarationOverride": 0, + "m_Hidden": false, + "m_Value": { + "r": 0.0, + "g": 0.0, + "b": 0.0, + "a": 0.003921568859368563 + }, + "isMainColor": false, + "m_ColorMode": 1 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "2ce12b55d78441a3aedf83368b0eaeb2", + "m_Group": { + "m_Id": "" + }, + "m_Name": "SurfaceDescription.Metallic", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "667c15a82a8e4e47bc5199734b658eb2" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "SurfaceDescription.Metallic" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.PropertyNode", + "m_ObjectId": "2d09cfbcb6d24c4f9c46dfe49d14b1f0", + "m_Group": { + "m_Id": "761963ffa72d42e180a4200f889aa3bc" + }, + "m_Name": "Property", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -1174.0, + "y": 741.5, + "width": 152.50006103515626, + "height": 34.0 + } + }, + "m_Slots": [ + { + "m_Id": "8a970bd9737d4c70916e16b6c72cb006" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_Property": { + "m_Id": "81ca8a168f9c4e17b490fd23d29bfec5" + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector4MaterialSlot", + "m_ObjectId": "3ba6c8a698ea4f12a219a246a6a083ed", + "m_Id": 1190027673, + "m_DisplayName": "BaseColor", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "_BaseColor", + "m_StageCapability": 2, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.DynamicVectorMaterialSlot", + "m_ObjectId": "40a90148709b43efa6ac0f7d241361d0", + "m_Id": 0, + "m_DisplayName": "Out", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out", + "m_StageCapability": 3, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "4700f29aea044a02b8c70d154263a580", + "m_Id": 0, + "m_DisplayName": "Cutoff", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out", + "m_StageCapability": 3, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "48602648207f44cba0b1494f9cde4496", + "m_Group": { + "m_Id": "" + }, + "m_Name": "VertexDescription.Tangent", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "c4b0c725d82342c49111724fea52551d" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "VertexDescription.Tangent" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.CategoryData", + "m_ObjectId": "48d1691978ed405387844998eb582a38", + "m_Name": "", + "m_ChildObjectList": [ + { + "m_Id": "a0a1a7b3ccf149bf9fab4f25cbf04621" + }, + { + "m_Id": "d09ad266770042b783f41774f95255a0" + }, + { + "m_Id": "c639c3809c6f4963b3aa7422aa39259f" + }, + { + "m_Id": "e540e490b602446c82e9bc1e1de48847" + }, + { + "m_Id": "8c2ee6de8ac44969afc807897aec8963" + }, + { + "m_Id": "81ca8a168f9c4e17b490fd23d29bfec5" + }, + { + "m_Id": "2a0fc11ff11745fbae58a8e255270113" + }, + { + "m_Id": "0b563b81796b44489ab147673a69538d" + } + ] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "4c936cb861624b99946a5c431d1d115a", + "m_Id": 2, + "m_DisplayName": "Out_Alpha", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out_Alpha", + "m_StageCapability": 2, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "579f39a209ac4a00be6e05f7b10e188c", + "m_Group": { + "m_Id": "" + }, + "m_Name": "SurfaceDescription.Alpha", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "e41f1e9b5e9d4085807c5eb3a1a808cd" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "SurfaceDescription.Alpha" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "588955e76cd0400088929404da30207c", + "m_Group": { + "m_Id": "" + }, + "m_Name": "SurfaceDescription.Smoothness", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "d89f2f3643754337a808610951ebe432" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "SurfaceDescription.Smoothness" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector4MaterialSlot", + "m_ObjectId": "5d81a64da39b4e9c97762e3bcddabf93", + "m_Id": -1281716962, + "m_DisplayName": "EmissionColor", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "_EmissionColor", + "m_StageCapability": 2, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "667c15a82a8e4e47bc5199734b658eb2", + "m_Id": 0, + "m_DisplayName": "Metallic", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Metallic", + "m_StageCapability": 2, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.GroupData", + "m_ObjectId": "761963ffa72d42e180a4200f889aa3bc", + "m_Title": "Emission", + "m_Position": { + "x": -1199.0, + "y": 470.5 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.NormalMaterialSlot", + "m_ObjectId": "7c9be3cac93f459d9bb1a415e2923cd7", + "m_Id": 0, + "m_DisplayName": "Normal (Tangent Space)", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "NormalTS", + "m_StageCapability": 2, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [], + "m_Space": 3 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.KeywordNode", + "m_ObjectId": "7e7f3c2a0a59469e9f8da0fef2c555ab", + "m_Group": { + "m_Id": "761963ffa72d42e180a4200f889aa3bc" + }, + "m_Name": "Emission", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -423.0, + "y": 592.5, + "width": 208.0, + "height": 302.0 + } + }, + "m_Slots": [ + { + "m_Id": "40a90148709b43efa6ac0f7d241361d0" + }, + { + "m_Id": "cb011b3461d948eb89b7eeb2d4bf56e5" + }, + { + "m_Id": "9c7fab440f5847eeb2d0b35822d207eb" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_Keyword": { + "m_Id": "d09ad266770042b783f41774f95255a0" + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Internal.Texture2DShaderProperty", + "m_ObjectId": "81ca8a168f9c4e17b490fd23d29bfec5", + "m_Guid": { + "m_GuidSerialized": "28fd325d-a234-49df-a1af-5a626526e80a" + }, + "m_Name": "EmissionMap", + "m_DefaultRefNameVersion": 1, + "m_RefNameGeneratedByDisplayName": "EmissionMap", + "m_DefaultReferenceName": "_EmissionMap", + "m_OverrideReferenceName": "", + "m_GeneratePropertyBlock": true, + "m_UseCustomSlotLabel": false, + "m_CustomSlotLabel": "", + "m_DismissedVersion": 0, + "m_Precision": 0, + "overrideHLSLDeclaration": false, + "hlslDeclarationOverride": 0, + "m_Hidden": false, + "m_Value": { + "m_SerializedTexture": "{\"texture\":{\"instanceID\":0}}", + "m_Guid": "" + }, + "isMainTexture": false, + "useTilingAndOffset": false, + "m_Modifiable": true, + "m_DefaultType": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.GroupData", + "m_ObjectId": "826bd371d8994a52b649a0d87cc81f81", + "m_Title": "Main Texture", + "m_Position": { + "x": -869.0000610351563, + "y": -207.50006103515626 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.PropertyNode", + "m_ObjectId": "828d5b03117e4ec091f676889638d4be", + "m_Group": { + "m_Id": "" + }, + "m_Name": "Property", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -588.86181640625, + "y": 373.20074462890627, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "8edd7013382d494d903e596c1bcbfd7d" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_Property": { + "m_Id": "8c2ee6de8ac44969afc807897aec8963" + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Texture2DMaterialSlot", + "m_ObjectId": "8a970bd9737d4c70916e16b6c72cb006", + "m_Id": 0, + "m_DisplayName": "EmissionMap", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out", + "m_StageCapability": 3, + "m_BareResource": false +} + +{ + "m_SGVersion": 1, + "m_Type": "UnityEditor.ShaderGraph.Internal.Vector1ShaderProperty", + "m_ObjectId": "8c2ee6de8ac44969afc807897aec8963", + "m_Guid": { + "m_GuidSerialized": "480fa37f-3add-4a10-b636-e16d827e803e" + }, + "m_Name": "Smoothness", + "m_DefaultRefNameVersion": 1, + "m_RefNameGeneratedByDisplayName": "Smoothness", + "m_DefaultReferenceName": "_Smoothness", + "m_OverrideReferenceName": "", + "m_GeneratePropertyBlock": true, + "m_UseCustomSlotLabel": false, + "m_CustomSlotLabel": "", + "m_DismissedVersion": 0, + "m_Precision": 0, + "overrideHLSLDeclaration": false, + "hlslDeclarationOverride": 0, + "m_Hidden": false, + "m_Value": 0.0, + "m_FloatType": 1, + "m_RangeValues": { + "x": 0.0, + "y": 1.0 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "8edd7013382d494d903e596c1bcbfd7d", + "m_Id": 0, + "m_DisplayName": "Smoothness", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out", + "m_StageCapability": 3, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.PropertyNode", + "m_ObjectId": "8f7b504968c94a8e97b294b8cf6817cf", + "m_Group": { + "m_Id": "" + }, + "m_Name": "Property", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -299.7841796875, + "y": 490.97308349609377, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "4700f29aea044a02b8c70d154263a580" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_Property": { + "m_Id": "0b563b81796b44489ab147673a69538d" + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.SubGraphNode", + "m_ObjectId": "921a017b3b77432f928fd08d62758430", + "m_Group": { + "m_Id": "826bd371d8994a52b649a0d87cc81f81" + }, + "m_Name": "SampleMainRiveTexture", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -511.499755859375, + "y": -149.000244140625, + "width": 235.499755859375, + "height": 303.000244140625 + } + }, + "m_Slots": [ + { + "m_Id": "c589a8d6f4b24aa0b7c804c6b193def3" + }, + { + "m_Id": "3ba6c8a698ea4f12a219a246a6a083ed" + }, + { + "m_Id": "05d4cc6185954d34a644d234a88e432a" + }, + { + "m_Id": "4c936cb861624b99946a5c431d1d115a" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedSubGraph": "{\n \"subGraph\": {\n \"fileID\": -5475051401550479605,\n \"guid\": \"287ae8d259edf47cf9ec073950debe11\",\n \"type\": 3\n }\n}", + "m_PropertyGuids": [ + "4b65a152-6b9e-429e-bbc1-bebac7fac8fc", + "0dafdea0-1c0d-40c7-9a2f-3553ae8cb358" + ], + "m_PropertyIds": [ + 1334702512, + 1190027673 + ], + "m_Dropdowns": [], + "m_DropdownSelectedEntries": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.DynamicVectorMaterialSlot", + "m_ObjectId": "9c7fab440f5847eeb2d0b35822d207eb", + "m_Id": 2, + "m_DisplayName": "Off", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Off", + "m_StageCapability": 3, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "9f2fe456fc3b4ebb9a19c3045d7ca0db", + "m_Group": { + "m_Id": "" + }, + "m_Name": "VertexDescription.Position", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "c98289edea1f4376acc039d24722b2e7" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "VertexDescription.Position" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Texture2DInputMaterialSlot", + "m_ObjectId": "9f7387dc94e34e5b8d048abd47f23d46", + "m_Id": -680323842, + "m_DisplayName": "EmissionMap", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "_EmissionMap", + "m_StageCapability": 2, + "m_BareResource": false, + "m_Texture": { + "m_SerializedTexture": "{\"texture\":{\"instanceID\":0}}", + "m_Guid": "" + }, + "m_DefaultType": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Internal.Texture2DShaderProperty", + "m_ObjectId": "a0a1a7b3ccf149bf9fab4f25cbf04621", + "m_Guid": { + "m_GuidSerialized": "e2244111-b527-4244-935b-34e6f93b48bb" + }, + "m_Name": "BaseMap", + "m_DefaultRefNameVersion": 1, + "m_RefNameGeneratedByDisplayName": "BaseMap", + "m_DefaultReferenceName": "_BaseMap", + "m_OverrideReferenceName": "", + "m_GeneratePropertyBlock": true, + "m_UseCustomSlotLabel": false, + "m_CustomSlotLabel": "", + "m_DismissedVersion": 0, + "m_Precision": 0, + "overrideHLSLDeclaration": false, + "hlslDeclarationOverride": 2, + "m_Hidden": false, + "m_Value": { + "m_SerializedTexture": "{\"texture\":{\"instanceID\":0}}", + "m_Guid": "" + }, + "isMainTexture": true, + "useTilingAndOffset": true, + "m_Modifiable": true, + "m_DefaultType": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector4MaterialSlot", + "m_ObjectId": "a1ef5bc5ae234dd297818a83f7f7e80e", + "m_Id": 1, + "m_DisplayName": "Out_Emission", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out_Emission", + "m_StageCapability": 2, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.SubGraphNode", + "m_ObjectId": "a6611900bc41403e8cadb05d29d07447", + "m_Group": { + "m_Id": "761963ffa72d42e180a4200f889aa3bc" + }, + "m_Name": "SampleEmission", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -944.4998779296875, + "y": 591.5, + "width": 248.4998779296875, + "height": 303.0 + } + }, + "m_Slots": [ + { + "m_Id": "5d81a64da39b4e9c97762e3bcddabf93" + }, + { + "m_Id": "9f7387dc94e34e5b8d048abd47f23d46" + }, + { + "m_Id": "a1ef5bc5ae234dd297818a83f7f7e80e" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedSubGraph": "{\n \"subGraph\": {\n \"fileID\": -5475051401550479605,\n \"guid\": \"c3bbcf1d5b5ee446baa01a87b8e5dadf\",\n \"type\": 3\n }\n}", + "m_PropertyGuids": [ + "417ee71e-80a1-414f-b809-df8c19e3743f", + "9fae8bf3-f659-4d48-8efb-5f8bda92ca8e", + "0d74976b-fbf8-4395-8137-14c541e8d2c5" + ], + "m_PropertyIds": [ + -1281716962, + -680323842, + 1311224659 + ], + "m_Dropdowns": [], + "m_DropdownSelectedEntries": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "a878504fb615472bbc92981bc85f2022", + "m_Group": { + "m_Id": "" + }, + "m_Name": "VertexDescription.Normal", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "18bfde8172d449f5b47af1d451333d37" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "VertexDescription.Normal" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "ba21ea3ac7184ac7934508c7644d50f9", + "m_Id": 0, + "m_DisplayName": "Alpha Clip Threshold", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "AlphaClipThreshold", + "m_StageCapability": 2, + "m_Value": 0.5, + "m_DefaultValue": 0.5, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.TangentMaterialSlot", + "m_ObjectId": "c4b0c725d82342c49111724fea52551d", + "m_Id": 0, + "m_DisplayName": "Tangent", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Tangent", + "m_StageCapability": 1, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [], + "m_Space": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Texture2DInputMaterialSlot", + "m_ObjectId": "c589a8d6f4b24aa0b7c804c6b193def3", + "m_Id": 1334702512, + "m_DisplayName": "BaseMap", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "_BaseMap", + "m_StageCapability": 2, + "m_BareResource": false, + "m_Texture": { + "m_SerializedTexture": "{\"texture\":{\"instanceID\":0}}", + "m_Guid": "" + }, + "m_DefaultType": 0 +} + +{ + "m_SGVersion": 3, + "m_Type": "UnityEditor.ShaderGraph.Internal.ColorShaderProperty", + "m_ObjectId": "c639c3809c6f4963b3aa7422aa39259f", + "m_Guid": { + "m_GuidSerialized": "9c3e2468-d461-4d5b-8d76-738adef1932e" + }, + "m_Name": "BaseColor", + "m_DefaultRefNameVersion": 1, + "m_RefNameGeneratedByDisplayName": "BaseColor", + "m_DefaultReferenceName": "_BaseColor", + "m_OverrideReferenceName": "", + "m_GeneratePropertyBlock": true, + "m_UseCustomSlotLabel": false, + "m_CustomSlotLabel": "", + "m_DismissedVersion": 0, + "m_Precision": 0, + "overrideHLSLDeclaration": false, + "hlslDeclarationOverride": 0, + "m_Hidden": false, + "m_Value": { + "r": 1.0, + "g": 1.0, + "b": 1.0, + "a": 1.0 + }, + "isMainColor": true, + "m_ColorMode": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.PositionMaterialSlot", + "m_ObjectId": "c98289edea1f4376acc039d24722b2e7", + "m_Id": 0, + "m_DisplayName": "Position", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Position", + "m_StageCapability": 1, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [], + "m_Space": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Texture2DMaterialSlot", + "m_ObjectId": "cae82917714d408ea6e91e8f60e4cc45", + "m_Id": 0, + "m_DisplayName": "BaseMap", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out", + "m_StageCapability": 3, + "m_BareResource": false +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.DynamicVectorMaterialSlot", + "m_ObjectId": "cb011b3461d948eb89b7eeb2d4bf56e5", + "m_Id": 1, + "m_DisplayName": "On", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "On", + "m_StageCapability": 3, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.PropertyNode", + "m_ObjectId": "cdc2a37a66084667be8fa90fd47552a0", + "m_Group": { + "m_Id": "826bd371d8994a52b649a0d87cc81f81" + }, + "m_Name": "Property", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -842.5000610351563, + "y": -34.0, + "width": 135.5001220703125, + "height": 34.0 + } + }, + "m_Slots": [ + { + "m_Id": "121e4df78be441dea07c0e2b2a2863bb" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_Property": { + "m_Id": "c639c3809c6f4963b3aa7422aa39259f" + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "ce79319b1f18421c8a11de70d1616779", + "m_Group": { + "m_Id": "" + }, + "m_Name": "SurfaceDescription.Emission", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "289471af076c4276ae3beaafae636092" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "SurfaceDescription.Emission" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "cfa87eff0748450d848f35fa65cee7a5", + "m_Id": 0, + "m_DisplayName": "Ambient Occlusion", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Occlusion", + "m_StageCapability": 2, + "m_Value": 1.0, + "m_DefaultValue": 1.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 1, + "m_Type": "UnityEditor.ShaderGraph.ShaderKeyword", + "m_ObjectId": "d09ad266770042b783f41774f95255a0", + "m_Guid": { + "m_GuidSerialized": "ddac7e60-c11c-4f06-9c65-e06890571cc5" + }, + "m_Name": "Emission", + "m_DefaultRefNameVersion": 1, + "m_RefNameGeneratedByDisplayName": "Emission", + "m_DefaultReferenceName": "_EMISSION", + "m_OverrideReferenceName": "_USE_EMISSION_ON", + "m_GeneratePropertyBlock": true, + "m_UseCustomSlotLabel": false, + "m_CustomSlotLabel": "", + "m_DismissedVersion": 0, + "m_KeywordType": 0, + "m_KeywordDefinition": 0, + "m_KeywordScope": 0, + "m_KeywordStages": 63, + "m_Entries": [], + "m_Value": 0, + "m_IsEditable": true +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "d89f2f3643754337a808610951ebe432", + "m_Id": 0, + "m_DisplayName": "Smoothness", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Smoothness", + "m_StageCapability": 2, + "m_Value": 0.5, + "m_DefaultValue": 0.5, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "e41f1e9b5e9d4085807c5eb3a1a808cd", + "m_Id": 0, + "m_DisplayName": "Alpha", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Alpha", + "m_StageCapability": 2, + "m_Value": 1.0, + "m_DefaultValue": 1.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 1, + "m_Type": "UnityEditor.ShaderGraph.Internal.Vector1ShaderProperty", + "m_ObjectId": "e540e490b602446c82e9bc1e1de48847", + "m_Guid": { + "m_GuidSerialized": "a23e5e78-799d-49d7-b847-f5f1b66d6682" + }, + "m_Name": "Metallic", + "m_DefaultRefNameVersion": 1, + "m_RefNameGeneratedByDisplayName": "Metallic", + "m_DefaultReferenceName": "_Metallic", + "m_OverrideReferenceName": "", + "m_GeneratePropertyBlock": true, + "m_UseCustomSlotLabel": false, + "m_CustomSlotLabel": "", + "m_DismissedVersion": 0, + "m_Precision": 0, + "overrideHLSLDeclaration": false, + "hlslDeclarationOverride": 0, + "m_Hidden": false, + "m_Value": 0.0, + "m_FloatType": 1, + "m_RangeValues": { + "x": 0.0, + "y": 1.0 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "e8449ac4440842089ed71d24ae1abbdc", + "m_Group": { + "m_Id": "" + }, + "m_Name": "SurfaceDescription.NormalTS", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "7c9be3cac93f459d9bb1a415e2923cd7" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "SurfaceDescription.NormalTS" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.PropertyNode", + "m_ObjectId": "f7b5dc0511224e8597b295ae31b079e8", + "m_Group": { + "m_Id": "826bd371d8994a52b649a0d87cc81f81" + }, + "m_Name": "Property", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -844.0000610351563, + "y": -97.5, + "width": 137.0001220703125, + "height": 34.0 + } + }, + "m_Slots": [ + { + "m_Id": "cae82917714d408ea6e91e8f60e4cc45" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_Property": { + "m_Id": "a0a1a7b3ccf149bf9fab4f25cbf04621" + } +} + diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/BuiltIn/Shaders/Lit.shadergraph.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/BuiltIn/Shaders/Lit.shadergraph.meta new file mode 100644 index 00000000..2b269c6f --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/BuiltIn/Shaders/Lit.shadergraph.meta @@ -0,0 +1,17 @@ +fileFormatVersion: 2 +guid: 3c4ae610ec7364aec894036ae7cb69e2 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: 625f186215c104763be7675aa2d941aa, type: 3} +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/BuiltIn/Shaders/Lit.shadergraph + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/BuiltIn/Shaders/Unlit.shadergraph b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/BuiltIn/Shaders/Unlit.shadergraph new file mode 100644 index 00000000..52f13a15 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/BuiltIn/Shaders/Unlit.shadergraph @@ -0,0 +1,958 @@ +{ + "m_SGVersion": 3, + "m_Type": "UnityEditor.ShaderGraph.GraphData", + "m_ObjectId": "9b7e820c8778486bada5a35a290ebcea", + "m_Properties": [ + { + "m_Id": "b7bab3dda7164dbda50965ea6bd957bc" + }, + { + "m_Id": "fc4e9a78e2e6410cabad64694fcf4962" + }, + { + "m_Id": "8a69ae393a41469db98f604c6177995a" + } + ], + "m_Keywords": [], + "m_Dropdowns": [], + "m_CategoryData": [ + { + "m_Id": "2d378862b56749e4a4e2e13d2d13a5f2" + } + ], + "m_Nodes": [ + { + "m_Id": "5a7cda9650144ecc87df3bd450be9f2a" + }, + { + "m_Id": "7443ee7d7aa44d4bbdb398b6fa6629cb" + }, + { + "m_Id": "f6ddf963776344e098ca59b7d58e7e15" + }, + { + "m_Id": "434538ea5bf64b9d946302b35349766d" + }, + { + "m_Id": "8de34b4a4e804f25bc79cb9ddca9b0a7" + }, + { + "m_Id": "95616170b52d463991eff0eee9a4faf2" + }, + { + "m_Id": "09e795084a984a1fb79d8582556054c0" + }, + { + "m_Id": "271c2b0440e74b30a77a8aa41e6cb8b2" + }, + { + "m_Id": "a71d9d75d29a49238858bae25d2f0b53" + }, + { + "m_Id": "aed28144c3e746c19c068b407dbad670" + } + ], + "m_GroupDatas": [ + { + "m_Id": "a10ffd04f0be43c5a4ea562ecf38d040" + } + ], + "m_StickyNoteDatas": [], + "m_Edges": [ + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "271c2b0440e74b30a77a8aa41e6cb8b2" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "8de34b4a4e804f25bc79cb9ddca9b0a7" + }, + "m_SlotId": 1334702512 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "8de34b4a4e804f25bc79cb9ddca9b0a7" + }, + "m_SlotId": 1 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "434538ea5bf64b9d946302b35349766d" + }, + "m_SlotId": 0 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "8de34b4a4e804f25bc79cb9ddca9b0a7" + }, + "m_SlotId": 2 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "95616170b52d463991eff0eee9a4faf2" + }, + "m_SlotId": 0 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "a71d9d75d29a49238858bae25d2f0b53" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "8de34b4a4e804f25bc79cb9ddca9b0a7" + }, + "m_SlotId": 1190027673 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "aed28144c3e746c19c068b407dbad670" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "09e795084a984a1fb79d8582556054c0" + }, + "m_SlotId": 0 + } + } + ], + "m_VertexContext": { + "m_Position": { + "x": 0.0, + "y": 0.0 + }, + "m_Blocks": [ + { + "m_Id": "5a7cda9650144ecc87df3bd450be9f2a" + }, + { + "m_Id": "7443ee7d7aa44d4bbdb398b6fa6629cb" + }, + { + "m_Id": "f6ddf963776344e098ca59b7d58e7e15" + } + ] + }, + "m_FragmentContext": { + "m_Position": { + "x": 0.0, + "y": 200.0 + }, + "m_Blocks": [ + { + "m_Id": "434538ea5bf64b9d946302b35349766d" + }, + { + "m_Id": "95616170b52d463991eff0eee9a4faf2" + }, + { + "m_Id": "09e795084a984a1fb79d8582556054c0" + } + ] + }, + "m_PreviewData": { + "serializedMesh": { + "m_SerializedMesh": "{\"mesh\":{\"instanceID\":0}}", + "m_Guid": "" + }, + "preventRotation": false + }, + "m_Path": "Rive/Built-in Render Pipeline", + "m_GraphPrecision": 1, + "m_PreviewMode": 2, + "m_OutputNode": { + "m_Id": "" + }, + "m_SubDatas": [], + "m_ActiveTargets": [ + { + "m_Id": "03c202ba004b4f45a520b349e6a21b33" + } + ] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Texture2DMaterialSlot", + "m_ObjectId": "01770f048f0043c28acf7aeca697e75f", + "m_Id": 0, + "m_DisplayName": "BaseMap", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out", + "m_StageCapability": 3, + "m_BareResource": false +} + +{ + "m_SGVersion": 2, + "m_Type": "UnityEditor.Rendering.BuiltIn.ShaderGraph.BuiltInTarget", + "m_ObjectId": "03c202ba004b4f45a520b349e6a21b33", + "m_ActiveSubTarget": { + "m_Id": "2bd35b25e1e54b7198040a4bc91059a6" + }, + "m_AllowMaterialOverride": true, + "m_SurfaceType": 1, + "m_ZWriteControl": 0, + "m_ZTestMode": 4, + "m_AlphaMode": 0, + "m_RenderFace": 2, + "m_AlphaClip": false, + "m_CustomEditorGUI": "" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "09e795084a984a1fb79d8582556054c0", + "m_Group": { + "m_Id": "" + }, + "m_Name": "SurfaceDescription.AlphaClipThreshold", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "9aea1fa6e08e4385a03179f3fba903f8" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "SurfaceDescription.AlphaClipThreshold" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Texture2DInputMaterialSlot", + "m_ObjectId": "187c41dab86149959a55e0e9c70fb58e", + "m_Id": 1334702512, + "m_DisplayName": "BaseMap", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "_BaseMap", + "m_StageCapability": 2, + "m_BareResource": false, + "m_Texture": { + "m_SerializedTexture": "{\"texture\":{\"instanceID\":0}}", + "m_Guid": "" + }, + "m_DefaultType": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.PropertyNode", + "m_ObjectId": "271c2b0440e74b30a77a8aa41e6cb8b2", + "m_Group": { + "m_Id": "a10ffd04f0be43c5a4ea562ecf38d040" + }, + "m_Name": "Property", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -748.9999389648438, + "y": -33.999969482421878, + "width": 131.99993896484376, + "height": 33.999969482421878 + } + }, + "m_Slots": [ + { + "m_Id": "01770f048f0043c28acf7aeca697e75f" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_Property": { + "m_Id": "8a69ae393a41469db98f604c6177995a" + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector4MaterialSlot", + "m_ObjectId": "2b19f293ab424c55b9eb70a04aa4cd30", + "m_Id": 0, + "m_DisplayName": "BaseColor", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out", + "m_StageCapability": 3, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.Rendering.BuiltIn.ShaderGraph.BuiltInUnlitSubTarget", + "m_ObjectId": "2bd35b25e1e54b7198040a4bc91059a6" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.CategoryData", + "m_ObjectId": "2d378862b56749e4a4e2e13d2d13a5f2", + "m_Name": "", + "m_ChildObjectList": [ + { + "m_Id": "8a69ae393a41469db98f604c6177995a" + }, + { + "m_Id": "fc4e9a78e2e6410cabad64694fcf4962" + }, + { + "m_Id": "b7bab3dda7164dbda50965ea6bd957bc" + } + ] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "42005a4f0add4b2bb6de3608381aac9e", + "m_Id": 0, + "m_DisplayName": "Cutoff", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out", + "m_StageCapability": 3, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "434538ea5bf64b9d946302b35349766d", + "m_Group": { + "m_Id": "" + }, + "m_Name": "SurfaceDescription.BaseColor", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "e666458e83ff46bf8911145101f34380" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "SurfaceDescription.BaseColor" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "457c94e6ad02406185e8fbff53b73917", + "m_Id": 2, + "m_DisplayName": "Out_Alpha", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out_Alpha", + "m_StageCapability": 2, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "4c17d675c3634602819e2a3abee0b02f", + "m_Id": 0, + "m_DisplayName": "Alpha", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Alpha", + "m_StageCapability": 2, + "m_Value": 1.0, + "m_DefaultValue": 1.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.PositionMaterialSlot", + "m_ObjectId": "5843253a305d45eca4db99b957b4d3a6", + "m_Id": 0, + "m_DisplayName": "Position", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Position", + "m_StageCapability": 1, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [], + "m_Space": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "5a7cda9650144ecc87df3bd450be9f2a", + "m_Group": { + "m_Id": "" + }, + "m_Name": "VertexDescription.Position", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "5843253a305d45eca4db99b957b4d3a6" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "VertexDescription.Position" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "7443ee7d7aa44d4bbdb398b6fa6629cb", + "m_Group": { + "m_Id": "" + }, + "m_Name": "VertexDescription.Normal", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "b0185323536d40069d31721b9159de91" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "VertexDescription.Normal" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector3MaterialSlot", + "m_ObjectId": "7c91e69fd44c429da3bc8221dd13e1c3", + "m_Id": 1, + "m_DisplayName": "Out_BaseColor", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out_BaseColor", + "m_StageCapability": 2, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Internal.Texture2DShaderProperty", + "m_ObjectId": "8a69ae393a41469db98f604c6177995a", + "m_Guid": { + "m_GuidSerialized": "9f4b34c8-dbe8-4a08-8cec-2338ff65d947" + }, + "m_Name": "BaseMap", + "m_DefaultRefNameVersion": 1, + "m_RefNameGeneratedByDisplayName": "BaseMap", + "m_DefaultReferenceName": "_BaseMap", + "m_OverrideReferenceName": "", + "m_GeneratePropertyBlock": true, + "m_UseCustomSlotLabel": false, + "m_CustomSlotLabel": "", + "m_DismissedVersion": 0, + "m_Precision": 0, + "overrideHLSLDeclaration": false, + "hlslDeclarationOverride": 2, + "m_Hidden": false, + "m_Value": { + "m_SerializedTexture": "{\"texture\":{\"instanceID\":0}}", + "m_Guid": "" + }, + "isMainTexture": true, + "useTilingAndOffset": true, + "m_Modifiable": true, + "m_DefaultType": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.SubGraphNode", + "m_ObjectId": "8de34b4a4e804f25bc79cb9ddca9b0a7", + "m_Group": { + "m_Id": "a10ffd04f0be43c5a4ea562ecf38d040" + }, + "m_Name": "SampleMainRiveTexture", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -416.50006103515627, + "y": -63.0, + "width": 235.50006103515626, + "height": 303.0 + } + }, + "m_Slots": [ + { + "m_Id": "187c41dab86149959a55e0e9c70fb58e" + }, + { + "m_Id": "c05d9dad6a4841e9bb9a10390c3f644b" + }, + { + "m_Id": "7c91e69fd44c429da3bc8221dd13e1c3" + }, + { + "m_Id": "457c94e6ad02406185e8fbff53b73917" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedSubGraph": "{\n \"subGraph\": {\n \"fileID\": -5475051401550479605,\n \"guid\": \"287ae8d259edf47cf9ec073950debe11\",\n \"type\": 3\n }\n}", + "m_PropertyGuids": [ + "4b65a152-6b9e-429e-bbc1-bebac7fac8fc", + "0dafdea0-1c0d-40c7-9a2f-3553ae8cb358" + ], + "m_PropertyIds": [ + 1334702512, + 1190027673 + ], + "m_Dropdowns": [], + "m_DropdownSelectedEntries": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "95616170b52d463991eff0eee9a4faf2", + "m_Group": { + "m_Id": "" + }, + "m_Name": "SurfaceDescription.Alpha", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "4c17d675c3634602819e2a3abee0b02f" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "SurfaceDescription.Alpha" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "9aea1fa6e08e4385a03179f3fba903f8", + "m_Id": 0, + "m_DisplayName": "Alpha Clip Threshold", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "AlphaClipThreshold", + "m_StageCapability": 2, + "m_Value": 0.5, + "m_DefaultValue": 0.5, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.GroupData", + "m_ObjectId": "a10ffd04f0be43c5a4ea562ecf38d040", + "m_Title": "Main Texture", + "m_Position": { + "x": -773.9999389648438, + "y": -121.5 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.PropertyNode", + "m_ObjectId": "a71d9d75d29a49238858bae25d2f0b53", + "m_Group": { + "m_Id": "a10ffd04f0be43c5a4ea562ecf38d040" + }, + "m_Name": "Property", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -747.4999389648438, + "y": 23.0, + "width": 130.49993896484376, + "height": 34.0 + } + }, + "m_Slots": [ + { + "m_Id": "2b19f293ab424c55b9eb70a04aa4cd30" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_Property": { + "m_Id": "fc4e9a78e2e6410cabad64694fcf4962" + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.PropertyNode", + "m_ObjectId": "aed28144c3e746c19c068b407dbad670", + "m_Group": { + "m_Id": "" + }, + "m_Name": "Property", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -377.02886962890627, + "y": 321.515380859375, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "42005a4f0add4b2bb6de3608381aac9e" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_Property": { + "m_Id": "b7bab3dda7164dbda50965ea6bd957bc" + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.NormalMaterialSlot", + "m_ObjectId": "b0185323536d40069d31721b9159de91", + "m_Id": 0, + "m_DisplayName": "Normal", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Normal", + "m_StageCapability": 1, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [], + "m_Space": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.TangentMaterialSlot", + "m_ObjectId": "b0eb90f131844c248182c144dab2f9a2", + "m_Id": 0, + "m_DisplayName": "Tangent", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Tangent", + "m_StageCapability": 1, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [], + "m_Space": 0 +} + +{ + "m_SGVersion": 1, + "m_Type": "UnityEditor.ShaderGraph.Internal.Vector1ShaderProperty", + "m_ObjectId": "b7bab3dda7164dbda50965ea6bd957bc", + "m_Guid": { + "m_GuidSerialized": "4544524f-8687-4811-b671-a8eeaa66f239" + }, + "m_Name": "Cutoff", + "m_DefaultRefNameVersion": 1, + "m_RefNameGeneratedByDisplayName": "Cutoff", + "m_DefaultReferenceName": "_Cutoff", + "m_OverrideReferenceName": "", + "m_GeneratePropertyBlock": true, + "m_UseCustomSlotLabel": false, + "m_CustomSlotLabel": "", + "m_DismissedVersion": 0, + "m_Precision": 0, + "overrideHLSLDeclaration": false, + "hlslDeclarationOverride": 0, + "m_Hidden": false, + "m_Value": 0.5, + "m_FloatType": 1, + "m_RangeValues": { + "x": 0.0, + "y": 1.0 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector4MaterialSlot", + "m_ObjectId": "c05d9dad6a4841e9bb9a10390c3f644b", + "m_Id": 1190027673, + "m_DisplayName": "BaseColor", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "_BaseColor", + "m_StageCapability": 2, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.ColorRGBMaterialSlot", + "m_ObjectId": "e666458e83ff46bf8911145101f34380", + "m_Id": 0, + "m_DisplayName": "Base Color", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "BaseColor", + "m_StageCapability": 2, + "m_Value": { + "x": 0.5, + "y": 0.5, + "z": 0.5 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [], + "m_ColorMode": 0, + "m_DefaultColor": { + "r": 0.5, + "g": 0.5, + "b": 0.5, + "a": 1.0 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "f6ddf963776344e098ca59b7d58e7e15", + "m_Group": { + "m_Id": "" + }, + "m_Name": "VertexDescription.Tangent", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "b0eb90f131844c248182c144dab2f9a2" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "VertexDescription.Tangent" +} + +{ + "m_SGVersion": 3, + "m_Type": "UnityEditor.ShaderGraph.Internal.ColorShaderProperty", + "m_ObjectId": "fc4e9a78e2e6410cabad64694fcf4962", + "m_Guid": { + "m_GuidSerialized": "a7c7cddf-828c-450e-b14a-1b7a4cff4f65" + }, + "m_Name": "BaseColor", + "m_DefaultRefNameVersion": 1, + "m_RefNameGeneratedByDisplayName": "BaseColor", + "m_DefaultReferenceName": "_BaseColor", + "m_OverrideReferenceName": "", + "m_GeneratePropertyBlock": true, + "m_UseCustomSlotLabel": false, + "m_CustomSlotLabel": "", + "m_DismissedVersion": 0, + "m_Precision": 0, + "overrideHLSLDeclaration": false, + "hlslDeclarationOverride": 0, + "m_Hidden": false, + "m_Value": { + "r": 1.0, + "g": 1.0, + "b": 1.0, + "a": 1.0 + }, + "isMainColor": true, + "m_ColorMode": 0 +} + diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/BuiltIn/Shaders/Unlit.shadergraph.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/BuiltIn/Shaders/Unlit.shadergraph.meta new file mode 100644 index 00000000..3d2e3116 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/BuiltIn/Shaders/Unlit.shadergraph.meta @@ -0,0 +1,17 @@ +fileFormatVersion: 2 +guid: 633bc607ec1934fe0bbbe26598e95f76 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: 625f186215c104763be7675aa2d941aa, type: 3} +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/BuiltIn/Shaders/Unlit.shadergraph + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/HDRP.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/HDRP.meta new file mode 100644 index 00000000..5462abbe --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/HDRP.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 58a9e4c5764444e5495f652d211f0ac7 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/HDRP/HighDefinitionRenderPipelineHandler.cs b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/HDRP/HighDefinitionRenderPipelineHandler.cs new file mode 100644 index 00000000..146e5252 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/HDRP/HighDefinitionRenderPipelineHandler.cs @@ -0,0 +1,320 @@ +#if RIVE_USING_HDRP +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Rendering; +using UnityEngine.Rendering.HighDefinition; +using UnityEngine.SceneManagement; +using Rive.Utils; + +namespace Rive.Components.HDRP +{ + /// + /// This class is responsible for handling the rendering of Rive objects in the High Definition Render Pipeline. + /// + public class HighDefinitionRenderPipelineHandler : MonoBehaviour, IRenderPipelineHandler + { + [SerializeField] private CustomPassInjectionPoint m_injectionPoint = CustomPassInjectionPoint.AfterOpaqueDepthAndNormal; + + [Tooltip("The camera that will render the Rive content. If not provided, the main camera will be used.")] + [SerializeField] private Camera m_renderCamera; + + private Dictionary m_rtHandleCache = new Dictionary(); + + private bool m_registeredWithOrchestrator = false; + + /// + /// The camera that will render the Rive content. + /// + public Camera RenderCamera + { + get => m_renderCamera; + set + { + m_renderCamera = value; + if (m_customPassVolume != null) + { + m_customPassVolume.targetCamera = m_renderCamera; + } + } + } + + + private List m_activeRenderPasses = new List(); + + private RiveCustomPass m_riveCustomPass; + + private CustomPassVolume m_customPassVolume; + + private const string DEFAULT_RENDER_TEXTURE_NAME = "URP Rive Render Texture"; + + private RTHandleSystem m_RTHandleSystem = new RTHandleSystem(); + + private Coroutine m_setNewRenderCameraCoroutine; + + /// + /// The rive renderers that are currently being rendered by the custom pass. + /// + public IEnumerable ActiveRenderers => m_activeRenderPasses; + + + + + protected virtual void Awake() + { + m_RTHandleSystem.Initialize(Screen.width, Screen.height); + } + + protected virtual void OnEnable() + { + SceneManager.activeSceneChanged += ChangedActiveScene; + TrySubscribeToOrchestrator(); + } + + protected virtual void OnDisable() + { + SceneManager.activeSceneChanged -= ChangedActiveScene; + UnsubscribeFromOrchestrator(); + } + + private void TrySubscribeToOrchestrator() + { + if (m_registeredWithOrchestrator || !isActiveAndEnabled || m_activeRenderPasses.Count == 0) + { + return; + } + + var orchestrator = Orchestrator.Instance; + if (orchestrator != null) + { + orchestrator.OnPostRenderPreparation += ValidateRenderCamera; + m_registeredWithOrchestrator = true; + } + } + + private void UnsubscribeFromOrchestrator() + { + if (!m_registeredWithOrchestrator) + { + return; + } + + var orchestrator = Orchestrator.Instance; + if (orchestrator != null) + { + orchestrator.OnPostRenderPreparation -= ValidateRenderCamera; + } + m_registeredWithOrchestrator = false; + } + + private void ValidateRenderCamera() + { + if (m_renderCamera != null && !m_renderCamera.isActiveAndEnabled) + { + Camera newCamera = CameraHelper.GetRenderCameraInScene(); + if (newCamera != null) + { + RenderCamera = newCamera; + } + } + } + + private void ChangedActiveScene(Scene arg0, Scene arg1) + { + // If the scene changes and there's no main camera, we need to wait until there's one + if (m_renderCamera == null && m_setNewRenderCameraCoroutine == null) + { + m_setNewRenderCameraCoroutine = StartCoroutine(SetNewRenderCamera()); + } + } + + private IEnumerator SetNewRenderCamera() + { + // Wait until there's a main camera + Camera camera = null; + while (camera == null) + { + camera = Camera.main; + + if (camera == null) + { + yield return null; + } + + } + + RenderCamera = camera; + + m_setNewRenderCameraCoroutine = null; + + + } + + + protected virtual void Start() + { + if (m_renderCamera == null) + { + RenderCamera = Camera.main; + } + + m_customPassVolume = gameObject.AddComponent(); + + m_customPassVolume.injectionPoint = m_injectionPoint; + + // We only want one camera to render the Rive content. + m_customPassVolume.targetCamera = RenderCamera; + + + m_riveCustomPass = new RiveCustomPass(this); + m_customPassVolume.customPasses.Add(m_riveCustomPass); + } + + + public void Register(IRenderer renderer) + { + if (renderer == null) + { + DebugLogger.Instance.LogWarning("Cannot register a null renderer."); + return; + } + + if (m_activeRenderPasses.Contains(renderer)) + { + DebugLogger.Instance.LogWarning("Renderer is already registered."); + return; + } + + m_activeRenderPasses.Add(renderer); + TrySubscribeToOrchestrator(); + } + + public void Unregister(IRenderer renderer) + { + if (renderer == null) + { + DebugLogger.Instance.LogWarning("Cannot unregister a null renderer."); + return; + } + + if (!m_activeRenderPasses.Contains(renderer)) + { + // Teardown paths can attempt to unregister the same renderer more than once. + // We keep unregister idempotent and quiet to match URP/BuiltIn handlers. + return; + } + + m_activeRenderPasses.Remove(renderer); + + if (m_activeRenderPasses.Count == 0) + { + UnsubscribeFromOrchestrator(); + } + } + + public UnityEngine.RenderTexture AllocateRenderTexture(int width, int height) + { + var descriptor = TextureHelper.Descriptor(width, height); + return m_RTHandleSystem.Alloc(width, height, colorFormat: descriptor.graphicsFormat, enableRandomWrite: descriptor.enableRandomWrite, name: DEFAULT_RENDER_TEXTURE_NAME); + } + + public void ReleaseRenderTexture(RenderTexture renderTexture) + { + if (m_RTHandleSystem == null) + { + return; + } + + if (renderTexture == null) + { + return; + } + + if (m_rtHandleCache.Remove(renderTexture, out var rtHandle)) + { + rtHandle.Release(); + } + + } + + public RenderTexture ResizeRenderTexture(RenderTexture renderTexture, int width, int height) + { + if (m_RTHandleSystem == null) + { + DebugLogger.Instance.LogWarning("Cannot resize render texture. RTHandleSystem is null."); + return null; + } + + if (renderTexture == null) + { + DebugLogger.Instance.LogWarning("Cannot resize a null render texture."); + return null; + } + + if (m_rtHandleCache.TryGetValue(renderTexture, out var rtHandle)) + { + rtHandle.Release(); + m_rtHandleCache.Remove(renderTexture); + } + + return AllocateRenderTexture(width, height); + } + + public void SetRendererTexture(IRenderer renderer, RenderTexture renderTexture) + { + if (renderer == null) + { + DebugLogger.Instance.LogError("Cannot set texture on a null renderer."); + return; + } + + Renderer riveRenderer = renderer as Renderer; + + if (riveRenderer == null) + { + DebugLogger.Instance.LogError("Cannot set texture on a non-Rive renderer."); + return; + } + + riveRenderer.RenderQueue.UpdateTexture(renderTexture); + } + + public bool IsRendererRegistered(IRenderer renderer) + { + return m_activeRenderPasses.Contains(renderer); + } + + private void Cleanup() + { + UnsubscribeFromOrchestrator(); + + // Remove the custom pass from the volume and destroy the volume + if (m_customPassVolume != null) + { + if (m_riveCustomPass != null) + { + m_customPassVolume.customPasses.Remove(m_riveCustomPass); + m_riveCustomPass = null; + } + Destroy(m_customPassVolume); + m_customPassVolume = null; + } + m_RTHandleSystem?.Dispose(); + + // Stop any running coroutines + if (m_setNewRenderCameraCoroutine != null) + { + StopCoroutine(m_setNewRenderCameraCoroutine); + m_setNewRenderCameraCoroutine = null; + } + } + + private void OnDestroy() + { + Cleanup(); + } + + + } +} +#endif \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/HDRP/HighDefinitionRenderPipelineHandler.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/HDRP/HighDefinitionRenderPipelineHandler.cs.meta new file mode 100644 index 00000000..72d7c11d --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/HDRP/HighDefinitionRenderPipelineHandler.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 044baf737cb0648abafed0b3273303de +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/HDRP/HighDefinitionRenderPipelineHandler.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/HDRP/RiveCustomPass.cs b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/HDRP/RiveCustomPass.cs new file mode 100644 index 00000000..9bcae8ad --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/HDRP/RiveCustomPass.cs @@ -0,0 +1,58 @@ +#if RIVE_USING_HDRP +using UnityEngine; +using UnityEngine.Rendering; +using UnityEngine.Rendering.HighDefinition; + +namespace Rive.Components.HDRP +{ + /// + /// This is responsible for enqueueing the rendering of Rive objects in the HDRP. + /// + internal class RiveCustomPass : CustomPass + { + + private ProfilingSampler m_profilingSampler; + + private const string BUFFER_NAME = "Rive HDRP Render Pass"; + + private HighDefinitionRenderPipelineHandler m_rpHandler; + + + public RiveCustomPass(HighDefinitionRenderPipelineHandler rpHandler, string profilerMarkerName = null) + { + if (rpHandler == null) + throw new System.ArgumentNullException(nameof(rpHandler)); + + m_rpHandler = rpHandler; + var profilerName = string.IsNullOrEmpty(profilerMarkerName) ? BUFFER_NAME : profilerMarkerName; + m_profilingSampler = new ProfilingSampler(profilerName); + } + + protected override void Execute(CustomPassContext ctx) + { + if (m_rpHandler == null) + return; + + // Executed every frame for all the cameras inside the pass volume. + // The context contains the command buffer to use to enqueue graphics commands. + CommandBuffer cmd = ctx.cmd; + + using (new ProfilingScope(cmd, m_profilingSampler)) + { + foreach (IRenderer renderer in m_rpHandler.ActiveRenderers) + { + if (renderer == null) + continue; + + renderer.AddToCommandBuffer(cmd); + } + + + } + + } + + + } +} +#endif \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/HDRP/RiveCustomPass.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/HDRP/RiveCustomPass.cs.meta new file mode 100644 index 00000000..b1ac9bc0 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/HDRP/RiveCustomPass.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: a22ce65d8374a486593682a5cad632b8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/HDRP/RiveCustomPass.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/HDRP/Shaders.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/HDRP/Shaders.meta new file mode 100644 index 00000000..22fe3f5d --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/HDRP/Shaders.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 80dbfd8bc8b5c4409b8ccc1c97a098eb +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/HDRP/Shaders/Lit.shadergraph b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/HDRP/Shaders/Lit.shadergraph new file mode 100644 index 00000000..ab3cb1bf --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/HDRP/Shaders/Lit.shadergraph @@ -0,0 +1,2232 @@ +{ + "m_SGVersion": 3, + "m_Type": "UnityEditor.ShaderGraph.GraphData", + "m_ObjectId": "fa64c082769e473da6c4e854fbf43c3f", + "m_Properties": [ + { + "m_Id": "1a0aa4eacebd43a8b2f3ced981569c00" + }, + { + "m_Id": "66195679507648a393191e402e5bbcef" + }, + { + "m_Id": "e6849a509d3f4803821ef79c0305a630" + }, + { + "m_Id": "c83cec5c42b743d58dfcadfaa2273570" + }, + { + "m_Id": "bd128003368444768d33903a4ab8399a" + }, + { + "m_Id": "88d39338884b4be4a9651fba2a38c616" + }, + { + "m_Id": "848a65cec3a641ce94ba5510cfa75ff4" + }, + { + "m_Id": "ef96953cf986414aac81bd6d8830d50a" + } + ], + "m_Keywords": [], + "m_Dropdowns": [], + "m_CategoryData": [ + { + "m_Id": "cb265e6af4c74d8e8644fd884a640ed0" + } + ], + "m_Nodes": [ + { + "m_Id": "5b78b586fd1944a5b5327cfbcae221f3" + }, + { + "m_Id": "a30aee64e7484e5dbe265c1817ee5daf" + }, + { + "m_Id": "1302f9e0e15d409293dde16dd1b508d3" + }, + { + "m_Id": "3926fbe846ae4436a4de912346477059" + }, + { + "m_Id": "fa2ec2037aea496288fc8cd85a752c2a" + }, + { + "m_Id": "a15628faa8dd4b25a83ae8b718673e7e" + }, + { + "m_Id": "36729b7745de4952a5e2e88e2f39d624" + }, + { + "m_Id": "ed87e73240884d5aab955bfefd366e49" + }, + { + "m_Id": "d4add49381214e2aa0bcca7b6bd72b5e" + }, + { + "m_Id": "01ad28c4de774520b9bd6cd6b3fa85a9" + }, + { + "m_Id": "b751ef82bed2467483bf955597e15f28" + }, + { + "m_Id": "4b14aadf82b14c89a23d0b0816d1a3e9" + }, + { + "m_Id": "3b9ceb0454a147b2b4a6a5ebf18eac06" + }, + { + "m_Id": "44621e4563c14f368db9784ca89adfaf" + }, + { + "m_Id": "4d04dc8642c44568903ea0d545719a46" + }, + { + "m_Id": "c23507346f414de8846221d032e2e4ee" + }, + { + "m_Id": "67f7d261025245f88f43b61d01d68c13" + }, + { + "m_Id": "172e11bcfe924bc9bb24b982e3ce2b57" + }, + { + "m_Id": "d7351a071715421c85f73e96b2d849dc" + }, + { + "m_Id": "78c6849f60474062a161756e74a5a9be" + }, + { + "m_Id": "9b103b5fd1104025a7fd3613b739f4f8" + }, + { + "m_Id": "4fab3e95e949475a91aee8ada0c88a23" + }, + { + "m_Id": "eedeaf416082445b8f73c2c24fc23c98" + } + ], + "m_GroupDatas": [ + { + "m_Id": "190000938e814f30a4471481df27fe76" + }, + { + "m_Id": "be58da4c7f9e49a8aecd22ea30b716fe" + } + ], + "m_StickyNoteDatas": [], + "m_Edges": [ + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "172e11bcfe924bc9bb24b982e3ce2b57" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "67f7d261025245f88f43b61d01d68c13" + }, + "m_SlotId": -680323842 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "3b9ceb0454a147b2b4a6a5ebf18eac06" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "4b14aadf82b14c89a23d0b0816d1a3e9" + }, + "m_SlotId": 1334702512 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "44621e4563c14f368db9784ca89adfaf" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "4b14aadf82b14c89a23d0b0816d1a3e9" + }, + "m_SlotId": 1190027673 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "4b14aadf82b14c89a23d0b0816d1a3e9" + }, + "m_SlotId": 1 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "3926fbe846ae4436a4de912346477059" + }, + "m_SlotId": 0 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "4b14aadf82b14c89a23d0b0816d1a3e9" + }, + "m_SlotId": 2 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "b751ef82bed2467483bf955597e15f28" + }, + "m_SlotId": 0 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "4d04dc8642c44568903ea0d545719a46" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "36729b7745de4952a5e2e88e2f39d624" + }, + "m_SlotId": 0 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "67f7d261025245f88f43b61d01d68c13" + }, + "m_SlotId": 1 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "d7351a071715421c85f73e96b2d849dc" + }, + "m_SlotId": 1 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "78c6849f60474062a161756e74a5a9be" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "d7351a071715421c85f73e96b2d849dc" + }, + "m_SlotId": 3 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "9b103b5fd1104025a7fd3613b739f4f8" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "67f7d261025245f88f43b61d01d68c13" + }, + "m_SlotId": -1281716962 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "c23507346f414de8846221d032e2e4ee" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "d4add49381214e2aa0bcca7b6bd72b5e" + }, + "m_SlotId": 0 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "d7351a071715421c85f73e96b2d849dc" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "ed87e73240884d5aab955bfefd366e49" + }, + "m_SlotId": 0 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "eedeaf416082445b8f73c2c24fc23c98" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "4fab3e95e949475a91aee8ada0c88a23" + }, + "m_SlotId": 0 + } + } + ], + "m_VertexContext": { + "m_Position": { + "x": 560.0000610351563, + "y": -71.49996948242188 + }, + "m_Blocks": [ + { + "m_Id": "5b78b586fd1944a5b5327cfbcae221f3" + }, + { + "m_Id": "a30aee64e7484e5dbe265c1817ee5daf" + }, + { + "m_Id": "1302f9e0e15d409293dde16dd1b508d3" + } + ] + }, + "m_FragmentContext": { + "m_Position": { + "x": 560.0000610351563, + "y": 201.50006103515626 + }, + "m_Blocks": [ + { + "m_Id": "3926fbe846ae4436a4de912346477059" + }, + { + "m_Id": "fa2ec2037aea496288fc8cd85a752c2a" + }, + { + "m_Id": "a15628faa8dd4b25a83ae8b718673e7e" + }, + { + "m_Id": "36729b7745de4952a5e2e88e2f39d624" + }, + { + "m_Id": "ed87e73240884d5aab955bfefd366e49" + }, + { + "m_Id": "d4add49381214e2aa0bcca7b6bd72b5e" + }, + { + "m_Id": "01ad28c4de774520b9bd6cd6b3fa85a9" + }, + { + "m_Id": "b751ef82bed2467483bf955597e15f28" + }, + { + "m_Id": "4fab3e95e949475a91aee8ada0c88a23" + } + ] + }, + "m_PreviewData": { + "serializedMesh": { + "m_SerializedMesh": "{\"mesh\":{\"instanceID\":0}}", + "m_Guid": "" + }, + "preventRotation": false + }, + "m_Path": "Rive/High Definition Render Pipeline", + "m_GraphPrecision": 1, + "m_PreviewMode": 2, + "m_OutputNode": { + "m_Id": "" + }, + "m_SubDatas": [], + "m_ActiveTargets": [ + { + "m_Id": "0987c957b7aa4648ab0bf4f5498c5762" + } + ] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "01ad28c4de774520b9bd6cd6b3fa85a9", + "m_Group": { + "m_Id": "" + }, + "m_Name": "SurfaceDescription.Occlusion", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "4b4a8066c5714624a990811df4e7164b" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "SurfaceDescription.Occlusion" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector3MaterialSlot", + "m_ObjectId": "02636a2b36c54b75b539f2a4c227d689", + "m_Id": 1, + "m_DisplayName": "Out_BaseColor", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out_BaseColor", + "m_StageCapability": 2, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector4MaterialSlot", + "m_ObjectId": "05a939a2c6bc440da2717830e08a20ba", + "m_Id": 0, + "m_DisplayName": "EmissiveColor", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out", + "m_StageCapability": 3, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.Rendering.HighDefinition.ShaderGraph.HDTarget", + "m_ObjectId": "0987c957b7aa4648ab0bf4f5498c5762", + "m_ActiveSubTarget": { + "m_Id": "cdd06af4c596486e9ae7b17c048f9682" + }, + "m_Datas": [ + { + "m_Id": "162284f8c983480bad3d641925162dae" + }, + { + "m_Id": "e0bca0784ee44ed19a6a497f4f74486d" + }, + { + "m_Id": "776202f48fa2491b95c1aefac411e8f8" + }, + { + "m_Id": "f55b345d9c9a43ed8f4fd9d264de9091" + } + ], + "m_CustomEditorGUI": "", + "m_SupportVFX": false, + "m_SupportComputeForVertexSetup": false +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.ColorRGBMaterialSlot", + "m_ObjectId": "122351a18b6e44789faab8699ba16346", + "m_Id": 1, + "m_DisplayName": "Color", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Color", + "m_StageCapability": 3, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [], + "m_ColorMode": 0, + "m_DefaultColor": { + "r": 0.0, + "g": 0.0, + "b": 0.0, + "a": 1.0 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "1302f9e0e15d409293dde16dd1b508d3", + "m_Group": { + "m_Id": "" + }, + "m_Name": "VertexDescription.Tangent", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "2b9beb59be7a4aebaa561432e41c8349" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "VertexDescription.Tangent" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.Rendering.HighDefinition.ShaderGraph.BuiltinData", + "m_ObjectId": "162284f8c983480bad3d641925162dae", + "m_Distortion": false, + "m_DistortionMode": 0, + "m_DistortionDepthTest": true, + "m_AddPrecomputedVelocity": false, + "m_TransparentWritesMotionVec": false, + "m_DepthOffset": false, + "m_ConservativeDepthOffset": false, + "m_TransparencyFog": true, + "m_AlphaTestShadow": false, + "m_BackThenFrontRendering": false, + "m_TransparentDepthPrepass": false, + "m_TransparentDepthPostpass": false, + "m_SupportLodCrossFade": false +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.PropertyNode", + "m_ObjectId": "172e11bcfe924bc9bb24b982e3ce2b57", + "m_Group": { + "m_Id": "be58da4c7f9e49a8aecd22ea30b716fe" + }, + "m_Name": "Property", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -699.5000610351563, + "y": 798.5001220703125, + "width": 152.5, + "height": 33.9998779296875 + } + }, + "m_Slots": [ + { + "m_Id": "df97cb4acb8845fea757303bc1ccab93" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_Property": { + "m_Id": "c83cec5c42b743d58dfcadfaa2273570" + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.GroupData", + "m_ObjectId": "190000938e814f30a4471481df27fe76", + "m_Title": "Main Texture", + "m_Position": { + "x": -366.0000305175781, + "y": -92.5 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector4MaterialSlot", + "m_ObjectId": "19c1950da8ba4fb7abd03b9dc194b23a", + "m_Id": 1, + "m_DisplayName": "Out_Emission", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out_Emission", + "m_StageCapability": 2, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 1, + "m_Type": "UnityEditor.ShaderGraph.Internal.Vector1ShaderProperty", + "m_ObjectId": "1a0aa4eacebd43a8b2f3ced981569c00", + "m_Guid": { + "m_GuidSerialized": "27d00be8-b10d-4e66-878a-154eec52c0d8" + }, + "m_Name": "Smoothness", + "m_DefaultRefNameVersion": 1, + "m_RefNameGeneratedByDisplayName": "Smoothness", + "m_DefaultReferenceName": "_Smoothness", + "m_OverrideReferenceName": "", + "m_GeneratePropertyBlock": true, + "m_UseCustomSlotLabel": false, + "m_CustomSlotLabel": "", + "m_DismissedVersion": 0, + "m_Precision": 0, + "overrideHLSLDeclaration": false, + "hlslDeclarationOverride": 0, + "m_Hidden": false, + "m_Value": 0.0, + "m_FloatType": 1, + "m_RangeValues": { + "x": 0.0, + "y": 1.0 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.ColorRGBMaterialSlot", + "m_ObjectId": "204a21ea30634c6ca15f35973d35172b", + "m_Id": 0, + "m_DisplayName": "Emission", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Emission", + "m_StageCapability": 2, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [], + "m_ColorMode": 1, + "m_DefaultColor": { + "r": 0.0, + "g": 0.0, + "b": 0.0, + "a": 1.0 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.TangentMaterialSlot", + "m_ObjectId": "2b9beb59be7a4aebaa561432e41c8349", + "m_Id": 0, + "m_DisplayName": "Tangent", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Tangent", + "m_StageCapability": 1, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [], + "m_Space": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "2e991cb716d0474fbe12d948332f9044", + "m_Id": 0, + "m_DisplayName": "Smoothness", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Smoothness", + "m_StageCapability": 2, + "m_Value": 0.5, + "m_DefaultValue": 0.5, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "30c7b3e65629498ba1d97aad97036501", + "m_Id": 0, + "m_DisplayName": "Alpha", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Alpha", + "m_StageCapability": 2, + "m_Value": 1.0, + "m_DefaultValue": 1.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "36729b7745de4952a5e2e88e2f39d624", + "m_Group": { + "m_Id": "" + }, + "m_Name": "SurfaceDescription.Metallic", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "ecc3a5080eb1404b81d72c5b804a029e" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "SurfaceDescription.Metallic" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "37a59cfa875c409fb85ab5e4b032c10e", + "m_Id": 0, + "m_DisplayName": "Smoothness", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out", + "m_StageCapability": 3, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "3926fbe846ae4436a4de912346477059", + "m_Group": { + "m_Id": "" + }, + "m_Name": "SurfaceDescription.BaseColor", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "e354fa632f8e4c1e8c55ee922646db40" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "SurfaceDescription.BaseColor" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.PropertyNode", + "m_ObjectId": "3b9ceb0454a147b2b4a6a5ebf18eac06", + "m_Group": { + "m_Id": "190000938e814f30a4471481df27fe76" + }, + "m_Name": "Property", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -341.0, + "y": -33.99999237060547, + "width": 132.0, + "height": 33.9999885559082 + } + }, + "m_Slots": [ + { + "m_Id": "9523db49e73b42aeb9e637dd1ff91530" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_Property": { + "m_Id": "bd128003368444768d33903a4ab8399a" + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector4MaterialSlot", + "m_ObjectId": "3c3f4019904245398350375f6a409f28", + "m_Id": -1281716962, + "m_DisplayName": "EmissionColor", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "_EmissionColor", + "m_StageCapability": 2, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "3d08e7ca13f94a9592c00e6d41d4abf3", + "m_Id": 0, + "m_DisplayName": "Metallic", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out", + "m_StageCapability": 3, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.PropertyNode", + "m_ObjectId": "44621e4563c14f368db9784ca89adfaf", + "m_Group": { + "m_Id": "190000938e814f30a4471481df27fe76" + }, + "m_Name": "Property", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -341.0, + "y": 34.5, + "width": 130.5, + "height": 33.99998474121094 + } + }, + "m_Slots": [ + { + "m_Id": "a7e162cdf64744b6b5c2ed506db5bf75" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_Property": { + "m_Id": "e6849a509d3f4803821ef79c0305a630" + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.SubGraphNode", + "m_ObjectId": "4b14aadf82b14c89a23d0b0816d1a3e9", + "m_Group": { + "m_Id": "190000938e814f30a4471481df27fe76" + }, + "m_Name": "SampleMainRiveTexture", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -9.99994945526123, + "y": -34.000030517578128, + "width": 235.5, + "height": 303.0001220703125 + } + }, + "m_Slots": [ + { + "m_Id": "7ac34bb170204cd09b7d676a0527ef70" + }, + { + "m_Id": "9e14780d138843ee90e851e4723cf061" + }, + { + "m_Id": "02636a2b36c54b75b539f2a4c227d689" + }, + { + "m_Id": "a7f7919988af41cca260345311828efe" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedSubGraph": "{\n \"subGraph\": {\n \"fileID\": -5475051401550479605,\n \"guid\": \"287ae8d259edf47cf9ec073950debe11\",\n \"type\": 3\n }\n}", + "m_PropertyGuids": [ + "4b65a152-6b9e-429e-bbc1-bebac7fac8fc", + "0dafdea0-1c0d-40c7-9a2f-3553ae8cb358" + ], + "m_PropertyIds": [ + 1334702512, + 1190027673 + ], + "m_Dropdowns": [], + "m_DropdownSelectedEntries": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "4b4a8066c5714624a990811df4e7164b", + "m_Id": 0, + "m_DisplayName": "Ambient Occlusion", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Occlusion", + "m_StageCapability": 2, + "m_Value": 1.0, + "m_DefaultValue": 1.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.PropertyNode", + "m_ObjectId": "4d04dc8642c44568903ea0d545719a46", + "m_Group": { + "m_Id": "" + }, + "m_Name": "Property", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 260.5, + "y": 362.5, + "width": 115.5, + "height": 34.0 + } + }, + "m_Slots": [ + { + "m_Id": "3d08e7ca13f94a9592c00e6d41d4abf3" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_Property": { + "m_Id": "66195679507648a393191e402e5bbcef" + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "4fab3e95e949475a91aee8ada0c88a23", + "m_Group": { + "m_Id": "" + }, + "m_Name": "SurfaceDescription.AlphaClipThreshold", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "7e13e2184a3e40dcae2ce25f4fea380d" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "SurfaceDescription.AlphaClipThreshold" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.PositionMaterialSlot", + "m_ObjectId": "561feb56ee6a433f86dbe28a1fb724ef", + "m_Id": 0, + "m_DisplayName": "Position", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Position", + "m_StageCapability": 1, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [], + "m_Space": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.NormalMaterialSlot", + "m_ObjectId": "5981479123644cedbc173735744eb813", + "m_Id": 0, + "m_DisplayName": "Normal (Tangent Space)", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "NormalTS", + "m_StageCapability": 2, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [], + "m_Space": 3 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "5b78b586fd1944a5b5327cfbcae221f3", + "m_Group": { + "m_Id": "" + }, + "m_Name": "VertexDescription.Position", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "561feb56ee6a433f86dbe28a1fb724ef" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "VertexDescription.Position" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.NormalMaterialSlot", + "m_ObjectId": "61ca89722bf741a29ebba063f45985af", + "m_Id": 0, + "m_DisplayName": "Normal", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Normal", + "m_StageCapability": 1, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [], + "m_Space": 0 +} + +{ + "m_SGVersion": 1, + "m_Type": "UnityEditor.ShaderGraph.Internal.Vector1ShaderProperty", + "m_ObjectId": "66195679507648a393191e402e5bbcef", + "m_Guid": { + "m_GuidSerialized": "bd2f9f09-dccf-4f7c-9e37-8d8ece2907af" + }, + "m_Name": "Metallic", + "m_DefaultRefNameVersion": 1, + "m_RefNameGeneratedByDisplayName": "Metallic", + "m_DefaultReferenceName": "_Metallic", + "m_OverrideReferenceName": "", + "m_GeneratePropertyBlock": true, + "m_UseCustomSlotLabel": false, + "m_CustomSlotLabel": "", + "m_DismissedVersion": 0, + "m_Precision": 0, + "overrideHLSLDeclaration": false, + "hlslDeclarationOverride": 0, + "m_Hidden": false, + "m_Value": 0.0, + "m_FloatType": 1, + "m_RangeValues": { + "x": 0.0, + "y": 1.0 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.SubGraphNode", + "m_ObjectId": "67f7d261025245f88f43b61d01d68c13", + "m_Group": { + "m_Id": "be58da4c7f9e49a8aecd22ea30b716fe" + }, + "m_Name": "SampleEmission", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -340.9999694824219, + "y": 723.5, + "width": 248.49993896484376, + "height": 303.0 + } + }, + "m_Slots": [ + { + "m_Id": "3c3f4019904245398350375f6a409f28" + }, + { + "m_Id": "c03941ccae444248968eb3176ee46c85" + }, + { + "m_Id": "19c1950da8ba4fb7abd03b9dc194b23a" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedSubGraph": "{\n \"subGraph\": {\n \"fileID\": -5475051401550479605,\n \"guid\": \"c3bbcf1d5b5ee446baa01a87b8e5dadf\",\n \"type\": 3\n }\n}", + "m_PropertyGuids": [ + "417ee71e-80a1-414f-b809-df8c19e3743f", + "9fae8bf3-f659-4d48-8efb-5f8bda92ca8e", + "0d74976b-fbf8-4395-8137-14c541e8d2c5" + ], + "m_PropertyIds": [ + -1281716962, + -680323842, + 1311224659 + ], + "m_Dropdowns": [], + "m_DropdownSelectedEntries": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "7522cc9e71434eddaea97c72f19a5df1", + "m_Id": 2, + "m_DisplayName": "Intensity", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Intensity", + "m_StageCapability": 3, + "m_Value": 1.0, + "m_DefaultValue": 1.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.Rendering.HighDefinition.ShaderGraph.LightingData", + "m_ObjectId": "776202f48fa2491b95c1aefac411e8f8", + "m_NormalDropOffSpace": 0, + "m_BlendPreserveSpecular": false, + "m_ReceiveDecals": true, + "m_ReceiveSSR": true, + "m_ReceiveSSRTransparent": false, + "m_SpecularAA": false, + "m_SpecularOcclusionMode": 1, + "m_OverrideBakedGI": false +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.PropertyNode", + "m_ObjectId": "78c6849f60474062a161756e74a5a9be", + "m_Group": { + "m_Id": "be58da4c7f9e49a8aecd22ea30b716fe" + }, + "m_Name": "Property", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -59.00000762939453, + "y": 886.4999389648438, + "width": 206.0, + "height": 34.00006103515625 + } + }, + "m_Slots": [ + { + "m_Id": "f980f6f15d394624b730be111da1a96d" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_Property": { + "m_Id": "848a65cec3a641ce94ba5510cfa75ff4" + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Texture2DInputMaterialSlot", + "m_ObjectId": "7ac34bb170204cd09b7d676a0527ef70", + "m_Id": 1334702512, + "m_DisplayName": "BaseMap", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "_BaseMap", + "m_StageCapability": 2, + "m_BareResource": false, + "m_Texture": { + "m_SerializedTexture": "{\"texture\":{\"instanceID\":0}}", + "m_Guid": "" + }, + "m_DefaultType": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "7e13e2184a3e40dcae2ce25f4fea380d", + "m_Id": 0, + "m_DisplayName": "Alpha Clip Threshold", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "AlphaClipThreshold", + "m_StageCapability": 2, + "m_Value": 0.5, + "m_DefaultValue": 0.5, + "m_Labels": [] +} + +{ + "m_SGVersion": 1, + "m_Type": "UnityEditor.ShaderGraph.Internal.Vector1ShaderProperty", + "m_ObjectId": "848a65cec3a641ce94ba5510cfa75ff4", + "m_Guid": { + "m_GuidSerialized": "cbff8825-fb52-418c-832a-75718e3fe8a6" + }, + "m_Name": "EmissiveExposureWeight", + "m_DefaultRefNameVersion": 1, + "m_RefNameGeneratedByDisplayName": "EmissiveExposureWeight", + "m_DefaultReferenceName": "_EmissiveExposureWeight", + "m_OverrideReferenceName": "", + "m_GeneratePropertyBlock": true, + "m_UseCustomSlotLabel": false, + "m_CustomSlotLabel": "", + "m_DismissedVersion": 0, + "m_Precision": 0, + "overrideHLSLDeclaration": false, + "hlslDeclarationOverride": 0, + "m_Hidden": false, + "m_Value": 1.0, + "m_FloatType": 1, + "m_RangeValues": { + "x": 0.0, + "y": 1.0 + } +} + +{ + "m_SGVersion": 3, + "m_Type": "UnityEditor.ShaderGraph.Internal.ColorShaderProperty", + "m_ObjectId": "88d39338884b4be4a9651fba2a38c616", + "m_Guid": { + "m_GuidSerialized": "bcada6ec-5ff9-4814-95ab-f742f93cc523" + }, + "m_Name": "EmissiveColor", + "m_DefaultRefNameVersion": 1, + "m_RefNameGeneratedByDisplayName": "EmissiveColor", + "m_DefaultReferenceName": "_EmissiveColor", + "m_OverrideReferenceName": "", + "m_GeneratePropertyBlock": true, + "m_UseCustomSlotLabel": false, + "m_CustomSlotLabel": "", + "m_DismissedVersion": 0, + "m_Precision": 0, + "overrideHLSLDeclaration": false, + "hlslDeclarationOverride": 0, + "m_Hidden": false, + "m_Value": { + "r": 0.0, + "g": 0.0, + "b": 0.0, + "a": 0.0 + }, + "isMainColor": false, + "m_ColorMode": 1 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "8f4eb646fa284f288131ba1fa9522cfd", + "m_Id": 3, + "m_DisplayName": "Exposure Weight", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Exposure Weight", + "m_StageCapability": 3, + "m_Value": 1.0, + "m_DefaultValue": 1.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Texture2DMaterialSlot", + "m_ObjectId": "9523db49e73b42aeb9e637dd1ff91530", + "m_Id": 0, + "m_DisplayName": "BaseMap", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out", + "m_StageCapability": 3, + "m_BareResource": false +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.PropertyNode", + "m_ObjectId": "9b103b5fd1104025a7fd3613b739f4f8", + "m_Group": { + "m_Id": "" + }, + "m_Name": "Property", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -512.0538330078125, + "y": 718.2054443359375, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "05a939a2c6bc440da2717830e08a20ba" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_Property": { + "m_Id": "88d39338884b4be4a9651fba2a38c616" + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector4MaterialSlot", + "m_ObjectId": "9e14780d138843ee90e851e4723cf061", + "m_Id": 1190027673, + "m_DisplayName": "BaseColor", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "_BaseColor", + "m_StageCapability": 2, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "a15628faa8dd4b25a83ae8b718673e7e", + "m_Group": { + "m_Id": "" + }, + "m_Name": "SurfaceDescription.BentNormal", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "f56be29c7e7349be87fb53362a4ebe90" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "SurfaceDescription.BentNormal" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "a30aee64e7484e5dbe265c1817ee5daf", + "m_Group": { + "m_Id": "" + }, + "m_Name": "VertexDescription.Normal", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "61ca89722bf741a29ebba063f45985af" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "VertexDescription.Normal" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector4MaterialSlot", + "m_ObjectId": "a7e162cdf64744b6b5c2ed506db5bf75", + "m_Id": 0, + "m_DisplayName": "BaseColor", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out", + "m_StageCapability": 3, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "a7f7919988af41cca260345311828efe", + "m_Id": 2, + "m_DisplayName": "Out_Alpha", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out_Alpha", + "m_StageCapability": 2, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "ac2f6b0927e644339b2105302b6cec7b", + "m_Id": 0, + "m_DisplayName": "Cutoff", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out", + "m_StageCapability": 3, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "b751ef82bed2467483bf955597e15f28", + "m_Group": { + "m_Id": "" + }, + "m_Name": "SurfaceDescription.Alpha", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "30c7b3e65629498ba1d97aad97036501" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "SurfaceDescription.Alpha" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Internal.Texture2DShaderProperty", + "m_ObjectId": "bd128003368444768d33903a4ab8399a", + "m_Guid": { + "m_GuidSerialized": "a5e9dc59-7fb6-45e3-ad1f-c7ed11d8b7d8" + }, + "m_Name": "BaseMap", + "m_DefaultRefNameVersion": 1, + "m_RefNameGeneratedByDisplayName": "BaseMap", + "m_DefaultReferenceName": "_BaseMap", + "m_OverrideReferenceName": "", + "m_GeneratePropertyBlock": true, + "m_UseCustomSlotLabel": false, + "m_CustomSlotLabel": "", + "m_DismissedVersion": 0, + "m_Precision": 0, + "overrideHLSLDeclaration": false, + "hlslDeclarationOverride": 2, + "m_Hidden": false, + "m_Value": { + "m_SerializedTexture": "{\"texture\":{\"instanceID\":0}}", + "m_Guid": "" + }, + "isMainTexture": true, + "useTilingAndOffset": true, + "m_Modifiable": true, + "m_DefaultType": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.GroupData", + "m_ObjectId": "be58da4c7f9e49a8aecd22ea30b716fe", + "m_Title": "Emission", + "m_Position": { + "x": -724.5, + "y": 665.0 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Texture2DInputMaterialSlot", + "m_ObjectId": "c03941ccae444248968eb3176ee46c85", + "m_Id": -680323842, + "m_DisplayName": "EmissionMap", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "_EmissionMap", + "m_StageCapability": 2, + "m_BareResource": false, + "m_Texture": { + "m_SerializedTexture": "{\"texture\":{\"instanceID\":0}}", + "m_Guid": "" + }, + "m_DefaultType": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.PropertyNode", + "m_ObjectId": "c23507346f414de8846221d032e2e4ee", + "m_Group": { + "m_Id": "" + }, + "m_Name": "Property", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 260.5, + "y": 445.0, + "width": 140.00003051757813, + "height": 34.0 + } + }, + "m_Slots": [ + { + "m_Id": "37a59cfa875c409fb85ab5e4b032c10e" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_Property": { + "m_Id": "1a0aa4eacebd43a8b2f3ced981569c00" + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Internal.Texture2DShaderProperty", + "m_ObjectId": "c83cec5c42b743d58dfcadfaa2273570", + "m_Guid": { + "m_GuidSerialized": "bd09cbbc-96f5-43e9-8bba-0827402e82d5" + }, + "m_Name": "EmissionMap", + "m_DefaultRefNameVersion": 1, + "m_RefNameGeneratedByDisplayName": "EmissionMap", + "m_DefaultReferenceName": "_EmissionMap", + "m_OverrideReferenceName": "", + "m_GeneratePropertyBlock": true, + "m_UseCustomSlotLabel": false, + "m_CustomSlotLabel": "", + "m_DismissedVersion": 0, + "m_Precision": 0, + "overrideHLSLDeclaration": false, + "hlslDeclarationOverride": 0, + "m_Hidden": false, + "m_Value": { + "m_SerializedTexture": "{\"texture\":{\"instanceID\":0}}", + "m_Guid": "" + }, + "isMainTexture": false, + "useTilingAndOffset": false, + "m_Modifiable": true, + "m_DefaultType": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.CategoryData", + "m_ObjectId": "cb265e6af4c74d8e8644fd884a640ed0", + "m_Name": "", + "m_ChildObjectList": [ + { + "m_Id": "bd128003368444768d33903a4ab8399a" + }, + { + "m_Id": "e6849a509d3f4803821ef79c0305a630" + }, + { + "m_Id": "66195679507648a393191e402e5bbcef" + }, + { + "m_Id": "1a0aa4eacebd43a8b2f3ced981569c00" + }, + { + "m_Id": "c83cec5c42b743d58dfcadfaa2273570" + }, + { + "m_Id": "88d39338884b4be4a9651fba2a38c616" + }, + { + "m_Id": "848a65cec3a641ce94ba5510cfa75ff4" + }, + { + "m_Id": "ef96953cf986414aac81bd6d8830d50a" + } + ] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.Rendering.HighDefinition.ShaderGraph.HDLitSubTarget", + "m_ObjectId": "cdd06af4c596486e9ae7b17c048f9682" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "d4add49381214e2aa0bcca7b6bd72b5e", + "m_Group": { + "m_Id": "" + }, + "m_Name": "SurfaceDescription.Smoothness", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "2e991cb716d0474fbe12d948332f9044" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "SurfaceDescription.Smoothness" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.Rendering.HighDefinition.EmissionNode", + "m_ObjectId": "d7351a071715421c85f73e96b2d849dc", + "m_Group": { + "m_Id": "be58da4c7f9e49a8aecd22ea30b716fe" + }, + "m_Name": "Emission Node", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 174.99993896484376, + "y": 718.0, + "width": 225.50006103515626, + "height": 185.5 + } + }, + "m_Slots": [ + { + "m_Id": "122351a18b6e44789faab8699ba16346" + }, + { + "m_Id": "7522cc9e71434eddaea97c72f19a5df1" + }, + { + "m_Id": "8f4eb646fa284f288131ba1fa9522cfd" + }, + { + "m_Id": "dfb112494fa24600841ef1cd6e50b950" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "_intensityUnit": 0, + "m_NormalizeColor": false +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Texture2DMaterialSlot", + "m_ObjectId": "df97cb4acb8845fea757303bc1ccab93", + "m_Id": 0, + "m_DisplayName": "EmissionMap", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out", + "m_StageCapability": 3, + "m_BareResource": false +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.ColorRGBMaterialSlot", + "m_ObjectId": "dfb112494fa24600841ef1cd6e50b950", + "m_Id": 0, + "m_DisplayName": "Output", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Output", + "m_StageCapability": 3, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [], + "m_ColorMode": 1, + "m_DefaultColor": { + "r": 0.0, + "g": 0.0, + "b": 0.0, + "a": 1.0 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.Rendering.HighDefinition.ShaderGraph.SystemData", + "m_ObjectId": "e0bca0784ee44ed19a6a497f4f74486d", + "m_MaterialNeedsUpdateHash": 279841, + "m_SurfaceType": 1, + "m_RenderingPass": 4, + "m_BlendMode": 0, + "m_ZTest": 4, + "m_ZWrite": false, + "m_TransparentCullMode": 2, + "m_OpaqueCullMode": 2, + "m_SortPriority": 0, + "m_AlphaTest": true, + "m_ExcludeFromTUAndAA": false, + "m_TransparentDepthPrepass": false, + "m_TransparentDepthPostpass": false, + "m_SupportLodCrossFade": false, + "m_DoubleSidedMode": 0, + "m_DOTSInstancing": false, + "m_CustomVelocity": false, + "m_Tessellation": false, + "m_TessellationMode": 0, + "m_TessellationFactorMinDistance": 20.0, + "m_TessellationFactorMaxDistance": 50.0, + "m_TessellationFactorTriangleSize": 100.0, + "m_TessellationShapeFactor": 0.75, + "m_TessellationBackFaceCullEpsilon": -0.25, + "m_TessellationMaxDisplacement": 0.009999999776482582, + "m_Version": 1, + "inspectorFoldoutMask": 1 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.ColorRGBMaterialSlot", + "m_ObjectId": "e354fa632f8e4c1e8c55ee922646db40", + "m_Id": 0, + "m_DisplayName": "Base Color", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "BaseColor", + "m_StageCapability": 2, + "m_Value": { + "x": 0.5, + "y": 0.5, + "z": 0.5 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [], + "m_ColorMode": 0, + "m_DefaultColor": { + "r": 0.5, + "g": 0.5, + "b": 0.5, + "a": 1.0 + } +} + +{ + "m_SGVersion": 3, + "m_Type": "UnityEditor.ShaderGraph.Internal.ColorShaderProperty", + "m_ObjectId": "e6849a509d3f4803821ef79c0305a630", + "m_Guid": { + "m_GuidSerialized": "6f8c2768-210c-48c7-a17f-2aaf808fbd68" + }, + "m_Name": "BaseColor", + "m_DefaultRefNameVersion": 1, + "m_RefNameGeneratedByDisplayName": "BaseColor", + "m_DefaultReferenceName": "_BaseColor", + "m_OverrideReferenceName": "", + "m_GeneratePropertyBlock": true, + "m_UseCustomSlotLabel": false, + "m_CustomSlotLabel": "", + "m_DismissedVersion": 0, + "m_Precision": 0, + "overrideHLSLDeclaration": false, + "hlslDeclarationOverride": 0, + "m_Hidden": false, + "m_Value": { + "r": 1.0, + "g": 1.0, + "b": 1.0, + "a": 1.0 + }, + "isMainColor": true, + "m_ColorMode": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "ecc3a5080eb1404b81d72c5b804a029e", + "m_Id": 0, + "m_DisplayName": "Metallic", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Metallic", + "m_StageCapability": 2, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "ed87e73240884d5aab955bfefd366e49", + "m_Group": { + "m_Id": "" + }, + "m_Name": "SurfaceDescription.Emission", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "204a21ea30634c6ca15f35973d35172b" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "SurfaceDescription.Emission" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.PropertyNode", + "m_ObjectId": "eedeaf416082445b8f73c2c24fc23c98", + "m_Group": { + "m_Id": "" + }, + "m_Name": "Property", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 292.5000305175781, + "y": 584.0000610351563, + "width": 108.0, + "height": 33.99993896484375 + } + }, + "m_Slots": [ + { + "m_Id": "ac2f6b0927e644339b2105302b6cec7b" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_Property": { + "m_Id": "ef96953cf986414aac81bd6d8830d50a" + } +} + +{ + "m_SGVersion": 1, + "m_Type": "UnityEditor.ShaderGraph.Internal.Vector1ShaderProperty", + "m_ObjectId": "ef96953cf986414aac81bd6d8830d50a", + "m_Guid": { + "m_GuidSerialized": "25a97ba7-87a3-4fa4-aa72-f2ab624902d4" + }, + "m_Name": "Cutoff", + "m_DefaultRefNameVersion": 1, + "m_RefNameGeneratedByDisplayName": "Cutoff", + "m_DefaultReferenceName": "_Cutoff", + "m_OverrideReferenceName": "", + "m_GeneratePropertyBlock": true, + "m_UseCustomSlotLabel": false, + "m_CustomSlotLabel": "", + "m_DismissedVersion": 0, + "m_Precision": 0, + "overrideHLSLDeclaration": false, + "hlslDeclarationOverride": 0, + "m_Hidden": false, + "m_Value": 0.5, + "m_FloatType": 1, + "m_RangeValues": { + "x": 0.0, + "y": 1.0 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.Rendering.HighDefinition.ShaderGraph.HDLitData", + "m_ObjectId": "f55b345d9c9a43ed8f4fd9d264de9091", + "m_RayTracing": false, + "m_MaterialType": 0, + "m_RefractionModel": 0, + "m_SSSTransmission": true, + "m_EnergyConservingSpecular": true, + "m_ClearCoat": false +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.NormalMaterialSlot", + "m_ObjectId": "f56be29c7e7349be87fb53362a4ebe90", + "m_Id": 0, + "m_DisplayName": "Bent Normal", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "BentNormal", + "m_StageCapability": 2, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [], + "m_Space": 3 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "f980f6f15d394624b730be111da1a96d", + "m_Id": 0, + "m_DisplayName": "EmissiveExposureWeight", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out", + "m_StageCapability": 3, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "fa2ec2037aea496288fc8cd85a752c2a", + "m_Group": { + "m_Id": "" + }, + "m_Name": "SurfaceDescription.NormalTS", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "5981479123644cedbc173735744eb813" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "SurfaceDescription.NormalTS" +} + diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/HDRP/Shaders/Lit.shadergraph.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/HDRP/Shaders/Lit.shadergraph.meta new file mode 100644 index 00000000..811821ae --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/HDRP/Shaders/Lit.shadergraph.meta @@ -0,0 +1,17 @@ +fileFormatVersion: 2 +guid: 1c9bb15f6caab475182b96909a769a4d +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: 625f186215c104763be7675aa2d941aa, type: 3} +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/HDRP/Shaders/Lit.shadergraph + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/HDRP/Shaders/Unlit.shadergraph b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/HDRP/Shaders/Unlit.shadergraph new file mode 100644 index 00000000..2ef45d80 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/HDRP/Shaders/Unlit.shadergraph @@ -0,0 +1,1714 @@ +{ + "m_SGVersion": 3, + "m_Type": "UnityEditor.ShaderGraph.GraphData", + "m_ObjectId": "b59e210b43e5495e801139269c379682", + "m_Properties": [ + { + "m_Id": "14a2513875cd4bedad31bc3434dce4ed" + }, + { + "m_Id": "c0e72895fc20431c95cb85ee1ffae633" + }, + { + "m_Id": "f654e1fdd5a54e4f98f7cc912b6792fc" + }, + { + "m_Id": "63c10ad36e224cbe8900b6eb225cfa65" + }, + { + "m_Id": "198ebeb0d8144e908f0c502b8bae3c6f" + }, + { + "m_Id": "75b4318b313e45bf86467b06b66a8bd1" + } + ], + "m_Keywords": [], + "m_Dropdowns": [], + "m_CategoryData": [ + { + "m_Id": "7f5ba364662e4aa3aab4c078c2711899" + } + ], + "m_Nodes": [ + { + "m_Id": "dd069819e9944918930b6a6cd9ef4b2c" + }, + { + "m_Id": "c5489d276f804363b0f79fdbdfc366c3" + }, + { + "m_Id": "3c86daa3f6e749fc9f2ae95560e7a960" + }, + { + "m_Id": "f09876534ca746799e79391c0b945f7f" + }, + { + "m_Id": "17c500272541433797ef87d56cbbeb7a" + }, + { + "m_Id": "8ba36c99c6424cd6ab60f8b90bda9101" + }, + { + "m_Id": "5b3a52fa2f644eba8d875cb740c046d8" + }, + { + "m_Id": "cf9f1904491b4e7194a904b8667c095b" + }, + { + "m_Id": "b56bd8c5dc7f4c0995d2719333b75ae3" + }, + { + "m_Id": "7aaaeff70c1b4e96968af1228d4dec83" + }, + { + "m_Id": "918839ed8d6744f188ac75a1434fa0af" + }, + { + "m_Id": "90a9730731e049ff8ef6141640f6688a" + }, + { + "m_Id": "b3ec873b636b4d5b8937046e2e4a8fd0" + }, + { + "m_Id": "d4ae4c6b2dfd4ecc8bda0ad6c347b5b4" + }, + { + "m_Id": "42e844f32f9d4f9c8b1ae224e5fc3945" + }, + { + "m_Id": "984badfcb5794de7a0a3c73aad214424" + } + ], + "m_GroupDatas": [ + { + "m_Id": "4d185a851d114c7a97fcc7dcf0ee53f0" + }, + { + "m_Id": "e5caeb6982484141b0639405aaefae6c" + } + ], + "m_StickyNoteDatas": [], + "m_Edges": [ + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "5b3a52fa2f644eba8d875cb740c046d8" + }, + "m_SlotId": 1 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "f09876534ca746799e79391c0b945f7f" + }, + "m_SlotId": 0 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "5b3a52fa2f644eba8d875cb740c046d8" + }, + "m_SlotId": 2 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "8ba36c99c6424cd6ab60f8b90bda9101" + }, + "m_SlotId": 0 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "7aaaeff70c1b4e96968af1228d4dec83" + }, + "m_SlotId": 1 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "90a9730731e049ff8ef6141640f6688a" + }, + "m_SlotId": 1 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "90a9730731e049ff8ef6141640f6688a" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "17c500272541433797ef87d56cbbeb7a" + }, + "m_SlotId": 0 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "918839ed8d6744f188ac75a1434fa0af" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "7aaaeff70c1b4e96968af1228d4dec83" + }, + "m_SlotId": -680323842 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "984badfcb5794de7a0a3c73aad214424" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "42e844f32f9d4f9c8b1ae224e5fc3945" + }, + "m_SlotId": 0 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "b3ec873b636b4d5b8937046e2e4a8fd0" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "90a9730731e049ff8ef6141640f6688a" + }, + "m_SlotId": 3 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "b56bd8c5dc7f4c0995d2719333b75ae3" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "5b3a52fa2f644eba8d875cb740c046d8" + }, + "m_SlotId": 1190027673 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "cf9f1904491b4e7194a904b8667c095b" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "5b3a52fa2f644eba8d875cb740c046d8" + }, + "m_SlotId": 1334702512 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "d4ae4c6b2dfd4ecc8bda0ad6c347b5b4" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "7aaaeff70c1b4e96968af1228d4dec83" + }, + "m_SlotId": -1281716962 + } + } + ], + "m_VertexContext": { + "m_Position": { + "x": 0.0, + "y": 0.0 + }, + "m_Blocks": [ + { + "m_Id": "dd069819e9944918930b6a6cd9ef4b2c" + }, + { + "m_Id": "c5489d276f804363b0f79fdbdfc366c3" + }, + { + "m_Id": "3c86daa3f6e749fc9f2ae95560e7a960" + } + ] + }, + "m_FragmentContext": { + "m_Position": { + "x": 0.0, + "y": 200.0 + }, + "m_Blocks": [ + { + "m_Id": "f09876534ca746799e79391c0b945f7f" + }, + { + "m_Id": "17c500272541433797ef87d56cbbeb7a" + }, + { + "m_Id": "8ba36c99c6424cd6ab60f8b90bda9101" + }, + { + "m_Id": "42e844f32f9d4f9c8b1ae224e5fc3945" + } + ] + }, + "m_PreviewData": { + "serializedMesh": { + "m_SerializedMesh": "{\"mesh\":{\"instanceID\":0}}", + "m_Guid": "" + }, + "preventRotation": false + }, + "m_Path": "Rive/High Definition Render Pipeline", + "m_GraphPrecision": 1, + "m_PreviewMode": 2, + "m_OutputNode": { + "m_Id": "" + }, + "m_SubDatas": [], + "m_ActiveTargets": [ + { + "m_Id": "ba290823e9c74067bd7921f623e9e2c1" + } + ] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector3MaterialSlot", + "m_ObjectId": "087e07dad43446d6b0bbe336c500aab7", + "m_Id": 1, + "m_DisplayName": "Out_BaseColor", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out_BaseColor", + "m_StageCapability": 2, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 1, + "m_Type": "UnityEditor.ShaderGraph.Internal.Vector1ShaderProperty", + "m_ObjectId": "14a2513875cd4bedad31bc3434dce4ed", + "m_Guid": { + "m_GuidSerialized": "ad5aef4d-941b-4689-9c6c-9e075d042fe1" + }, + "m_Name": "Cutoff", + "m_DefaultRefNameVersion": 1, + "m_RefNameGeneratedByDisplayName": "Cutoff", + "m_DefaultReferenceName": "_Cutoff", + "m_OverrideReferenceName": "", + "m_GeneratePropertyBlock": true, + "m_UseCustomSlotLabel": false, + "m_CustomSlotLabel": "", + "m_DismissedVersion": 0, + "m_Precision": 0, + "overrideHLSLDeclaration": false, + "hlslDeclarationOverride": 0, + "m_Hidden": false, + "m_Value": 0.5, + "m_FloatType": 1, + "m_RangeValues": { + "x": 0.0, + "y": 1.0 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "17c500272541433797ef87d56cbbeb7a", + "m_Group": { + "m_Id": "" + }, + "m_Name": "SurfaceDescription.Emission", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "f61bb2d0e76b44ec9f14184fbd531409" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "SurfaceDescription.Emission" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "185b8a82456c4fe6970ca6e51d753a79", + "m_Id": 0, + "m_DisplayName": "Cutoff", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out", + "m_StageCapability": 3, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.Rendering.HighDefinition.ShaderGraph.BuiltinData", + "m_ObjectId": "193843b4017941d1a6077704ff23d8da", + "m_Distortion": false, + "m_DistortionMode": 0, + "m_DistortionDepthTest": true, + "m_AddPrecomputedVelocity": false, + "m_TransparentWritesMotionVec": false, + "m_DepthOffset": false, + "m_ConservativeDepthOffset": false, + "m_TransparencyFog": true, + "m_AlphaTestShadow": false, + "m_BackThenFrontRendering": false, + "m_TransparentDepthPrepass": false, + "m_TransparentDepthPostpass": false, + "m_SupportLodCrossFade": false +} + +{ + "m_SGVersion": 3, + "m_Type": "UnityEditor.ShaderGraph.Internal.ColorShaderProperty", + "m_ObjectId": "198ebeb0d8144e908f0c502b8bae3c6f", + "m_Guid": { + "m_GuidSerialized": "8e48ead8-51a7-43dd-bb49-9d5ce1a981c4" + }, + "m_Name": "BaseColor", + "m_DefaultRefNameVersion": 1, + "m_RefNameGeneratedByDisplayName": "BaseColor", + "m_DefaultReferenceName": "_BaseColor", + "m_OverrideReferenceName": "", + "m_GeneratePropertyBlock": true, + "m_UseCustomSlotLabel": false, + "m_CustomSlotLabel": "", + "m_DismissedVersion": 0, + "m_Precision": 0, + "overrideHLSLDeclaration": false, + "hlslDeclarationOverride": 0, + "m_Hidden": false, + "m_Value": { + "r": 1.0, + "g": 1.0, + "b": 1.0, + "a": 1.0 + }, + "isMainColor": true, + "m_ColorMode": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.PositionMaterialSlot", + "m_ObjectId": "1c55619dc5a943669b293d53b2f2292f", + "m_Id": 0, + "m_DisplayName": "Position", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Position", + "m_StageCapability": 1, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [], + "m_Space": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector4MaterialSlot", + "m_ObjectId": "1db460f1f6d5407f887ddf42267f6c59", + "m_Id": 0, + "m_DisplayName": "BaseColor", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out", + "m_StageCapability": 3, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.Rendering.HighDefinition.ShaderGraph.HDUnlitData", + "m_ObjectId": "229acb6557564fae91f524637b71c0d6", + "m_EnableShadowMatte": false, + "m_DistortionOnly": false +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.Rendering.HighDefinition.ShaderGraph.SystemData", + "m_ObjectId": "2bb08f5be0ad48f1a86bc9cea5ceb4e2", + "m_MaterialNeedsUpdateHash": 1, + "m_SurfaceType": 1, + "m_RenderingPass": 4, + "m_BlendMode": 0, + "m_ZTest": 4, + "m_ZWrite": false, + "m_TransparentCullMode": 2, + "m_OpaqueCullMode": 2, + "m_SortPriority": 0, + "m_AlphaTest": true, + "m_ExcludeFromTUAndAA": false, + "m_TransparentDepthPrepass": false, + "m_TransparentDepthPostpass": false, + "m_SupportLodCrossFade": false, + "m_DoubleSidedMode": 0, + "m_DOTSInstancing": false, + "m_CustomVelocity": false, + "m_Tessellation": false, + "m_TessellationMode": 0, + "m_TessellationFactorMinDistance": 20.0, + "m_TessellationFactorMaxDistance": 50.0, + "m_TessellationFactorTriangleSize": 100.0, + "m_TessellationShapeFactor": 0.75, + "m_TessellationBackFaceCullEpsilon": -0.25, + "m_TessellationMaxDisplacement": 0.009999999776482582, + "m_Version": 1, + "inspectorFoldoutMask": 1 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "2fc55180791d48eda9d792b9dfa84589", + "m_Id": 2, + "m_DisplayName": "Intensity", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Intensity", + "m_StageCapability": 3, + "m_Value": 1.0, + "m_DefaultValue": 1.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector4MaterialSlot", + "m_ObjectId": "2fca64b3b48542d895cd9e9c638ef191", + "m_Id": -1281716962, + "m_DisplayName": "EmissionColor", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "_EmissionColor", + "m_StageCapability": 2, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Texture2DMaterialSlot", + "m_ObjectId": "32447e534670474ba5ea577b4b1a347d", + "m_Id": 0, + "m_DisplayName": "BaseMap", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out", + "m_StageCapability": 3, + "m_BareResource": false +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.ColorRGBMaterialSlot", + "m_ObjectId": "32e809adcc8b49a2bb69a2a09d161409", + "m_Id": 0, + "m_DisplayName": "Output", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Output", + "m_StageCapability": 3, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [], + "m_ColorMode": 1, + "m_DefaultColor": { + "r": 0.0, + "g": 0.0, + "b": 0.0, + "a": 1.0 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.NormalMaterialSlot", + "m_ObjectId": "3a8648c6730747c2aa7c211ebd1db6c8", + "m_Id": 0, + "m_DisplayName": "Normal", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Normal", + "m_StageCapability": 1, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [], + "m_Space": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector4MaterialSlot", + "m_ObjectId": "3b71ebada7334d2eb709592e968357ae", + "m_Id": 1190027673, + "m_DisplayName": "BaseColor", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "_BaseColor", + "m_StageCapability": 2, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "3c86daa3f6e749fc9f2ae95560e7a960", + "m_Group": { + "m_Id": "" + }, + "m_Name": "VertexDescription.Tangent", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "cd741f82d9664aa7a9cc694a78111b2b" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "VertexDescription.Tangent" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.ColorRGBMaterialSlot", + "m_ObjectId": "418faedce56b49c3a7b0502f184e9c99", + "m_Id": 0, + "m_DisplayName": "Base Color", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "BaseColor", + "m_StageCapability": 2, + "m_Value": { + "x": 0.5, + "y": 0.5, + "z": 0.5 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [], + "m_ColorMode": 0, + "m_DefaultColor": { + "r": 0.5, + "g": 0.5, + "b": 0.5, + "a": 1.0 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "423a781e92924d9fb334ed621d889c0a", + "m_Id": 0, + "m_DisplayName": "Alpha Clip Threshold", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "AlphaClipThreshold", + "m_StageCapability": 2, + "m_Value": 0.5, + "m_DefaultValue": 0.5, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "42e844f32f9d4f9c8b1ae224e5fc3945", + "m_Group": { + "m_Id": "" + }, + "m_Name": "SurfaceDescription.AlphaClipThreshold", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "423a781e92924d9fb334ed621d889c0a" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "SurfaceDescription.AlphaClipThreshold" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.GroupData", + "m_ObjectId": "4d185a851d114c7a97fcc7dcf0ee53f0", + "m_Title": "Main Texture", + "m_Position": { + "x": -706.6890258789063, + "y": -200.8223419189453 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "536de08bf33049888a29f2bfdc6e6e2d", + "m_Id": 3, + "m_DisplayName": "Exposure Weight", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Exposure Weight", + "m_StageCapability": 3, + "m_Value": 1.0, + "m_DefaultValue": 1.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.SubGraphNode", + "m_ObjectId": "5b3a52fa2f644eba8d875cb740c046d8", + "m_Group": { + "m_Id": "4d185a851d114c7a97fcc7dcf0ee53f0" + }, + "m_Name": "SampleMainRiveTexture", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -350.5000305175781, + "y": -142.49996948242188, + "width": 235.5000457763672, + "height": 302.9999694824219 + } + }, + "m_Slots": [ + { + "m_Id": "afe96a5b2a074ba6bf064e23a3c5dc25" + }, + { + "m_Id": "3b71ebada7334d2eb709592e968357ae" + }, + { + "m_Id": "087e07dad43446d6b0bbe336c500aab7" + }, + { + "m_Id": "9e92538bad0e452fab7adf86ce82f44a" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedSubGraph": "{\n \"subGraph\": {\n \"fileID\": -5475051401550479605,\n \"guid\": \"287ae8d259edf47cf9ec073950debe11\",\n \"type\": 3\n }\n}", + "m_PropertyGuids": [ + "4b65a152-6b9e-429e-bbc1-bebac7fac8fc", + "0dafdea0-1c0d-40c7-9a2f-3553ae8cb358" + ], + "m_PropertyIds": [ + 1334702512, + 1190027673 + ], + "m_Dropdowns": [], + "m_DropdownSelectedEntries": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector4MaterialSlot", + "m_ObjectId": "5cffc8b18ff84645a013a145c406112b", + "m_Id": 1, + "m_DisplayName": "Out_Emission", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out_Emission", + "m_StageCapability": 2, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.Rendering.HighDefinition.ShaderGraph.HDUnlitSubTarget", + "m_ObjectId": "5d0b637753844b84a1ffd935c75aebaa" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Internal.Texture2DShaderProperty", + "m_ObjectId": "63c10ad36e224cbe8900b6eb225cfa65", + "m_Guid": { + "m_GuidSerialized": "7d228967-d6c1-4953-a522-94e24f7f4fde" + }, + "m_Name": "EmissionMap", + "m_DefaultRefNameVersion": 1, + "m_RefNameGeneratedByDisplayName": "EmissionMap", + "m_DefaultReferenceName": "_EmissionMap", + "m_OverrideReferenceName": "", + "m_GeneratePropertyBlock": true, + "m_UseCustomSlotLabel": false, + "m_CustomSlotLabel": "", + "m_DismissedVersion": 0, + "m_Precision": 0, + "overrideHLSLDeclaration": false, + "hlslDeclarationOverride": 0, + "m_Hidden": false, + "m_Value": { + "m_SerializedTexture": "{\"texture\":{\"instanceID\":0}}", + "m_Guid": "" + }, + "isMainTexture": false, + "useTilingAndOffset": false, + "m_Modifiable": true, + "m_DefaultType": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Texture2DInputMaterialSlot", + "m_ObjectId": "6d73a920f8cf419ea2a864faa7a3177b", + "m_Id": -680323842, + "m_DisplayName": "EmissionMap", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "_EmissionMap", + "m_StageCapability": 2, + "m_BareResource": false, + "m_Texture": { + "m_SerializedTexture": "{\"texture\":{\"instanceID\":0}}", + "m_Guid": "" + }, + "m_DefaultType": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Internal.Texture2DShaderProperty", + "m_ObjectId": "75b4318b313e45bf86467b06b66a8bd1", + "m_Guid": { + "m_GuidSerialized": "25125037-7122-4fba-a083-f7d027317299" + }, + "m_Name": "BaseMap", + "m_DefaultRefNameVersion": 1, + "m_RefNameGeneratedByDisplayName": "BaseMap", + "m_DefaultReferenceName": "_BaseMap", + "m_OverrideReferenceName": "", + "m_GeneratePropertyBlock": true, + "m_UseCustomSlotLabel": false, + "m_CustomSlotLabel": "", + "m_DismissedVersion": 0, + "m_Precision": 0, + "overrideHLSLDeclaration": false, + "hlslDeclarationOverride": 2, + "m_Hidden": false, + "m_Value": { + "m_SerializedTexture": "{\"texture\":{\"instanceID\":0}}", + "m_Guid": "" + }, + "isMainTexture": true, + "useTilingAndOffset": true, + "m_Modifiable": true, + "m_DefaultType": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.SubGraphNode", + "m_ObjectId": "7aaaeff70c1b4e96968af1228d4dec83", + "m_Group": { + "m_Id": "e5caeb6982484141b0639405aaefae6c" + }, + "m_Name": "SampleEmission", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -470.9999084472656, + "y": 453.0000305175781, + "width": 248.49990844726563, + "height": 302.9999084472656 + } + }, + "m_Slots": [ + { + "m_Id": "2fca64b3b48542d895cd9e9c638ef191" + }, + { + "m_Id": "6d73a920f8cf419ea2a864faa7a3177b" + }, + { + "m_Id": "5cffc8b18ff84645a013a145c406112b" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedSubGraph": "{\n \"subGraph\": {\n \"fileID\": -5475051401550479605,\n \"guid\": \"c3bbcf1d5b5ee446baa01a87b8e5dadf\",\n \"type\": 3\n }\n}", + "m_PropertyGuids": [ + "417ee71e-80a1-414f-b809-df8c19e3743f", + "9fae8bf3-f659-4d48-8efb-5f8bda92ca8e", + "0d74976b-fbf8-4395-8137-14c541e8d2c5" + ], + "m_PropertyIds": [ + -1281716962, + -680323842, + 1311224659 + ], + "m_Dropdowns": [], + "m_DropdownSelectedEntries": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.CategoryData", + "m_ObjectId": "7f5ba364662e4aa3aab4c078c2711899", + "m_Name": "", + "m_ChildObjectList": [ + { + "m_Id": "75b4318b313e45bf86467b06b66a8bd1" + }, + { + "m_Id": "198ebeb0d8144e908f0c502b8bae3c6f" + }, + { + "m_Id": "63c10ad36e224cbe8900b6eb225cfa65" + }, + { + "m_Id": "f654e1fdd5a54e4f98f7cc912b6792fc" + }, + { + "m_Id": "c0e72895fc20431c95cb85ee1ffae633" + }, + { + "m_Id": "14a2513875cd4bedad31bc3434dce4ed" + } + ] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector4MaterialSlot", + "m_ObjectId": "83cc5d66470e44c5ae264ed84ee79c80", + "m_Id": 0, + "m_DisplayName": "EmissiveColor", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out", + "m_StageCapability": 3, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "8ba36c99c6424cd6ab60f8b90bda9101", + "m_Group": { + "m_Id": "" + }, + "m_Name": "SurfaceDescription.Alpha", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "c672c7efa127483dbd32d758d615728c" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "SurfaceDescription.Alpha" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.ColorRGBMaterialSlot", + "m_ObjectId": "8fb4c23d4d1c4e9a95514a3f2499c8f1", + "m_Id": 1, + "m_DisplayName": "Color", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Color", + "m_StageCapability": 3, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [], + "m_ColorMode": 0, + "m_DefaultColor": { + "r": 0.0, + "g": 0.0, + "b": 0.0, + "a": 1.0 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.Rendering.HighDefinition.EmissionNode", + "m_ObjectId": "90a9730731e049ff8ef6141640f6688a", + "m_Group": { + "m_Id": "e5caeb6982484141b0639405aaefae6c" + }, + "m_Name": "Emission Node", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 45.0001106262207, + "y": 447.50006103515627, + "width": 225.4999542236328, + "height": 185.49993896484376 + } + }, + "m_Slots": [ + { + "m_Id": "8fb4c23d4d1c4e9a95514a3f2499c8f1" + }, + { + "m_Id": "2fc55180791d48eda9d792b9dfa84589" + }, + { + "m_Id": "536de08bf33049888a29f2bfdc6e6e2d" + }, + { + "m_Id": "32e809adcc8b49a2bb69a2a09d161409" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "_intensityUnit": 0, + "m_NormalizeColor": false +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.PropertyNode", + "m_ObjectId": "918839ed8d6744f188ac75a1434fa0af", + "m_Group": { + "m_Id": "e5caeb6982484141b0639405aaefae6c" + }, + "m_Name": "Property", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -829.4999389648438, + "y": 528.0000610351563, + "width": 152.50006103515626, + "height": 33.9998779296875 + } + }, + "m_Slots": [ + { + "m_Id": "96ee09c525194347bb67e0f8463f3cff" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_Property": { + "m_Id": "63c10ad36e224cbe8900b6eb225cfa65" + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Texture2DMaterialSlot", + "m_ObjectId": "96ee09c525194347bb67e0f8463f3cff", + "m_Id": 0, + "m_DisplayName": "EmissionMap", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out", + "m_StageCapability": 3, + "m_BareResource": false +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.PropertyNode", + "m_ObjectId": "984badfcb5794de7a0a3c73aad214424", + "m_Group": { + "m_Id": "" + }, + "m_Name": "Property", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -212.50425720214845, + "y": 355.0482482910156, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "185b8a82456c4fe6970ca6e51d753a79" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_Property": { + "m_Id": "14a2513875cd4bedad31bc3434dce4ed" + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "9e92538bad0e452fab7adf86ce82f44a", + "m_Id": 2, + "m_DisplayName": "Out_Alpha", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out_Alpha", + "m_StageCapability": 2, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "a87005b8debd40559b7b7bb164da73ad", + "m_Id": 0, + "m_DisplayName": "EmissiveExposureWeight", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out", + "m_StageCapability": 3, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Texture2DInputMaterialSlot", + "m_ObjectId": "afe96a5b2a074ba6bf064e23a3c5dc25", + "m_Id": 1334702512, + "m_DisplayName": "BaseMap", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "_BaseMap", + "m_StageCapability": 2, + "m_BareResource": false, + "m_Texture": { + "m_SerializedTexture": "{\"texture\":{\"instanceID\":0}}", + "m_Guid": "" + }, + "m_DefaultType": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.PropertyNode", + "m_ObjectId": "b3ec873b636b4d5b8937046e2e4a8fd0", + "m_Group": { + "m_Id": "e5caeb6982484141b0639405aaefae6c" + }, + "m_Name": "Property", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -188.99986267089845, + "y": 616.0, + "width": 205.99998474121095, + "height": 34.00006103515625 + } + }, + "m_Slots": [ + { + "m_Id": "a87005b8debd40559b7b7bb164da73ad" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_Property": { + "m_Id": "c0e72895fc20431c95cb85ee1ffae633" + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.PropertyNode", + "m_ObjectId": "b56bd8c5dc7f4c0995d2719333b75ae3", + "m_Group": { + "m_Id": "4d185a851d114c7a97fcc7dcf0ee53f0" + }, + "m_Name": "Property", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -681.5, + "y": -74.00000762939453, + "width": 130.5, + "height": 34.0000114440918 + } + }, + "m_Slots": [ + { + "m_Id": "1db460f1f6d5407f887ddf42267f6c59" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_Property": { + "m_Id": "198ebeb0d8144e908f0c502b8bae3c6f" + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.Rendering.HighDefinition.ShaderGraph.HDTarget", + "m_ObjectId": "ba290823e9c74067bd7921f623e9e2c1", + "m_ActiveSubTarget": { + "m_Id": "5d0b637753844b84a1ffd935c75aebaa" + }, + "m_Datas": [ + { + "m_Id": "193843b4017941d1a6077704ff23d8da" + }, + { + "m_Id": "2bb08f5be0ad48f1a86bc9cea5ceb4e2" + }, + { + "m_Id": "229acb6557564fae91f524637b71c0d6" + } + ], + "m_CustomEditorGUI": "", + "m_SupportVFX": false, + "m_SupportComputeForVertexSetup": false +} + +{ + "m_SGVersion": 1, + "m_Type": "UnityEditor.ShaderGraph.Internal.Vector1ShaderProperty", + "m_ObjectId": "c0e72895fc20431c95cb85ee1ffae633", + "m_Guid": { + "m_GuidSerialized": "c5eac1ab-91a9-47ce-a2ec-df0ae241554b" + }, + "m_Name": "EmissiveExposureWeight", + "m_DefaultRefNameVersion": 1, + "m_RefNameGeneratedByDisplayName": "EmissiveExposureWeight", + "m_DefaultReferenceName": "_EmissiveExposureWeight", + "m_OverrideReferenceName": "", + "m_GeneratePropertyBlock": true, + "m_UseCustomSlotLabel": false, + "m_CustomSlotLabel": "", + "m_DismissedVersion": 0, + "m_Precision": 0, + "overrideHLSLDeclaration": false, + "hlslDeclarationOverride": 0, + "m_Hidden": false, + "m_Value": 1.0, + "m_FloatType": 1, + "m_RangeValues": { + "x": 0.0, + "y": 1.0 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "c5489d276f804363b0f79fdbdfc366c3", + "m_Group": { + "m_Id": "" + }, + "m_Name": "VertexDescription.Normal", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "3a8648c6730747c2aa7c211ebd1db6c8" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "VertexDescription.Normal" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "c672c7efa127483dbd32d758d615728c", + "m_Id": 0, + "m_DisplayName": "Alpha", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Alpha", + "m_StageCapability": 2, + "m_Value": 1.0, + "m_DefaultValue": 1.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.TangentMaterialSlot", + "m_ObjectId": "cd741f82d9664aa7a9cc694a78111b2b", + "m_Id": 0, + "m_DisplayName": "Tangent", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Tangent", + "m_StageCapability": 1, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [], + "m_Space": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.PropertyNode", + "m_ObjectId": "cf9f1904491b4e7194a904b8667c095b", + "m_Group": { + "m_Id": "4d185a851d114c7a97fcc7dcf0ee53f0" + }, + "m_Name": "Property", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -681.5, + "y": -142.49996948242188, + "width": 132.0, + "height": 34.0 + } + }, + "m_Slots": [ + { + "m_Id": "32447e534670474ba5ea577b4b1a347d" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_Property": { + "m_Id": "75b4318b313e45bf86467b06b66a8bd1" + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.PropertyNode", + "m_ObjectId": "d4ae4c6b2dfd4ecc8bda0ad6c347b5b4", + "m_Group": { + "m_Id": "" + }, + "m_Name": "Property", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -682.3529663085938, + "y": 464.9252624511719, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "83cc5d66470e44c5ae264ed84ee79c80" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_Property": { + "m_Id": "f654e1fdd5a54e4f98f7cc912b6792fc" + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "dd069819e9944918930b6a6cd9ef4b2c", + "m_Group": { + "m_Id": "" + }, + "m_Name": "VertexDescription.Position", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "1c55619dc5a943669b293d53b2f2292f" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "VertexDescription.Position" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.GroupData", + "m_ObjectId": "e5caeb6982484141b0639405aaefae6c", + "m_Title": "Emission", + "m_Position": { + "x": -854.682861328125, + "y": 388.90106201171877 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "f09876534ca746799e79391c0b945f7f", + "m_Group": { + "m_Id": "" + }, + "m_Name": "SurfaceDescription.BaseColor", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "418faedce56b49c3a7b0502f184e9c99" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "SurfaceDescription.BaseColor" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.ColorRGBMaterialSlot", + "m_ObjectId": "f61bb2d0e76b44ec9f14184fbd531409", + "m_Id": 0, + "m_DisplayName": "Emission", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Emission", + "m_StageCapability": 2, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [], + "m_ColorMode": 1, + "m_DefaultColor": { + "r": 0.0, + "g": 0.0, + "b": 0.0, + "a": 1.0 + } +} + +{ + "m_SGVersion": 3, + "m_Type": "UnityEditor.ShaderGraph.Internal.ColorShaderProperty", + "m_ObjectId": "f654e1fdd5a54e4f98f7cc912b6792fc", + "m_Guid": { + "m_GuidSerialized": "029c05f7-1347-4544-a072-adaf3c288d01" + }, + "m_Name": "EmissiveColor", + "m_DefaultRefNameVersion": 1, + "m_RefNameGeneratedByDisplayName": "EmissiveColor", + "m_DefaultReferenceName": "_EmissiveColor", + "m_OverrideReferenceName": "", + "m_GeneratePropertyBlock": true, + "m_UseCustomSlotLabel": false, + "m_CustomSlotLabel": "", + "m_DismissedVersion": 0, + "m_Precision": 0, + "overrideHLSLDeclaration": false, + "hlslDeclarationOverride": 0, + "m_Hidden": false, + "m_Value": { + "r": 0.0, + "g": 0.0, + "b": 0.0, + "a": 0.0 + }, + "isMainColor": false, + "m_ColorMode": 1 +} + diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/HDRP/Shaders/Unlit.shadergraph.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/HDRP/Shaders/Unlit.shadergraph.meta new file mode 100644 index 00000000..171e7442 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/HDRP/Shaders/Unlit.shadergraph.meta @@ -0,0 +1,17 @@ +fileFormatVersion: 2 +guid: 511c099da70f649f4b1c0ef83a8c70f4 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: 625f186215c104763be7675aa2d941aa, type: 3} +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/HDRP/Shaders/Unlit.shadergraph + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/IRenderPipelineHandler.cs b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/IRenderPipelineHandler.cs new file mode 100644 index 00000000..1404429d --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/IRenderPipelineHandler.cs @@ -0,0 +1,61 @@ +using UnityEngine; + +namespace Rive.Components +{ + /// + /// Interface for a render pipeline handler. The render pipeline handler is responsible for registering and unregistering renderers with the render pipeline. + /// + public interface IRenderPipelineHandler + { + /// + /// Registers a renderer with the handler. This tells the render pipeline to execute the renderer's render commands. + /// + /// The Rive renderer to register + void Register(IRenderer renderer); + + /// + /// Unregisters a renderer with the handler. This tells the render pipeline to stop executing the renderer's render commands. + /// + /// The Rive renderer to unregister + void Unregister(IRenderer renderer); + + /// + /// Returns true if the renderer is registered with the handler. + /// + /// The Rive renderer to check + /// True if the renderer is registered with the handler + bool IsRendererRegistered(IRenderer renderer); + + /// + /// Allocates a render texture with the specified width and height. + /// + /// The width of the render texture + /// The height of the render texture + /// The allocated render texture + RenderTexture AllocateRenderTexture(int width, int height); + + + /// + /// Releases a render texture. + /// + /// The render texture to release + void ReleaseRenderTexture(RenderTexture renderTexture); + + /// + /// Resize a render texture to the specified width and height. + /// + /// The render texture to resize + /// The new width of the render texture + /// The new height of the render texture + /// + RenderTexture ResizeRenderTexture(RenderTexture renderTexture, int width, int height); + + /// + /// Sets the render texture for the specified renderer. This tells the render pipeline handler to use the specified render texture for rendering. + /// + /// The Rive renderer to set the render texture for + /// The render texture to set + void SetRendererTexture(IRenderer renderer, RenderTexture renderTexture); + + } +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/IRenderPipelineHandler.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/IRenderPipelineHandler.cs.meta new file mode 100644 index 00000000..d2144cb4 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/IRenderPipelineHandler.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 822d542e4449f468f9c5eaf1af87f18f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/IRenderPipelineHandler.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/URP.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/URP.meta new file mode 100644 index 00000000..f7de701b --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/URP.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 04fc77c7b453740f48a56320eaf7e250 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/URP/RenderPass.cs b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/URP/RenderPass.cs new file mode 100644 index 00000000..37c51838 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/URP/RenderPass.cs @@ -0,0 +1,121 @@ +#if RIVE_USING_URP +using UnityEngine; +using UnityEngine.Rendering; +#if UNITY_2023_1_OR_NEWER +using UnityEngine.Rendering.RenderGraphModule; +#endif +using UnityEngine.Rendering.Universal; +namespace Rive.Components.URP +{ + internal class RenderPass : ScriptableRenderPass + { + private IRenderer m_riveRenderer; + + private ProfilingSampler m_profilingSampler; + + private const string m_bufferName = "Rive Render Pass"; + + + internal RenderPass() + { + // Default constructor for object pooling + } + + public RenderPass(Renderer riveRenderer, RenderPassEvent passEvent, string profilerMarkerName) + { + if (riveRenderer == null) + throw new System.ArgumentNullException(nameof(riveRenderer)); + + this.Init(riveRenderer, passEvent, profilerMarkerName); + } + + internal void Init(IRenderer riveRenderer, RenderPassEvent passEvent, string profilerMarkerName) + { + m_riveRenderer = riveRenderer; + renderPassEvent = passEvent; + m_profilingSampler = new ProfilingSampler(profilerMarkerName); + } + + + +#if UNITY_2023_1_OR_NEWER + private class PassData + { + internal Renderer riveRenderer; + } + + + public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData) + { + if (m_riveRenderer == null) return; + + Renderer renderer = m_riveRenderer as Renderer; + + if (renderer == null) return; + + // Since we're not using most of the RenderGraph features, we can use AddUnsafePass instead of AddRasterRenderPass. + // In this mode, we're required to handle/set up graphics state, which we already do in c++. + // By using AddUnsafePass, we avoid the overhead of having to call SetRenderAttachment as required by AddRasterRenderPass. + // More info: https://docs.unity.cn/Packages/com.unity.render-pipelines.core@17.0/api/UnityEngine.Rendering.RenderGraphModule.RenderGraph.html#UnityEngine_Rendering_RenderGraphModule_RenderGraph_AddUnsafePass__1_System_String___0__ + using (var builder = renderGraph.AddUnsafePass("Rive Render Pass", out var passData)) + { + passData.riveRenderer = renderer; + + // Prevent render graph from culling this pass + builder.AllowPassCulling(false); + + + builder.SetRenderFunc((PassData data, UnsafeGraphContext context) => + { + ((Renderer)data.riveRenderer).AddToCommandBuffer(context.cmd); + }); + } + } +#endif + // Unity 6.4 / URP 17.4 no longer exposes the compatibility Execute override on + // ScriptableRenderPass, so we only compile this path on older versions. + // On supported older versions, we keep it so that Rive rendering still works without RenderGraph when in Compatibility mode. +#if UNITY_2023_1_OR_NEWER && !UNITY_6000_4_OR_NEWER + [System.Obsolete] +#endif +#if !UNITY_6000_4_OR_NEWER + public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData) + { + + if (m_riveRenderer == null) + { + return; + } + + CommandBuffer cmd = CommandBufferPool.Get(m_bufferName); + + using (new ProfilingScope(cmd, m_profilingSampler)) + { + m_riveRenderer.AddToCommandBuffer(cmd); + + } + + + context.ExecuteCommandBuffer(cmd); + CommandBufferPool.Release(cmd); + } +#endif + + public IRenderer GetRenderer() + { + return m_riveRenderer; + } + + public void UpdateRenderer(IRenderer renderer) + { + m_riveRenderer = renderer; + } + + public void UpdateRenderPassEvent(RenderPassEvent passEvent) + { + renderPassEvent = passEvent; + } + + } +} +#endif \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/URP/RenderPass.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/URP/RenderPass.cs.meta new file mode 100644 index 00000000..1434b661 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/URP/RenderPass.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 825193055e30845f3958828afa35dc5f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/URP/RenderPass.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/URP/RenderPassPool.cs b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/URP/RenderPassPool.cs new file mode 100644 index 00000000..0e51b5f8 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/URP/RenderPassPool.cs @@ -0,0 +1,56 @@ +#if RIVE_USING_URP + +using UnityEngine.Pool; +using UnityEngine.Rendering.Universal; + +namespace Rive.Components.URP +{ + /// + /// A pool of RenderPass objects to reduce the overhead of creating and destroying them. + /// + internal class RenderPassPool + { + private ObjectPool m_pool; + + public RenderPassPool(int defaultCapacity = 10, int maxSize = 10000) + { + m_pool = new ObjectPool( + createFunc: CreateRenderPass, + actionOnGet: null, + actionOnRelease: OnReleaseRenderPass, + collectionCheck: true, + defaultCapacity: defaultCapacity, + maxSize: maxSize + ); + } + + public RenderPass Get(IRenderer riveRenderer, RenderPassEvent passEvent, string profilerMarkerName) + { + var renderPass = m_pool.Get(); + renderPass.Init(riveRenderer, passEvent, profilerMarkerName); + return renderPass; + } + + public void Release(RenderPass renderPass) + { + m_pool.Release(renderPass); + } + + private RenderPass CreateRenderPass() + { + return new RenderPass(); + } + + private void OnReleaseRenderPass(RenderPass renderPass) + { + // Reset the RenderPass state when releasing it back to the pool + renderPass.Init(null, RenderPassEvent.AfterRenderingOpaques, ""); + } + + public void Clear() + { + m_pool.Clear(); + } + } +} +#endif \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/URP/RenderPassPool.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/URP/RenderPassPool.cs.meta new file mode 100644 index 00000000..03c489f9 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/URP/RenderPassPool.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 0a79bffaf9b6f4152836303522bdb045 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/URP/RenderPassPool.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/URP/Shaders.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/URP/Shaders.meta new file mode 100644 index 00000000..71cc2925 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/URP/Shaders.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8ee1feb60dcca4276b4f135c1c462523 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/URP/Shaders/Lit.shadergraph b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/URP/Shaders/Lit.shadergraph new file mode 100644 index 00000000..7ef8405e --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/URP/Shaders/Lit.shadergraph @@ -0,0 +1,2184 @@ +{ + "m_SGVersion": 3, + "m_Type": "UnityEditor.ShaderGraph.GraphData", + "m_ObjectId": "be42bbb51ea04874840a923272a2ca51", + "m_Properties": [ + { + "m_Id": "7d5a4ae6d2d74bdbb882bcc9af57ec8c" + }, + { + "m_Id": "0813cf92747e40a1be3590e6f8f10aca" + }, + { + "m_Id": "736938f9b2d4477992ce0d5e1b2c67ec" + }, + { + "m_Id": "00473f8308054e68bf73f91612e82397" + }, + { + "m_Id": "4fab56d0354446d793c04673b5962b16" + }, + { + "m_Id": "5730dcee64f34c94ae9584c4ebd04922" + }, + { + "m_Id": "d09d6ae72a434fc0b0cf579bb39078ff" + }, + { + "m_Id": "5455964a267d4c1a809e3abf53058cb8" + } + ], + "m_Keywords": [ + { + "m_Id": "aed4ad7f5d0147998d777ef3cc7d2426" + } + ], + "m_Dropdowns": [], + "m_CategoryData": [ + { + "m_Id": "c055f67af2a649798edb9150d9d9e596" + } + ], + "m_Nodes": [ + { + "m_Id": "23adb08db2734ef79327b447af83562b" + }, + { + "m_Id": "9769617b837244c0a7232fc1d3dbfb1b" + }, + { + "m_Id": "5a99c25ea3c24d1ea3ab8e518392fd03" + }, + { + "m_Id": "67bd1c0c076d4739a438002b86d711f2" + }, + { + "m_Id": "943835c69f534645b1a7772126571304" + }, + { + "m_Id": "01b9e10fa9e94bf7893e9c8b7a885cdb" + }, + { + "m_Id": "96e775680d93405fa5ad6da92aea4087" + }, + { + "m_Id": "9ee486ab00f145f596c0be4b0447231c" + }, + { + "m_Id": "6d99b4d4d03c4bb786479ebc06189b3e" + }, + { + "m_Id": "599ea00fc37d40e1a2123ced4ee17ae8" + }, + { + "m_Id": "07d14ac616bb4659b7f607984866a1de" + }, + { + "m_Id": "c208f2afc03f45f0a8d82cc56d1bb6ce" + }, + { + "m_Id": "4b5e8c69daaf4dca8be37e1018f89467" + }, + { + "m_Id": "b95c6f45ca1d48dab6c795b9b5b9c925" + }, + { + "m_Id": "4d05cc60d1fc4ae4be5c2c9d120ecf53" + }, + { + "m_Id": "fc7ebf94393e47a7a21b73be38064276" + }, + { + "m_Id": "2122e0a185ad48d5be4c2d7cf64c54d3" + }, + { + "m_Id": "ff42a4d72e234f509e687042ecc67e78" + }, + { + "m_Id": "f555859ce36242d0882e613d4490acde" + }, + { + "m_Id": "4e95ded0a3034f56aa6cf4b21180cb64" + }, + { + "m_Id": "23153ce124104a54b1b17cc80faa63f6" + }, + { + "m_Id": "08db1323e56b4525a018dac0b42a6053" + }, + { + "m_Id": "1000fee8e9624654aab329c016417acc" + } + ], + "m_GroupDatas": [ + { + "m_Id": "4baa747411704fbcaef61b65912aa809" + }, + { + "m_Id": "b8767b3c733b43e98cf197b634bd4810" + } + ], + "m_StickyNoteDatas": [], + "m_Edges": [ + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "07d14ac616bb4659b7f607984866a1de" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "23153ce124104a54b1b17cc80faa63f6" + }, + "m_SlotId": 1334702512 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "08db1323e56b4525a018dac0b42a6053" + }, + "m_SlotId": 1 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "4e95ded0a3034f56aa6cf4b21180cb64" + }, + "m_SlotId": 1 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "1000fee8e9624654aab329c016417acc" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "ff42a4d72e234f509e687042ecc67e78" + }, + "m_SlotId": 0 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "23153ce124104a54b1b17cc80faa63f6" + }, + "m_SlotId": 1 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "67bd1c0c076d4739a438002b86d711f2" + }, + "m_SlotId": 0 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "23153ce124104a54b1b17cc80faa63f6" + }, + "m_SlotId": 2 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "2122e0a185ad48d5be4c2d7cf64c54d3" + }, + "m_SlotId": 0 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "4b5e8c69daaf4dca8be37e1018f89467" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "96e775680d93405fa5ad6da92aea4087" + }, + "m_SlotId": 0 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "4d05cc60d1fc4ae4be5c2c9d120ecf53" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "08db1323e56b4525a018dac0b42a6053" + }, + "m_SlotId": -1281716962 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "4e95ded0a3034f56aa6cf4b21180cb64" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "9ee486ab00f145f596c0be4b0447231c" + }, + "m_SlotId": 0 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "599ea00fc37d40e1a2123ced4ee17ae8" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "23153ce124104a54b1b17cc80faa63f6" + }, + "m_SlotId": 1190027673 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "b95c6f45ca1d48dab6c795b9b5b9c925" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "08db1323e56b4525a018dac0b42a6053" + }, + "m_SlotId": -680323842 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "c208f2afc03f45f0a8d82cc56d1bb6ce" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "01b9e10fa9e94bf7893e9c8b7a885cdb" + }, + "m_SlotId": 0 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "f555859ce36242d0882e613d4490acde" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "fc7ebf94393e47a7a21b73be38064276" + }, + "m_SlotId": 0 + } + } + ], + "m_VertexContext": { + "m_Position": { + "x": 308.0001220703125, + "y": -124.5 + }, + "m_Blocks": [ + { + "m_Id": "23adb08db2734ef79327b447af83562b" + }, + { + "m_Id": "9769617b837244c0a7232fc1d3dbfb1b" + }, + { + "m_Id": "5a99c25ea3c24d1ea3ab8e518392fd03" + } + ] + }, + "m_FragmentContext": { + "m_Position": { + "x": 308.0001220703125, + "y": 75.5 + }, + "m_Blocks": [ + { + "m_Id": "67bd1c0c076d4739a438002b86d711f2" + }, + { + "m_Id": "943835c69f534645b1a7772126571304" + }, + { + "m_Id": "01b9e10fa9e94bf7893e9c8b7a885cdb" + }, + { + "m_Id": "96e775680d93405fa5ad6da92aea4087" + }, + { + "m_Id": "9ee486ab00f145f596c0be4b0447231c" + }, + { + "m_Id": "6d99b4d4d03c4bb786479ebc06189b3e" + }, + { + "m_Id": "fc7ebf94393e47a7a21b73be38064276" + }, + { + "m_Id": "2122e0a185ad48d5be4c2d7cf64c54d3" + }, + { + "m_Id": "ff42a4d72e234f509e687042ecc67e78" + } + ] + }, + "m_PreviewData": { + "serializedMesh": { + "m_SerializedMesh": "{\"mesh\":{\"instanceID\":0}}", + "m_Guid": "" + }, + "preventRotation": false + }, + "m_Path": "Rive/Universal Render Pipeline", + "m_GraphPrecision": 1, + "m_PreviewMode": 2, + "m_OutputNode": { + "m_Id": "" + }, + "m_SubDatas": [], + "m_ActiveTargets": [ + { + "m_Id": "35da55e626d7485cb886114cde270bde" + } + ] +} + +{ + "m_SGVersion": 1, + "m_Type": "UnityEditor.ShaderGraph.Internal.Vector1ShaderProperty", + "m_ObjectId": "00473f8308054e68bf73f91612e82397", + "m_Guid": { + "m_GuidSerialized": "3c27b79b-f053-474c-8411-b73c460cc3e0" + }, + "m_Name": "Smoothness", + "m_DefaultRefNameVersion": 1, + "m_RefNameGeneratedByDisplayName": "Smoothness", + "m_DefaultReferenceName": "_Smoothness", + "m_OverrideReferenceName": "", + "m_GeneratePropertyBlock": true, + "m_UseCustomSlotLabel": false, + "m_CustomSlotLabel": "", + "m_DismissedVersion": 0, + "m_Precision": 0, + "overrideHLSLDeclaration": false, + "hlslDeclarationOverride": 0, + "m_Hidden": false, + "m_Value": 0.0, + "m_FloatType": 1, + "m_RangeValues": { + "x": 0.0, + "y": 1.0 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "01b9e10fa9e94bf7893e9c8b7a885cdb", + "m_Group": { + "m_Id": "" + }, + "m_Name": "SurfaceDescription.Metallic", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "159f84eeb35240de9248152334ada197" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "SurfaceDescription.Metallic" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.PropertyNode", + "m_ObjectId": "07d14ac616bb4659b7f607984866a1de", + "m_Group": { + "m_Id": "b8767b3c733b43e98cf197b634bd4810" + }, + "m_Name": "Property", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -866.0, + "y": 69.00003051757813, + "width": 137.0, + "height": 33.99993896484375 + } + }, + "m_Slots": [ + { + "m_Id": "824937d0649f40e4b934cedd2fe49ddd" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_Property": { + "m_Id": "7d5a4ae6d2d74bdbb882bcc9af57ec8c" + } +} + +{ + "m_SGVersion": 3, + "m_Type": "UnityEditor.ShaderGraph.Internal.ColorShaderProperty", + "m_ObjectId": "0813cf92747e40a1be3590e6f8f10aca", + "m_Guid": { + "m_GuidSerialized": "409db227-4b8b-4c56-a3d9-d97f5d087e18" + }, + "m_Name": "BaseColor", + "m_DefaultRefNameVersion": 1, + "m_RefNameGeneratedByDisplayName": "BaseColor", + "m_DefaultReferenceName": "_BaseColor", + "m_OverrideReferenceName": "", + "m_GeneratePropertyBlock": true, + "m_UseCustomSlotLabel": false, + "m_CustomSlotLabel": "", + "m_DismissedVersion": 0, + "m_Precision": 0, + "overrideHLSLDeclaration": false, + "hlslDeclarationOverride": 0, + "m_Hidden": false, + "m_Value": { + "r": 0.9176470637321472, + "g": 0.9176470637321472, + "b": 0.9176470637321472, + "a": 1.0 + }, + "isMainColor": true, + "m_ColorMode": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.SubGraphNode", + "m_ObjectId": "08db1323e56b4525a018dac0b42a6053", + "m_Group": { + "m_Id": "4baa747411704fbcaef61b65912aa809" + }, + "m_Name": "SampleEmission", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -520.9998779296875, + "y": 1030.0, + "width": 248.4998779296875, + "height": 303.0 + } + }, + "m_Slots": [ + { + "m_Id": "8475cf6a36e34e51b9424ce8948d28a0" + }, + { + "m_Id": "d3c0d817065c450a9ea0171f965a1160" + }, + { + "m_Id": "8f23017ecc06458d952a7276427e1f05" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedSubGraph": "{\n \"subGraph\": {\n \"fileID\": -5475051401550479605,\n \"guid\": \"c3bbcf1d5b5ee446baa01a87b8e5dadf\",\n \"type\": 3\n }\n}", + "m_PropertyGuids": [ + "417ee71e-80a1-414f-b809-df8c19e3743f", + "9fae8bf3-f659-4d48-8efb-5f8bda92ca8e", + "0d74976b-fbf8-4395-8137-14c541e8d2c5" + ], + "m_PropertyIds": [ + -1281716962, + -680323842, + 1311224659 + ], + "m_Dropdowns": [], + "m_DropdownSelectedEntries": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "0e90611521a34249b0f08a300d1fde30", + "m_Id": 0, + "m_DisplayName": "Smoothness", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out", + "m_StageCapability": 3, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.PropertyNode", + "m_ObjectId": "1000fee8e9624654aab329c016417acc", + "m_Group": { + "m_Id": "" + }, + "m_Name": "Property", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -178.5, + "y": 475.0, + "width": 103.0, + "height": 34.0 + } + }, + "m_Slots": [ + { + "m_Id": "ceda68202afd492dbe482831c417d135" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_Property": { + "m_Id": "5455964a267d4c1a809e3abf53058cb8" + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Texture2DInputMaterialSlot", + "m_ObjectId": "1065c656ec18417baf380582c74156f6", + "m_Id": 1334702512, + "m_DisplayName": "BaseMap", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "_BaseMap", + "m_StageCapability": 2, + "m_BareResource": false, + "m_Texture": { + "m_SerializedTexture": "{\"texture\":{\"instanceID\":0}}", + "m_Guid": "" + }, + "m_DefaultType": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "10d2ebfa524c48f69733f92b4e79be0e", + "m_Id": 2, + "m_DisplayName": "Out_Alpha", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out_Alpha", + "m_StageCapability": 2, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "159f84eeb35240de9248152334ada197", + "m_Id": 0, + "m_DisplayName": "Metallic", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Metallic", + "m_StageCapability": 2, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Texture2DMaterialSlot", + "m_ObjectId": "18922248a30941c4ad7c86f785853061", + "m_Id": 0, + "m_DisplayName": "EmissionMap", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out", + "m_StageCapability": 3, + "m_BareResource": false +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "2122e0a185ad48d5be4c2d7cf64c54d3", + "m_Group": { + "m_Id": "" + }, + "m_Name": "SurfaceDescription.Alpha", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "fa9901c539ef44948e56770f900425a4" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "SurfaceDescription.Alpha" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.SubGraphNode", + "m_ObjectId": "23153ce124104a54b1b17cc80faa63f6", + "m_Group": { + "m_Id": "b8767b3c733b43e98cf197b634bd4810" + }, + "m_Name": "SampleMainRiveTexture", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -533.5, + "y": 35.500030517578128, + "width": 235.5, + "height": 302.99993896484377 + } + }, + "m_Slots": [ + { + "m_Id": "1065c656ec18417baf380582c74156f6" + }, + { + "m_Id": "6cde706d62b3429baa3f8c9206adea31" + }, + { + "m_Id": "564a34b862e44589883750a739e4da5b" + }, + { + "m_Id": "10d2ebfa524c48f69733f92b4e79be0e" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedSubGraph": "{\n \"subGraph\": {\n \"fileID\": -5475051401550479605,\n \"guid\": \"287ae8d259edf47cf9ec073950debe11\",\n \"type\": 3\n }\n}", + "m_PropertyGuids": [ + "4b65a152-6b9e-429e-bbc1-bebac7fac8fc", + "0dafdea0-1c0d-40c7-9a2f-3553ae8cb358" + ], + "m_PropertyIds": [ + 1334702512, + 1190027673 + ], + "m_Dropdowns": [], + "m_DropdownSelectedEntries": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "23adb08db2734ef79327b447af83562b", + "m_Group": { + "m_Id": "" + }, + "m_Name": "VertexDescription.Position", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "bd70d260d9ac411a836054266d22c481" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "VertexDescription.Position" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.ColorRGBMaterialSlot", + "m_ObjectId": "35a5fc0bbf7f4aaba5a81144d5e6793c", + "m_Id": 0, + "m_DisplayName": "Base Color", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "BaseColor", + "m_StageCapability": 2, + "m_Value": { + "x": 0.5, + "y": 0.5, + "z": 0.5 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [], + "m_ColorMode": 0, + "m_DefaultColor": { + "r": 0.5, + "g": 0.5, + "b": 0.5, + "a": 1.0 + } +} + +{ + "m_SGVersion": 1, + "m_Type": "UnityEditor.Rendering.Universal.ShaderGraph.UniversalTarget", + "m_ObjectId": "35da55e626d7485cb886114cde270bde", + "m_Datas": [], + "m_ActiveSubTarget": { + "m_Id": "4f5002fd7e39473391aa44f6ae6bb432" + }, + "m_AllowMaterialOverride": true, + "m_SurfaceType": 1, + "m_ZTestMode": 4, + "m_ZWriteControl": 0, + "m_AlphaMode": 0, + "m_RenderFace": 2, + "m_AlphaClip": false, + "m_CastShadows": true, + "m_ReceiveShadows": true, + "m_SupportsLODCrossFade": false, + "m_CustomEditorGUI": "", + "m_SupportVFX": false +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "38cc0e713c3c4b0499ae4ff5f9247187", + "m_Id": 0, + "m_DisplayName": "Smoothness", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Smoothness", + "m_StageCapability": 2, + "m_Value": 0.5, + "m_DefaultValue": 0.5, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "3aaf7ac95a0d465cb2254bc56a0693f8", + "m_Id": 0, + "m_DisplayName": "Alpha Clip Threshold", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "AlphaClipThreshold", + "m_StageCapability": 2, + "m_Value": 0.5, + "m_DefaultValue": 0.5, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.DynamicVectorMaterialSlot", + "m_ObjectId": "3bfa29ce7a6e4a2ab63997286c434326", + "m_Id": 1, + "m_DisplayName": "On", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "On", + "m_StageCapability": 3, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.PropertyNode", + "m_ObjectId": "4b5e8c69daaf4dca8be37e1018f89467", + "m_Group": { + "m_Id": "" + }, + "m_Name": "Property", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -5.0, + "y": 672.0, + "width": 140.0001220703125, + "height": 34.0 + } + }, + "m_Slots": [ + { + "m_Id": "0e90611521a34249b0f08a300d1fde30" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_Property": { + "m_Id": "00473f8308054e68bf73f91612e82397" + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.GroupData", + "m_ObjectId": "4baa747411704fbcaef61b65912aa809", + "m_Title": "Emission", + "m_Position": { + "x": -920.5, + "y": 930.5 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.PropertyNode", + "m_ObjectId": "4d05cc60d1fc4ae4be5c2c9d120ecf53", + "m_Group": { + "m_Id": "4baa747411704fbcaef61b65912aa809" + }, + "m_Name": "Property", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -882.4998779296875, + "y": 1030.9998779296875, + "width": 151.0, + "height": 34.0 + } + }, + "m_Slots": [ + { + "m_Id": "d83a3cbd14d042939f91122475ec6c9f" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_Property": { + "m_Id": "5730dcee64f34c94ae9584c4ebd04922" + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.KeywordNode", + "m_ObjectId": "4e95ded0a3034f56aa6cf4b21180cb64", + "m_Group": { + "m_Id": "4baa747411704fbcaef61b65912aa809" + }, + "m_Name": "Emission", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.5, + "y": 1031.0, + "width": 208.0001220703125, + "height": 302.0 + } + }, + "m_Slots": [ + { + "m_Id": "e66b034bd17d454293a65f4cc89a69f6" + }, + { + "m_Id": "3bfa29ce7a6e4a2ab63997286c434326" + }, + { + "m_Id": "6edaf0696ee142c48af5561543746ca0" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_Keyword": { + "m_Id": "aed4ad7f5d0147998d777ef3cc7d2426" + } +} + +{ + "m_SGVersion": 2, + "m_Type": "UnityEditor.Rendering.Universal.ShaderGraph.UniversalLitSubTarget", + "m_ObjectId": "4f5002fd7e39473391aa44f6ae6bb432", + "m_WorkflowMode": 1, + "m_NormalDropOffSpace": 0, + "m_ClearCoat": false, + "m_BlendModePreserveSpecular": false +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Internal.Texture2DShaderProperty", + "m_ObjectId": "4fab56d0354446d793c04673b5962b16", + "m_Guid": { + "m_GuidSerialized": "e5bbf746-236f-4644-93d6-8f986fc8843c" + }, + "m_Name": "EmissionMap", + "m_DefaultRefNameVersion": 1, + "m_RefNameGeneratedByDisplayName": "EmissionMap", + "m_DefaultReferenceName": "_EmissionMap", + "m_OverrideReferenceName": "", + "m_GeneratePropertyBlock": true, + "m_UseCustomSlotLabel": false, + "m_CustomSlotLabel": "", + "m_DismissedVersion": 0, + "m_Precision": 0, + "overrideHLSLDeclaration": false, + "hlslDeclarationOverride": 0, + "m_Hidden": false, + "m_Value": { + "m_SerializedTexture": "{\"texture\":{\"instanceID\":0}}", + "m_Guid": "" + }, + "isMainTexture": false, + "useTilingAndOffset": false, + "m_Modifiable": true, + "m_DefaultType": 0 +} + +{ + "m_SGVersion": 1, + "m_Type": "UnityEditor.ShaderGraph.Internal.Vector1ShaderProperty", + "m_ObjectId": "5455964a267d4c1a809e3abf53058cb8", + "m_Guid": { + "m_GuidSerialized": "328aee4e-6ba7-4e1a-a05c-06e5563d9327" + }, + "m_Name": "Cutoff", + "m_DefaultRefNameVersion": 1, + "m_RefNameGeneratedByDisplayName": "Cutoff", + "m_DefaultReferenceName": "_Cutoff", + "m_OverrideReferenceName": "", + "m_GeneratePropertyBlock": true, + "m_UseCustomSlotLabel": false, + "m_CustomSlotLabel": "", + "m_DismissedVersion": 0, + "m_Precision": 0, + "overrideHLSLDeclaration": false, + "hlslDeclarationOverride": 2, + "m_Hidden": false, + "m_Value": 0.5, + "m_FloatType": 1, + "m_RangeValues": { + "x": 0.0, + "y": 1.0 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector3MaterialSlot", + "m_ObjectId": "564a34b862e44589883750a739e4da5b", + "m_Id": 1, + "m_DisplayName": "Out_BaseColor", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out_BaseColor", + "m_StageCapability": 2, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 3, + "m_Type": "UnityEditor.ShaderGraph.Internal.ColorShaderProperty", + "m_ObjectId": "5730dcee64f34c94ae9584c4ebd04922", + "m_Guid": { + "m_GuidSerialized": "f783df94-24f4-4a37-bb6f-2a19696506a2" + }, + "m_Name": "EmissionColor", + "m_DefaultRefNameVersion": 1, + "m_RefNameGeneratedByDisplayName": "EmissionColor", + "m_DefaultReferenceName": "_EmissionColor", + "m_OverrideReferenceName": "", + "m_GeneratePropertyBlock": true, + "m_UseCustomSlotLabel": false, + "m_CustomSlotLabel": "", + "m_DismissedVersion": 0, + "m_Precision": 0, + "overrideHLSLDeclaration": false, + "hlslDeclarationOverride": 0, + "m_Hidden": false, + "m_Value": { + "r": 0.0, + "g": 0.0, + "b": 0.0, + "a": 0.003921568859368563 + }, + "isMainColor": false, + "m_ColorMode": 1 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.PropertyNode", + "m_ObjectId": "599ea00fc37d40e1a2123ced4ee17ae8", + "m_Group": { + "m_Id": "b8767b3c733b43e98cf197b634bd4810" + }, + "m_Name": "Property", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -866.0, + "y": 120.99996948242188, + "width": 135.5, + "height": 34.00006103515625 + } + }, + "m_Slots": [ + { + "m_Id": "6f282f99c2314617bd76a9fefdea4bb0" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_Property": { + "m_Id": "0813cf92747e40a1be3590e6f8f10aca" + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "5a99c25ea3c24d1ea3ab8e518392fd03", + "m_Group": { + "m_Id": "" + }, + "m_Name": "VertexDescription.Tangent", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "a6c989315dea4e89aea933c960cba6c2" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "VertexDescription.Tangent" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "67bd1c0c076d4739a438002b86d711f2", + "m_Group": { + "m_Id": "" + }, + "m_Name": "SurfaceDescription.BaseColor", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "35a5fc0bbf7f4aaba5a81144d5e6793c" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "SurfaceDescription.BaseColor" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.NormalMaterialSlot", + "m_ObjectId": "6b6059ce48e64c4e9bea880e097df40d", + "m_Id": 0, + "m_DisplayName": "Normal", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Normal", + "m_StageCapability": 1, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [], + "m_Space": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector4MaterialSlot", + "m_ObjectId": "6cde706d62b3429baa3f8c9206adea31", + "m_Id": 1190027673, + "m_DisplayName": "BaseColor", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "_BaseColor", + "m_StageCapability": 2, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "6d99b4d4d03c4bb786479ebc06189b3e", + "m_Group": { + "m_Id": "" + }, + "m_Name": "SurfaceDescription.Occlusion", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "b2d89e8d0168468dabc9f7d4b6c32906" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "SurfaceDescription.Occlusion" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.DynamicVectorMaterialSlot", + "m_ObjectId": "6edaf0696ee142c48af5561543746ca0", + "m_Id": 2, + "m_DisplayName": "Off", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Off", + "m_StageCapability": 3, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector4MaterialSlot", + "m_ObjectId": "6f282f99c2314617bd76a9fefdea4bb0", + "m_Id": 0, + "m_DisplayName": "BaseColor", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out", + "m_StageCapability": 3, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 1, + "m_Type": "UnityEditor.ShaderGraph.Internal.Vector1ShaderProperty", + "m_ObjectId": "736938f9b2d4477992ce0d5e1b2c67ec", + "m_Guid": { + "m_GuidSerialized": "64bf31e2-7a67-4329-9f8b-126e605930d6" + }, + "m_Name": "Metallic", + "m_DefaultRefNameVersion": 1, + "m_RefNameGeneratedByDisplayName": "Metallic", + "m_DefaultReferenceName": "_Metallic", + "m_OverrideReferenceName": "", + "m_GeneratePropertyBlock": true, + "m_UseCustomSlotLabel": false, + "m_CustomSlotLabel": "", + "m_DismissedVersion": 0, + "m_Precision": 0, + "overrideHLSLDeclaration": false, + "hlslDeclarationOverride": 0, + "m_Hidden": false, + "m_Value": 0.0, + "m_FloatType": 1, + "m_RangeValues": { + "x": 0.0, + "y": 1.0 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Internal.Texture2DShaderProperty", + "m_ObjectId": "7d5a4ae6d2d74bdbb882bcc9af57ec8c", + "m_Guid": { + "m_GuidSerialized": "54398ed1-91a8-47b5-9a0b-5631d5acb8b8" + }, + "m_Name": "BaseMap", + "m_DefaultRefNameVersion": 1, + "m_RefNameGeneratedByDisplayName": "BaseMap", + "m_DefaultReferenceName": "_BaseMap", + "m_OverrideReferenceName": "", + "m_GeneratePropertyBlock": true, + "m_UseCustomSlotLabel": false, + "m_CustomSlotLabel": "", + "m_DismissedVersion": 0, + "m_Precision": 0, + "overrideHLSLDeclaration": false, + "hlslDeclarationOverride": 2, + "m_Hidden": false, + "m_Value": { + "m_SerializedTexture": "{\"texture\":{\"instanceID\":0}}", + "m_Guid": "" + }, + "isMainTexture": true, + "useTilingAndOffset": true, + "m_Modifiable": true, + "m_DefaultType": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Texture2DMaterialSlot", + "m_ObjectId": "824937d0649f40e4b934cedd2fe49ddd", + "m_Id": 0, + "m_DisplayName": "BaseMap", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out", + "m_StageCapability": 3, + "m_BareResource": false +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector4MaterialSlot", + "m_ObjectId": "8450f3a032cf4a8799269087d8ca5db2", + "m_Id": 0, + "m_DisplayName": "SpecularColor", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out", + "m_StageCapability": 3, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector4MaterialSlot", + "m_ObjectId": "8475cf6a36e34e51b9424ce8948d28a0", + "m_Id": -1281716962, + "m_DisplayName": "EmissionColor", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "_EmissionColor", + "m_StageCapability": 2, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector4MaterialSlot", + "m_ObjectId": "8f23017ecc06458d952a7276427e1f05", + "m_Id": 1, + "m_DisplayName": "Out_Emission", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out_Emission", + "m_StageCapability": 2, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.NormalMaterialSlot", + "m_ObjectId": "93ba0f1ded524c46a8118b5a94d3e050", + "m_Id": 0, + "m_DisplayName": "Normal (Tangent Space)", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "NormalTS", + "m_StageCapability": 2, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [], + "m_Space": 3 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "943835c69f534645b1a7772126571304", + "m_Group": { + "m_Id": "" + }, + "m_Name": "SurfaceDescription.NormalTS", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "93ba0f1ded524c46a8118b5a94d3e050" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "SurfaceDescription.NormalTS" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "96e775680d93405fa5ad6da92aea4087", + "m_Group": { + "m_Id": "" + }, + "m_Name": "SurfaceDescription.Smoothness", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "38cc0e713c3c4b0499ae4ff5f9247187" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "SurfaceDescription.Smoothness" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "9769617b837244c0a7232fc1d3dbfb1b", + "m_Group": { + "m_Id": "" + }, + "m_Name": "VertexDescription.Normal", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "6b6059ce48e64c4e9bea880e097df40d" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "VertexDescription.Normal" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "9ba36d916c0b41c7b349dacbc6ac63af", + "m_Id": 0, + "m_DisplayName": "Metallic", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out", + "m_StageCapability": 3, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "9ee486ab00f145f596c0be4b0447231c", + "m_Group": { + "m_Id": "" + }, + "m_Name": "SurfaceDescription.Emission", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "dfe73f50e6b947f9affb6138700394cc" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "SurfaceDescription.Emission" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.TangentMaterialSlot", + "m_ObjectId": "a6c989315dea4e89aea933c960cba6c2", + "m_Id": 0, + "m_DisplayName": "Tangent", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Tangent", + "m_StageCapability": 1, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [], + "m_Space": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.ColorRGBMaterialSlot", + "m_ObjectId": "a6d30a27d0fb4a8098593c405fccdf93", + "m_Id": 0, + "m_DisplayName": "Specular Color", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Specular", + "m_StageCapability": 2, + "m_Value": { + "x": 0.5, + "y": 0.5, + "z": 0.5 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [], + "m_ColorMode": 0, + "m_DefaultColor": { + "r": 0.5, + "g": 0.5, + "b": 0.5, + "a": 1.0 + } +} + +{ + "m_SGVersion": 1, + "m_Type": "UnityEditor.ShaderGraph.ShaderKeyword", + "m_ObjectId": "aed4ad7f5d0147998d777ef3cc7d2426", + "m_Guid": { + "m_GuidSerialized": "ddac7e60-c11c-4f06-9c65-e06890571cc5" + }, + "m_Name": "Emission", + "m_DefaultRefNameVersion": 1, + "m_RefNameGeneratedByDisplayName": "Emission", + "m_DefaultReferenceName": "_EMISSION", + "m_OverrideReferenceName": "_USE_EMISSION_ON", + "m_GeneratePropertyBlock": true, + "m_UseCustomSlotLabel": false, + "m_CustomSlotLabel": "", + "m_DismissedVersion": 0, + "m_KeywordType": 0, + "m_KeywordDefinition": 0, + "m_KeywordScope": 0, + "m_KeywordStages": 63, + "m_Entries": [], + "m_Value": 0, + "m_IsEditable": true +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "b2d89e8d0168468dabc9f7d4b6c32906", + "m_Id": 0, + "m_DisplayName": "Ambient Occlusion", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Occlusion", + "m_StageCapability": 2, + "m_Value": 1.0, + "m_DefaultValue": 1.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.GroupData", + "m_ObjectId": "b8767b3c733b43e98cf197b634bd4810", + "m_Title": "Main Texture", + "m_Position": { + "x": -890.8063354492188, + "y": -22.795249938964845 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.PropertyNode", + "m_ObjectId": "b95c6f45ca1d48dab6c795b9b5b9c925", + "m_Group": { + "m_Id": "4baa747411704fbcaef61b65912aa809" + }, + "m_Name": "Property", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -895.5, + "y": 1105.9998779296875, + "width": 152.5, + "height": 34.0001220703125 + } + }, + "m_Slots": [ + { + "m_Id": "18922248a30941c4ad7c86f785853061" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_Property": { + "m_Id": "4fab56d0354446d793c04673b5962b16" + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.PositionMaterialSlot", + "m_ObjectId": "bd70d260d9ac411a836054266d22c481", + "m_Id": 0, + "m_DisplayName": "Position", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Position", + "m_StageCapability": 1, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [], + "m_Space": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.CategoryData", + "m_ObjectId": "c055f67af2a649798edb9150d9d9e596", + "m_Name": "", + "m_ChildObjectList": [ + { + "m_Id": "7d5a4ae6d2d74bdbb882bcc9af57ec8c" + }, + { + "m_Id": "0813cf92747e40a1be3590e6f8f10aca" + }, + { + "m_Id": "736938f9b2d4477992ce0d5e1b2c67ec" + }, + { + "m_Id": "00473f8308054e68bf73f91612e82397" + }, + { + "m_Id": "aed4ad7f5d0147998d777ef3cc7d2426" + }, + { + "m_Id": "4fab56d0354446d793c04673b5962b16" + }, + { + "m_Id": "5730dcee64f34c94ae9584c4ebd04922" + }, + { + "m_Id": "d09d6ae72a434fc0b0cf579bb39078ff" + }, + { + "m_Id": "5455964a267d4c1a809e3abf53058cb8" + } + ] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.PropertyNode", + "m_ObjectId": "c208f2afc03f45f0a8d82cc56d1bb6ce", + "m_Group": { + "m_Id": "" + }, + "m_Name": "Property", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 19.5, + "y": 603.0, + "width": 115.5001220703125, + "height": 34.0 + } + }, + "m_Slots": [ + { + "m_Id": "9ba36d916c0b41c7b349dacbc6ac63af" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_Property": { + "m_Id": "736938f9b2d4477992ce0d5e1b2c67ec" + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "ceda68202afd492dbe482831c417d135", + "m_Id": 0, + "m_DisplayName": "Cutoff", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out", + "m_StageCapability": 3, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 3, + "m_Type": "UnityEditor.ShaderGraph.Internal.ColorShaderProperty", + "m_ObjectId": "d09d6ae72a434fc0b0cf579bb39078ff", + "m_Guid": { + "m_GuidSerialized": "497e5e2b-a1b2-4644-9d03-bdba3dbb506e" + }, + "m_Name": "SpecularColor", + "m_DefaultRefNameVersion": 1, + "m_RefNameGeneratedByDisplayName": "SpecularColor", + "m_DefaultReferenceName": "_SpecularColor", + "m_OverrideReferenceName": "_SpecColor", + "m_GeneratePropertyBlock": true, + "m_UseCustomSlotLabel": false, + "m_CustomSlotLabel": "", + "m_DismissedVersion": 0, + "m_Precision": 0, + "overrideHLSLDeclaration": false, + "hlslDeclarationOverride": 0, + "m_Hidden": false, + "m_Value": { + "r": 0.501960813999176, + "g": 0.501960813999176, + "b": 0.501960813999176, + "a": 1.0 + }, + "isMainColor": false, + "m_ColorMode": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Texture2DInputMaterialSlot", + "m_ObjectId": "d3c0d817065c450a9ea0171f965a1160", + "m_Id": -680323842, + "m_DisplayName": "EmissionMap", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "_EmissionMap", + "m_StageCapability": 2, + "m_BareResource": false, + "m_Texture": { + "m_SerializedTexture": "{\"texture\":{\"instanceID\":0}}", + "m_Guid": "" + }, + "m_DefaultType": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector4MaterialSlot", + "m_ObjectId": "d83a3cbd14d042939f91122475ec6c9f", + "m_Id": 0, + "m_DisplayName": "EmissionColor", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out", + "m_StageCapability": 3, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.ColorRGBMaterialSlot", + "m_ObjectId": "dfe73f50e6b947f9affb6138700394cc", + "m_Id": 0, + "m_DisplayName": "Emission", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Emission", + "m_StageCapability": 2, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [], + "m_ColorMode": 1, + "m_DefaultColor": { + "r": 0.0, + "g": 0.0, + "b": 0.0, + "a": 1.0 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.DynamicVectorMaterialSlot", + "m_ObjectId": "e66b034bd17d454293a65f4cc89a69f6", + "m_Id": 0, + "m_DisplayName": "Out", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out", + "m_StageCapability": 3, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.PropertyNode", + "m_ObjectId": "f555859ce36242d0882e613d4490acde", + "m_Group": { + "m_Id": "" + }, + "m_Name": "Property", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -45.9998779296875, + "y": 756.5, + "width": 150.4998779296875, + "height": 34.0 + } + }, + "m_Slots": [ + { + "m_Id": "8450f3a032cf4a8799269087d8ca5db2" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_Property": { + "m_Id": "d09d6ae72a434fc0b0cf579bb39078ff" + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "fa9901c539ef44948e56770f900425a4", + "m_Id": 0, + "m_DisplayName": "Alpha", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Alpha", + "m_StageCapability": 2, + "m_Value": 1.0, + "m_DefaultValue": 1.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "fc7ebf94393e47a7a21b73be38064276", + "m_Group": { + "m_Id": "" + }, + "m_Name": "SurfaceDescription.Specular", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "a6d30a27d0fb4a8098593c405fccdf93" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "SurfaceDescription.Specular" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "ff42a4d72e234f509e687042ecc67e78", + "m_Group": { + "m_Id": "" + }, + "m_Name": "SurfaceDescription.AlphaClipThreshold", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "3aaf7ac95a0d465cb2254bc56a0693f8" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "SurfaceDescription.AlphaClipThreshold" +} + diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/URP/Shaders/Lit.shadergraph.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/URP/Shaders/Lit.shadergraph.meta new file mode 100644 index 00000000..4f9ca8ed --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/URP/Shaders/Lit.shadergraph.meta @@ -0,0 +1,17 @@ +fileFormatVersion: 2 +guid: 3f7c775fc281646d8acee82c47c7016a +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: 625f186215c104763be7675aa2d941aa, type: 3} +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/URP/Shaders/Lit.shadergraph + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/URP/Shaders/Unlit.shadergraph b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/URP/Shaders/Unlit.shadergraph new file mode 100644 index 00000000..e4a35b45 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/URP/Shaders/Unlit.shadergraph @@ -0,0 +1,963 @@ +{ + "m_SGVersion": 3, + "m_Type": "UnityEditor.ShaderGraph.GraphData", + "m_ObjectId": "8a72c217aca04e8da794e3a37be1c994", + "m_Properties": [ + { + "m_Id": "0e6cbb8fa0dd44a2adbb600415866ac7" + }, + { + "m_Id": "37de38f66da04e79885d090f815c85f2" + }, + { + "m_Id": "e3dec2af43aa4aaea19b15892e1fb205" + } + ], + "m_Keywords": [], + "m_Dropdowns": [], + "m_CategoryData": [ + { + "m_Id": "97b3f2f641234bdc9115dc56f8f717f4" + } + ], + "m_Nodes": [ + { + "m_Id": "22d8082a3e004e5f82fadc7fd187409b" + }, + { + "m_Id": "1aae4ce00b5a4a72aacf335067b4d9df" + }, + { + "m_Id": "a9295c78809f4f88bbf9a98f0bd83c0e" + }, + { + "m_Id": "ca9e31a73bbc42f1add1c7c5d13d0dd3" + }, + { + "m_Id": "e58c2aa05205411cae96b18996dc21b6" + }, + { + "m_Id": "2f1ccb70104242e199ea54a5503738db" + }, + { + "m_Id": "dc75333dde6a4f05bade7f0bff7cab17" + }, + { + "m_Id": "8eb12b50125f4a1b8b39cb4465a24b8a" + }, + { + "m_Id": "9e29b3f2e47e4522b6be9d02761107fc" + }, + { + "m_Id": "aee999def90c4824aefd76e178e312eb" + } + ], + "m_GroupDatas": [ + { + "m_Id": "798620dff22b4592ae6fe625b9d0959e" + } + ], + "m_StickyNoteDatas": [], + "m_Edges": [ + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "8eb12b50125f4a1b8b39cb4465a24b8a" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "9e29b3f2e47e4522b6be9d02761107fc" + }, + "m_SlotId": 1334702512 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "9e29b3f2e47e4522b6be9d02761107fc" + }, + "m_SlotId": 1 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "ca9e31a73bbc42f1add1c7c5d13d0dd3" + }, + "m_SlotId": 0 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "9e29b3f2e47e4522b6be9d02761107fc" + }, + "m_SlotId": 2 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "e58c2aa05205411cae96b18996dc21b6" + }, + "m_SlotId": 0 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "aee999def90c4824aefd76e178e312eb" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "2f1ccb70104242e199ea54a5503738db" + }, + "m_SlotId": 0 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "dc75333dde6a4f05bade7f0bff7cab17" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "9e29b3f2e47e4522b6be9d02761107fc" + }, + "m_SlotId": 1190027673 + } + } + ], + "m_VertexContext": { + "m_Position": { + "x": 0.0, + "y": 0.0 + }, + "m_Blocks": [ + { + "m_Id": "22d8082a3e004e5f82fadc7fd187409b" + }, + { + "m_Id": "1aae4ce00b5a4a72aacf335067b4d9df" + }, + { + "m_Id": "a9295c78809f4f88bbf9a98f0bd83c0e" + } + ] + }, + "m_FragmentContext": { + "m_Position": { + "x": 0.0, + "y": 200.0 + }, + "m_Blocks": [ + { + "m_Id": "ca9e31a73bbc42f1add1c7c5d13d0dd3" + }, + { + "m_Id": "e58c2aa05205411cae96b18996dc21b6" + }, + { + "m_Id": "2f1ccb70104242e199ea54a5503738db" + } + ] + }, + "m_PreviewData": { + "serializedMesh": { + "m_SerializedMesh": "{\"mesh\":{\"instanceID\":0}}", + "m_Guid": "" + }, + "preventRotation": false + }, + "m_Path": "Rive/Universal Render Pipeline", + "m_GraphPrecision": 1, + "m_PreviewMode": 2, + "m_OutputNode": { + "m_Id": "" + }, + "m_SubDatas": [], + "m_ActiveTargets": [ + { + "m_Id": "e990e6fec6c64676a507d6a40b2f8543" + } + ] +} + +{ + "m_SGVersion": 2, + "m_Type": "UnityEditor.Rendering.Universal.ShaderGraph.UniversalUnlitSubTarget", + "m_ObjectId": "094d9ebd56e34282a396968bb312ca49" +} + +{ + "m_SGVersion": 3, + "m_Type": "UnityEditor.ShaderGraph.Internal.ColorShaderProperty", + "m_ObjectId": "0e6cbb8fa0dd44a2adbb600415866ac7", + "m_Guid": { + "m_GuidSerialized": "74e41c20-6580-4aa3-bd4b-6cd95e066ee8" + }, + "m_Name": "BaseColor", + "m_DefaultRefNameVersion": 1, + "m_RefNameGeneratedByDisplayName": "BaseColor", + "m_DefaultReferenceName": "_BaseColor", + "m_OverrideReferenceName": "", + "m_GeneratePropertyBlock": true, + "m_UseCustomSlotLabel": false, + "m_CustomSlotLabel": "", + "m_DismissedVersion": 0, + "m_Precision": 0, + "overrideHLSLDeclaration": false, + "hlslDeclarationOverride": 0, + "m_Hidden": false, + "m_Value": { + "r": 1.0, + "g": 1.0, + "b": 1.0, + "a": 1.0 + }, + "isMainColor": true, + "m_ColorMode": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "1aae4ce00b5a4a72aacf335067b4d9df", + "m_Group": { + "m_Id": "" + }, + "m_Name": "VertexDescription.Normal", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "866a5342b58e41b68a9688a76c504a1e" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "VertexDescription.Normal" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.PositionMaterialSlot", + "m_ObjectId": "1d5dd77babb548a2a1cca90455792a3c", + "m_Id": 0, + "m_DisplayName": "Position", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Position", + "m_StageCapability": 1, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [], + "m_Space": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "22d8082a3e004e5f82fadc7fd187409b", + "m_Group": { + "m_Id": "" + }, + "m_Name": "VertexDescription.Position", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "1d5dd77babb548a2a1cca90455792a3c" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "VertexDescription.Position" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Texture2DMaterialSlot", + "m_ObjectId": "28bc48b35c1e4ce89186650e5f80e5d6", + "m_Id": 0, + "m_DisplayName": "BaseMap", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out", + "m_StageCapability": 3, + "m_BareResource": false +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "2f1ccb70104242e199ea54a5503738db", + "m_Group": { + "m_Id": "" + }, + "m_Name": "SurfaceDescription.AlphaClipThreshold", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "35a70fbe5f7e409fbd225b5d5adb47e4" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "SurfaceDescription.AlphaClipThreshold" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "30051542fb7c4262905702e4edc2fe6f", + "m_Id": 0, + "m_DisplayName": "Alpha", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Alpha", + "m_StageCapability": 2, + "m_Value": 1.0, + "m_DefaultValue": 1.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "35a70fbe5f7e409fbd225b5d5adb47e4", + "m_Id": 0, + "m_DisplayName": "Alpha Clip Threshold", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "AlphaClipThreshold", + "m_StageCapability": 2, + "m_Value": 0.5, + "m_DefaultValue": 0.5, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Internal.Texture2DShaderProperty", + "m_ObjectId": "37de38f66da04e79885d090f815c85f2", + "m_Guid": { + "m_GuidSerialized": "1c5d2b01-9615-499a-84ce-1efbf5767117" + }, + "m_Name": "BaseMap", + "m_DefaultRefNameVersion": 1, + "m_RefNameGeneratedByDisplayName": "BaseMap", + "m_DefaultReferenceName": "_BaseMap", + "m_OverrideReferenceName": "", + "m_GeneratePropertyBlock": true, + "m_UseCustomSlotLabel": false, + "m_CustomSlotLabel": "", + "m_DismissedVersion": 0, + "m_Precision": 0, + "overrideHLSLDeclaration": false, + "hlslDeclarationOverride": 2, + "m_Hidden": false, + "m_Value": { + "m_SerializedTexture": "{\"texture\":{\"instanceID\":0}}", + "m_Guid": "" + }, + "isMainTexture": true, + "useTilingAndOffset": true, + "m_Modifiable": true, + "m_DefaultType": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "56252a9d762f4616a3411a77bd4cb4a0", + "m_Id": 0, + "m_DisplayName": "Cutoff", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out", + "m_StageCapability": 3, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Texture2DInputMaterialSlot", + "m_ObjectId": "5d2b140780d74aab8cc79bd6117c9f36", + "m_Id": 1334702512, + "m_DisplayName": "BaseMap", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "_BaseMap", + "m_StageCapability": 2, + "m_BareResource": false, + "m_Texture": { + "m_SerializedTexture": "{\"texture\":{\"instanceID\":0}}", + "m_Guid": "" + }, + "m_DefaultType": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector3MaterialSlot", + "m_ObjectId": "6088f2f8640c42b8a4708198e138a5b3", + "m_Id": 1, + "m_DisplayName": "Out_BaseColor", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out_BaseColor", + "m_StageCapability": 2, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "67c27cacf13d4fd4812ad7b6e441ea59", + "m_Id": 2, + "m_DisplayName": "Out_Alpha", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out_Alpha", + "m_StageCapability": 2, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.TangentMaterialSlot", + "m_ObjectId": "693e86d58ad04f5fad62c5d0ebdcb88e", + "m_Id": 0, + "m_DisplayName": "Tangent", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Tangent", + "m_StageCapability": 1, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [], + "m_Space": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.GroupData", + "m_ObjectId": "798620dff22b4592ae6fe625b9d0959e", + "m_Title": "Main Texture", + "m_Position": { + "x": -924.4998779296875, + "y": 2.99993896484375 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.NormalMaterialSlot", + "m_ObjectId": "866a5342b58e41b68a9688a76c504a1e", + "m_Id": 0, + "m_DisplayName": "Normal", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Normal", + "m_StageCapability": 1, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [], + "m_Space": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector4MaterialSlot", + "m_ObjectId": "8da44223424740bb8aa84e4593ece275", + "m_Id": 0, + "m_DisplayName": "BaseColor", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out", + "m_StageCapability": 3, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.PropertyNode", + "m_ObjectId": "8eb12b50125f4a1b8b39cb4465a24b8a", + "m_Group": { + "m_Id": "798620dff22b4592ae6fe625b9d0959e" + }, + "m_Name": "Property", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -899.5, + "y": 95.0, + "width": 137.0, + "height": 34.0 + } + }, + "m_Slots": [ + { + "m_Id": "28bc48b35c1e4ce89186650e5f80e5d6" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_Property": { + "m_Id": "37de38f66da04e79885d090f815c85f2" + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.CategoryData", + "m_ObjectId": "97b3f2f641234bdc9115dc56f8f717f4", + "m_Name": "", + "m_ChildObjectList": [ + { + "m_Id": "37de38f66da04e79885d090f815c85f2" + }, + { + "m_Id": "0e6cbb8fa0dd44a2adbb600415866ac7" + }, + { + "m_Id": "e3dec2af43aa4aaea19b15892e1fb205" + } + ] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.SubGraphNode", + "m_ObjectId": "9e29b3f2e47e4522b6be9d02761107fc", + "m_Group": { + "m_Id": "798620dff22b4592ae6fe625b9d0959e" + }, + "m_Name": "SampleMainRiveTexture", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -567.0, + "y": 61.5, + "width": 235.5, + "height": 302.99993896484377 + } + }, + "m_Slots": [ + { + "m_Id": "5d2b140780d74aab8cc79bd6117c9f36" + }, + { + "m_Id": "e9ff0a80260c49209ddc034c4408259f" + }, + { + "m_Id": "6088f2f8640c42b8a4708198e138a5b3" + }, + { + "m_Id": "67c27cacf13d4fd4812ad7b6e441ea59" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedSubGraph": "{\n \"subGraph\": {\n \"fileID\": -5475051401550479605,\n \"guid\": \"287ae8d259edf47cf9ec073950debe11\",\n \"type\": 3\n }\n}", + "m_PropertyGuids": [ + "4b65a152-6b9e-429e-bbc1-bebac7fac8fc", + "0dafdea0-1c0d-40c7-9a2f-3553ae8cb358" + ], + "m_PropertyIds": [ + 1334702512, + 1190027673 + ], + "m_Dropdowns": [], + "m_DropdownSelectedEntries": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.ColorRGBMaterialSlot", + "m_ObjectId": "a5e61f11c2054ed985b54088ee1ab0ec", + "m_Id": 0, + "m_DisplayName": "Base Color", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "BaseColor", + "m_StageCapability": 2, + "m_Value": { + "x": 0.5, + "y": 0.5, + "z": 0.5 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [], + "m_ColorMode": 0, + "m_DefaultColor": { + "r": 0.5, + "g": 0.5, + "b": 0.5, + "a": 1.0 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "a9295c78809f4f88bbf9a98f0bd83c0e", + "m_Group": { + "m_Id": "" + }, + "m_Name": "VertexDescription.Tangent", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "693e86d58ad04f5fad62c5d0ebdcb88e" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "VertexDescription.Tangent" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.PropertyNode", + "m_ObjectId": "aee999def90c4824aefd76e178e312eb", + "m_Group": { + "m_Id": "" + }, + "m_Name": "Property", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -427.515380859375, + "y": 435.34539794921877, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "56252a9d762f4616a3411a77bd4cb4a0" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_Property": { + "m_Id": "e3dec2af43aa4aaea19b15892e1fb205" + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "ca9e31a73bbc42f1add1c7c5d13d0dd3", + "m_Group": { + "m_Id": "" + }, + "m_Name": "SurfaceDescription.BaseColor", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "a5e61f11c2054ed985b54088ee1ab0ec" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "SurfaceDescription.BaseColor" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.PropertyNode", + "m_ObjectId": "dc75333dde6a4f05bade7f0bff7cab17", + "m_Group": { + "m_Id": "798620dff22b4592ae6fe625b9d0959e" + }, + "m_Name": "Property", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -899.5, + "y": 149.00006103515626, + "width": 135.5, + "height": 33.99993896484375 + } + }, + "m_Slots": [ + { + "m_Id": "8da44223424740bb8aa84e4593ece275" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_Property": { + "m_Id": "0e6cbb8fa0dd44a2adbb600415866ac7" + } +} + +{ + "m_SGVersion": 1, + "m_Type": "UnityEditor.ShaderGraph.Internal.Vector1ShaderProperty", + "m_ObjectId": "e3dec2af43aa4aaea19b15892e1fb205", + "m_Guid": { + "m_GuidSerialized": "00920b1e-8cf7-4d8c-9ce8-839854e22050" + }, + "m_Name": "Cutoff", + "m_DefaultRefNameVersion": 1, + "m_RefNameGeneratedByDisplayName": "Cutoff", + "m_DefaultReferenceName": "_Cutoff", + "m_OverrideReferenceName": "", + "m_GeneratePropertyBlock": true, + "m_UseCustomSlotLabel": false, + "m_CustomSlotLabel": "", + "m_DismissedVersion": 0, + "m_Precision": 0, + "overrideHLSLDeclaration": false, + "hlslDeclarationOverride": 0, + "m_Hidden": false, + "m_Value": 0.5, + "m_FloatType": 1, + "m_RangeValues": { + "x": 0.0, + "y": 1.0 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "e58c2aa05205411cae96b18996dc21b6", + "m_Group": { + "m_Id": "" + }, + "m_Name": "SurfaceDescription.Alpha", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "30051542fb7c4262905702e4edc2fe6f" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "SurfaceDescription.Alpha" +} + +{ + "m_SGVersion": 1, + "m_Type": "UnityEditor.Rendering.Universal.ShaderGraph.UniversalTarget", + "m_ObjectId": "e990e6fec6c64676a507d6a40b2f8543", + "m_Datas": [], + "m_ActiveSubTarget": { + "m_Id": "094d9ebd56e34282a396968bb312ca49" + }, + "m_AllowMaterialOverride": true, + "m_SurfaceType": 1, + "m_ZTestMode": 4, + "m_ZWriteControl": 0, + "m_AlphaMode": 0, + "m_RenderFace": 2, + "m_AlphaClip": false, + "m_CastShadows": true, + "m_ReceiveShadows": true, + "m_SupportsLODCrossFade": false, + "m_CustomEditorGUI": "", + "m_SupportVFX": false +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector4MaterialSlot", + "m_ObjectId": "e9ff0a80260c49209ddc034c4408259f", + "m_Id": 1190027673, + "m_DisplayName": "BaseColor", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "_BaseColor", + "m_StageCapability": 2, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_Labels": [] +} + diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/URP/Shaders/Unlit.shadergraph.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/URP/Shaders/Unlit.shadergraph.meta new file mode 100644 index 00000000..20c027e6 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/URP/Shaders/Unlit.shadergraph.meta @@ -0,0 +1,17 @@ +fileFormatVersion: 2 +guid: 39bae129d756041e4a0f305f26ebebe4 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: 625f186215c104763be7675aa2d941aa, type: 3} +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/URP/Shaders/Unlit.shadergraph + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/URP/UniversalRenderPipelineHandler.cs b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/URP/UniversalRenderPipelineHandler.cs new file mode 100644 index 00000000..a642e1bb --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/URP/UniversalRenderPipelineHandler.cs @@ -0,0 +1,340 @@ +#if RIVE_USING_URP + +using System.Collections.Generic; +using Rive.Utils; +using UnityEngine; +using UnityEngine.Rendering; +using UnityEngine.Rendering.Universal; + +namespace Rive.Components.URP +{ + /// + /// This class is responsible for handling the rendering of Rive objects in the Universal Render Pipeline. + /// + public class UniversalRenderPipelineHandler : MonoBehaviour, IRenderPipelineHandler + { + + [SerializeField] private RenderPassEvent m_renderPassEvent = RenderPassEvent.AfterRenderingTransparents; + + [Tooltip("The camera that will render the Rive content. If not provided, the main camera will be used.")] + [SerializeField] private Camera m_renderCamera; + + RenderPassPool m_renderPassPool; + + private Dictionary m_activeRenderPasses = new Dictionary(); + + private UniversalAdditionalCameraData m_cameraData; + + private bool m_isDestroyed = false; + + private List m_cleanupList = new List(); + + private Dictionary m_rtHandleCache = new Dictionary(); + + private const string PROFILER_MARKER_NAME = "Rive URP Render Pass"; + + private const string DEFAULT_RENDER_TEXTURE_NAME = "URP Rive Render Texture"; + + /// + /// The default capacity of the render pass pool. + /// + public int RenderPassPoolDefaultCapacity { get; set; } = 5; + + /// + /// The maximum size of the render pass pool. + /// + public int RenderPassPoolMaxSize { get; set; } = 10000; + + public bool IsInitialized { get; private set; } + + public RenderPassEvent RenderPassEvent + { + get => m_renderPassEvent; + set => m_renderPassEvent = value; + } + + public Camera RenderCamera + { + get + { + + return m_renderCamera; + } + set => SetRenderCamera(value); + } + + /// + /// The current instance of the UniversalRenderPipelineHandler in the scene. + /// + public static UniversalRenderPipelineHandler Instance + { + get + { + return RenderPipelineHelper.CurrentHandler as UniversalRenderPipelineHandler; + } + } + + private RTHandleSystem m_RTHandleSystem; + + private RTHandleSystem RTHandleSystem + { + get + { + if (m_isDestroyed) + { + return null; + } + if (m_RTHandleSystem == null) + { + m_RTHandleSystem = new RTHandleSystem(); + } + + return m_RTHandleSystem; + } + } + + + private void InitRenderPassPoolIfNeeded() + { + if (m_renderPassPool == null) + { + m_renderPassPool = new RenderPassPool(RenderPassPoolDefaultCapacity, RenderPassPoolMaxSize); + } + } + + private void Awake() + { + RTHandleSystem.Initialize(Screen.width, Screen.height); + IsInitialized = true; + } + + + private void OnEnable() + { + RenderPipelineManager.beginCameraRendering += OnBeginCamera; + } + + private void OnDisable() + { + RenderPipelineManager.beginCameraRendering -= OnBeginCamera; + } + + private void SetRenderCamera(Camera camera) + { + m_renderCamera = camera; + m_cameraData = camera != null ? camera.GetUniversalAdditionalCameraData() : null; + } + + private void OnBeginCamera(ScriptableRenderContext context, Camera camera) + { + if (RenderCamera == null || !RenderCamera.isActiveAndEnabled) + { + RenderCamera = CameraHelper.GetRenderCameraInScene(); + } + + bool isValidCamera = ReferenceEquals(camera, RenderCamera); + +#if UNITY_EDITOR + isValidCamera = isValidCamera || camera.cameraType == CameraType.SceneView; +#endif + + // We only want one camera to render the Rive graphics + if (RenderCamera == null || !isValidCamera) + { + return; + } + + UniversalAdditionalCameraData cameraData; + +#if UNITY_EDITOR + if (camera.cameraType == CameraType.SceneView) + { + cameraData = camera.GetUniversalAdditionalCameraData(); + } + else +#endif + { + cameraData = m_cameraData; + } + + ScriptableRenderer scriptableRenderer = cameraData != null ? cameraData.scriptableRenderer : null; + if (scriptableRenderer == null) + { + return; + } + + foreach (var renderHandle in m_activeRenderPasses.Values) + { + if (renderHandle != null) + { + scriptableRenderer.EnqueuePass(renderHandle); + } + } + } + + private RenderPass GetRenderHandleForRenderer(IRenderer renderer) + { + if (renderer == null) + { + return null; + } + + if (m_activeRenderPasses.ContainsKey(renderer)) + { + return m_activeRenderPasses[renderer]; + } + + return null; + } + + public void Register(IRenderer renderer) + { + InitRenderPassPoolIfNeeded(); + + if (renderer == null) + { + DebugLogger.Instance.LogWarning("Trying to register a null renderer."); + return; + } + + var existingHandle = GetRenderHandleForRenderer(renderer); + + if (existingHandle != null) + { + DebugLogger.Instance.LogWarning("Trying to register the same renderer twice."); + return; + } + + RenderPass riveRenderHandlePass = m_renderPassPool.Get(renderer, m_renderPassEvent, PROFILER_MARKER_NAME); + m_activeRenderPasses.Add(renderer, riveRenderHandlePass); + + } + + public void Unregister(IRenderer renderer) + { + if (renderer == null) + { + return; + } + + if (m_activeRenderPasses.TryGetValue(renderer, out var renderPass)) + { + m_activeRenderPasses.Remove(renderer); + m_renderPassPool.Release(renderPass); + } + } + + public RenderTexture AllocateRenderTexture(int width, int height) + { + if (RTHandleSystem == null) + { + return null; + } + var descriptor = TextureHelper.Descriptor(width, height); + RTHandle handle = RTHandleSystem.Alloc(width, height, colorFormat: descriptor.graphicsFormat, enableRandomWrite: descriptor.enableRandomWrite, name: DEFAULT_RENDER_TEXTURE_NAME); + + return handle; + } + + public void ReleaseRenderTexture(RenderTexture renderTexture) + { + if (RTHandleSystem == null) + { + return; + } + + if (renderTexture == null) + { + return; + } + + if (m_rtHandleCache.Remove(renderTexture, out var rtHandle)) + { + rtHandle.Release(); + } + + } + + public void SetRendererTexture(IRenderer renderer, RenderTexture renderTexture) + { + if (renderer == null) + { + DebugLogger.Instance.LogError("Cannot set texture on a null renderer."); + return; + } + + Renderer riveRenderer = renderer as Renderer; + + if (riveRenderer == null) + { + DebugLogger.Instance.LogError("Cannot set texture on a non-Rive renderer."); + return; + } + + riveRenderer.RenderQueue.UpdateTexture(renderTexture); + } + + public RenderTexture ResizeRenderTexture(RenderTexture renderTexture, int width, int height) + { + if (RTHandleSystem == null) + { + DebugLogger.Instance.LogWarning("Cannot resize render texture. RTHandleSystem is null."); + + return null; + } + + if (renderTexture == null) + { + DebugLogger.Instance.LogWarning("Cannot resize a null render texture."); + return null; + } + + if (m_rtHandleCache.TryGetValue(renderTexture, out var rtHandle)) + { + rtHandle.Release(); + m_rtHandleCache.Remove(renderTexture); + } + + return AllocateRenderTexture(width, height); + } + + + + public bool IsRendererRegistered(IRenderer renderer) + { + return m_activeRenderPasses.ContainsKey(renderer); + } + + + private void Cleanup() + { + + if (RTHandleSystem != null) + { + RTHandleSystem.Dispose(); + m_RTHandleSystem = null; + } + + // Unregister all renderers + m_cleanupList.Clear(); + m_cleanupList.AddRange(m_activeRenderPasses.Keys); + + for (int i = 0; i < m_cleanupList.Count; i++) + { + Unregister(m_cleanupList[i]); + } + + m_cameraData = null; + m_renderCamera = null; + } + + private void OnDestroy() + { + Cleanup(); + m_isDestroyed = true; + } + + + } +} +#endif \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/URP/UniversalRenderPipelineHandler.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/URP/UniversalRenderPipelineHandler.cs.meta new file mode 100644 index 00000000..44317b82 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/URP/UniversalRenderPipelineHandler.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: f8d0dc45a801545d9ad0ca00e00722e1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/RenderPipelines/URP/UniversalRenderPipelineHandler.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderTargetStategies.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderTargetStategies.meta new file mode 100644 index 00000000..d3472ebe --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderTargetStategies.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c8c08731d8a714d0bbcd16c8c18c8adc +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderTargetStategies/AtlasRenderTargetStrategy.cs b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderTargetStategies/AtlasRenderTargetStrategy.cs new file mode 100644 index 00000000..f31bd190 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderTargetStategies/AtlasRenderTargetStrategy.cs @@ -0,0 +1,884 @@ +using System.Collections.Generic; +using Rive.Components.Utilities; +using Rive.EditorTools; +using Rive.Utils; +using UnityEngine; +using UnityEngine.Pool; +using UnityEngine.Rendering; + +namespace Rive.Components +{ + /// + /// This strategy renders RivePanels to a single atlas texture. It uses the simple Shelf Packing algorithm to pack the render objects into the atlas. If a render object's dimensions exceeds the maximum resolution, it will be scaled down to fit a specified maximum resolution. + /// +#if UNITY_EDITOR + [InspectorSection(InspectorSections.Advanced, "Advanced", style: SectionStyle.Foldout)] +#endif + [AddComponentMenu("Rive/Render Target Strategies/Atlas Render Target Strategy")] + public class AtlasRenderTargetStrategy : RenderTargetStrategy + { +#if UNITY_EDITOR + + private static class InspectorSections + { + + public const string Advanced = "advanced"; + } +#endif + + private class RenderObjectData + { + public RectInt Position { get; set; } + public Vector2Int ScaledDimensions { get; set; } + public Vector2Int LastKnownSize { get; set; } + + public void Reset() + { + Position = default; + ScaledDimensions = default; + LastKnownSize = default; + + } + } + + [Tooltip("Controls when rendering occurs. In Batched mode, panels are rendered once per frame regardless of redraw requests. In Immediate mode, panels are rendered instantly when requested.")] + [SerializeField] private DrawTimingOption m_drawTiming = DrawTimingOption.DrawBatched; + + + [WidthHeightDimensions("Starting Size")] + [Tooltip("The initial dimensions of the atlas texture.")] + [SerializeField] private Vector2Int m_startingSize = new Vector2Int(1024, 1024); + + [WidthHeightDimensions("Max Atlas Size")] + [Tooltip("The maximum dimensions the atlas texture can grow to")] + [SerializeField] private Vector2Int m_maxAtlasSize = new Vector2Int(2048, 2048); + + [Tooltip("The maximum resolution of a single panel within the atlas texture. If a panel's dimensions exceed this resolution, it will be scaled down. This resolution is applied to the larger dimension of the panel's size.")] + [SerializeField] private int m_maxResolutionPerPanel = 512; + + [Tooltip("The padding between panels in the atlas texture.")] + [SerializeField] private int m_padding = 0; + +#if UNITY_EDITOR + [InspectorField(InspectorSections.Advanced)] +#endif + [Tooltip("The custom atlas packing provider to use. If not set, the default Shelf packing provider will be used.")] + [SerializeField] private RenderTargetAtlasPackingProvider m_customAtlasPackingProvider; + + private RenderTargetAtlasPackingProvider.IPackingStrategy m_packingStrategy; + + private RenderTexture m_atlasTexture; + private List m_renderObjectKeys = new List(); + + private UnityEngine.Pool.ObjectPool m_dataPool; + + private Path m_clipPath; + + + private Renderer m_renderer; + + private bool m_isRendererRegistered = false; + + + private bool m_isInitialized = false; + + + private Dictionary m_rivePanelData = new Dictionary(); + + + /// + /// Batch command options for the atlas render target strategy. Used to determine what action to take on the next frame. + /// + private enum BatchCommandOption + { + None = 0, + + Redraw = 1, + + RepackAndRedraw = 2, + } + + private BatchCommandOption m_batchCommand = BatchCommandOption.None; + + + public Vector2Int StartingSize => m_startingSize; + + public Vector2Int MaxAtlasSize => m_maxAtlasSize; + + public int MaxResolutionPerObject => m_maxResolutionPerPanel; + + public int Padding => m_padding; + + public override DrawTimingOption DrawTiming { get => m_drawTiming; set => m_drawTiming = value; } + + /// + /// The custom atlas packing provider to use. If not set, the default Shelf packing provider will be used. This can only be set before initialization (before any panels are registered). + /// + public RenderTargetAtlasPackingProvider.IPackingStrategy PackingStrategy + { + get => m_packingStrategy; + set + { + if (m_isInitialized) + { + DebugLogger.Instance.LogWarning("Cannot set the packing strategy after initialization."); + return; + } + + m_packingStrategy = value; + } + } + + private RenderTargetSpaceOccupancy TargetSpaceOccupancy + { + get + { + if (m_rivePanelData.Count == 1) + { + return RenderTargetSpaceOccupancy.Exclusive; + } + return RenderTargetSpaceOccupancy.Shared; + } + } + + private void InitializeIfNeeded() + { + if (m_isInitialized) + { + return; + } + + if (m_packingStrategy == null) + { + m_packingStrategy = (m_customAtlasPackingProvider == null || m_customAtlasPackingProvider.PackingStrategy == null) ? new ShelfPackingStrategy() : m_customAtlasPackingProvider.PackingStrategy; + } + + if (m_startingSize.x > m_maxAtlasSize.x || m_startingSize.y > m_maxAtlasSize.y) + { + m_maxAtlasSize = m_startingSize; + + DebugLogger.Instance.LogWarning("The starting size of the atlas texture is larger than the maximum atlas size. The atlas texture will use the starting size as the maximum size."); + } + + m_dataPool = new UnityEngine.Pool.ObjectPool( + createFunc: () => new RenderObjectData(), + actionOnGet: (data) => data.Reset(), + collectionCheck: true + ); + m_packingStrategy.Initialize(m_maxAtlasSize.x, m_maxAtlasSize.y); + CreateAtlasTexture(m_startingSize.x, m_startingSize.y); + + m_isInitialized = true; + } + + + private void CreateAtlasTexture(int width, int height) + { + if (m_renderer == null) + { + m_renderer = RendererUtils.CreateRenderer(); + } + + if (m_atlasTexture != null) + { + if (m_atlasTexture.width == width && m_atlasTexture.height == height) + { + return; + } + + // Resize existing texture + m_atlasTexture = ResizeRenderTexture(m_atlasTexture, width, height); + if (!m_atlasTexture.IsCreated()) + { + m_atlasTexture.Create(); + } + } + else + { + // Create new texture if none exists + m_atlasTexture = CreateRenderTexture(width, height); + + if (!m_atlasTexture.IsCreated()) + { + m_atlasTexture.Create(); + } + } + + RenderPipelineHandler.SetRendererTexture(m_renderer, m_atlasTexture); + } + + private void RedrawAtlas() + { + // Atlas uses a single render queue for multiple panels. If any panel requests AlwaysDraw, + // we should disable dirt-checking and render every frame. + bool shouldDisableArtboardDirtCheck = false; + foreach (var panel in m_rivePanelData.Keys) + { + if (panel != null && panel.DrawOptimization == DrawOptimizationOptions.AlwaysDraw) + { + shouldDisableArtboardDirtCheck = true; + break; + } + } + m_renderer.SetArtboardDirtCheckEnabled(!shouldDisableArtboardDirtCheck); + + // Clear the render queue to avoid rendering leftover visuals from the previous render + m_renderer.Clear(); + + // Redraw each render object in its new position + foreach (var panel in m_rivePanelData.Keys) + { + HandlePanelRendering(panel); + TriggerRenderTargetUpdatedEvent(panel); + } + + } + + /// + /// In OpenGL, the texture coordinate origin (0, 0) is at the bottom-left corner. In Direct3D (used by Windows) and Metal (used by macOS), the origin is typically at the top-left corner. + /// + /// + private bool ShouldFlipOffsetY() + { + return TextureHelper.IsOpenGLPlatform(); + } + + public override Vector2 GetPanelOffset(IRivePanel rivePanel) + { + if (m_atlasTexture == null) + { + return Vector2.zero; + } + + if (m_rivePanelData.TryGetValue(rivePanel, out var data)) + { + float xOffset = (float)data.Position.x / m_atlasTexture.width; + float yOffset = (float)data.Position.y / m_atlasTexture.height; + + return new Vector2(xOffset, yOffset); + } + return Vector2.zero; + } + + public override RenderTexture GetRenderTexture(IRivePanel rivePanel) + { + if (m_rivePanelData.TryGetValue(rivePanel, out var data)) + { + return m_atlasTexture; + } + + return null; + } + + public override Vector2 GetPanelScale(IRivePanel rivePanel) + { + if (m_atlasTexture == null) + { + return Vector2.one; + } + + if (m_rivePanelData.TryGetValue(rivePanel, out var data)) + { + return new Vector2((float)data.Position.width / m_atlasTexture.width, (float)data.Position.height / m_atlasTexture.height); + } + return Vector2.one; + } + + + private void HandlePanelRendering(IRivePanel panel) + { + if (m_rivePanelData.TryGetValue(panel, out var data)) + { + var rect = data.Position; + // Save the current render queue state + m_renderer.Save(); + + + + // Calculate the scale to simulate full render texture size + Vector2Int fullSize = new Vector2Int((int)panel.WidgetContainer.rect.size.x, (int)panel.WidgetContainer.rect.size.y); + float scaleX = (float)rect.width / fullSize.x; + float scaleY = (float)rect.height / fullSize.y; + float scale = Mathf.Min(scaleX, scaleY); + + + + // Only apply clipping if needed + // If there's only one panel in the atlas, we don't need to clip as the visuals overflowing won't affect other panels + bool needsClipping = m_rivePanelData.Count > 1 && DoesPanelNeedClipping(panel); + + + // Translate to the correct starting position to match the reference rect's position in the atlas + if (TextureHelper.ShouldFlipTexture()) + { + var translateMatrix = System.Numerics.Matrix3x2.CreateTranslation(rect.x, rect.y); + m_renderer.Transform(translateMatrix); + + } + else + { + // We need to do this for OpenGL as it uses a different coordinate system, but it isn't needed for Direct3D or Metal platforms + // If we don't do this, the graphic shows up at the wrong position on the y-axis + m_renderer.Transform(System.Numerics.Matrix3x2.CreateTranslation(rect.x, m_atlasTexture.height - rect.y - rect.height)); + } + + // Do the clipping after the translation so the clipping path is in the correct position + if (needsClipping) + { + if (m_clipPath == null) + { + m_clipPath = new Path(); + } + ClippingPathHelper.ConfigureClippingPath(m_clipPath, rect.width, rect.height); + m_renderer.Clip(m_clipPath); + } + + + // Apply the scale to simulate the full render texture size + // This is necessary to ensure the fit & alignment calculations are correct and rendered the way they would be if the artboard were to fill the render texture. Especially important for ScaleDown fit mode. + m_renderer.Transform(System.Numerics.Matrix3x2.CreateScale(scale)); + + // Render the artboard using the full size for alignment calculation + var targetInfo = new RenderTargetInfo( + new Vector2Int(m_atlasTexture.width, m_atlasTexture.height), + new Vector2Int(rect.width, rect.height) + ); + + + + DrawPanelWithRenderer(m_renderer, panel, targetInfo, TargetSpaceOccupancy); + + + + // Restore the render queue state + m_renderer.Restore(); + } + } + + + public override void DrawPanel(IRivePanel panel) + { + if (!IsPanelRegistered(panel)) + { + return; + } + // Check if panel size has changed to determine if we need to repack + Vector2Int currentSize = new Vector2Int((int)panel.WidgetContainer.rect.size.x, (int)panel.WidgetContainer.rect.size.y); + var data = m_rivePanelData[panel]; + + if (data.LastKnownSize != currentSize) + { + // Size changed, need to repack + data.LastKnownSize = currentSize; + RepackAndRedrawIfNeeded(); + } + else + { + // Size hasn't changed, just redraw the panels + RedrawIfNeeded(); + } + } + + + + public override bool IsPanelRegistered(IRivePanel panel) + { + return m_rivePanelData.ContainsKey(panel); + } + + public override bool RegisterPanel(IRivePanel panel) + { + if (IsDestroyed) + { + return false; + } + + InitializeIfNeeded(); + + if (!IsPanelRegistered(panel)) + { + // Check if it can fit + Vector2Int scaledDimensions; + if (!CanFitRenderObject(panel, out scaledDimensions)) + { + DebugLogger.Instance.LogWarning($"Panel cannot fit in the atlas."); + return false; + } + + var data = m_dataPool.Get(); + data.LastKnownSize = new Vector2Int((int)panel.WidgetContainer.rect.size.x, (int)panel.WidgetContainer.rect.size.y); + m_rivePanelData[panel] = data; + + + if (!m_isRendererRegistered) + { + RegisterRenderer(m_renderer); + m_isRendererRegistered = true; + } + RepackAndRedrawIfNeeded(); + + + + return true; + + } + + return false; + } + + public override bool UnregisterPanel(IRivePanel panel) + { + if (m_rivePanelData.Remove(panel, out var data)) + { + m_dataPool.Release(data); + RepackAndRedrawIfNeeded(); + } + + if (m_rivePanelData.Count == 0) + { + UnregisterRenderer(m_renderer); + m_isRendererRegistered = false; + } + + return true; + } + + private Vector2Int GetOrCalculateScaledDimensions(IRivePanel rivePanel, bool forceRecalculate = false) + { + RenderObjectData data = null; + bool hasData = m_rivePanelData.TryGetValue(rivePanel, out data); + + if (!hasData || forceRecalculate || data.ScaledDimensions == default) + { + + Vector2Int dimensions = new Vector2Int((int)rivePanel.WidgetContainer.rect.size.x, (int)rivePanel.WidgetContainer.rect.size.y); + int originalWidth = dimensions.x; + int originalHeight = dimensions.y; + + float scale = 1f; + if (originalWidth > m_maxResolutionPerPanel || originalHeight > m_maxResolutionPerPanel) + { + scale = (float)m_maxResolutionPerPanel / Mathf.Max(originalWidth, originalHeight); + } + + Vector2Int scaledDimensions = new Vector2Int( + Mathf.RoundToInt(originalWidth * scale), + Mathf.RoundToInt(originalHeight * scale) + ); + + if (hasData) + { + data.ScaledDimensions = scaledDimensions; + } + + return scaledDimensions; + } + + return data.ScaledDimensions; + } + + private bool CanFitRenderObject(IRivePanel rivePanel, out Vector2Int scaledDimensions, bool forceRecalculate = false) + { + scaledDimensions = GetOrCalculateScaledDimensions(rivePanel); + + int maxAtlasWidth = m_maxAtlasSize.x; + int maxAtlasHeight = m_maxAtlasSize.y; + + // Check if the object is larger than the maximum allowed dimensions + if (scaledDimensions.x + m_padding * 2 > maxAtlasWidth || scaledDimensions.y + m_padding * 2 > maxAtlasHeight) + { + // Cannot fit into the atlas even at maximum size + return false; + } + + // Simulate packing with current placements into an atlas of maximum allowed size + m_packingStrategy.Initialize(maxAtlasWidth, maxAtlasHeight); + + // Place existing render objects + foreach (var existingRenderObject in m_rivePanelData.Keys) + { + Vector2Int existingScaledDimensions = GetOrCalculateScaledDimensions(existingRenderObject, forceRecalculate); + + int existingRectWidth = existingScaledDimensions.x + m_padding * 2; + int existingRectHeight = existingScaledDimensions.y + m_padding * 2; + + RectInt existingRect; + if (!m_packingStrategy.TryInsert(existingRectWidth, existingRectHeight, out existingRect)) + { + // Failed to place existing object + return false; + } + + + } + + // Try to place the new render object + int rectWidth = scaledDimensions.x + m_padding * 2; + int rectHeight = scaledDimensions.y + m_padding * 2; + + RectInt rect; + if (!m_packingStrategy.TryInsert(rectWidth, rectHeight, out rect)) + { + // Cannot fit the new render object + return false; + } + + + return true; + } + + private void RepackAndRedrawIfNeeded() + { + if (DrawTiming == DrawTimingOption.DrawImmediate) + { + Repack(); + return; + } + + + m_batchCommand = BatchCommandOption.RepackAndRedraw; + + } + + + private void RedrawIfNeeded() + { + if (DrawTiming == DrawTimingOption.DrawImmediate) + { + RedrawAtlas(); + return; + } + + // Handle DrawTimingOption.DrawBatched + + // a RepackAndRedraw command has a higher priority than a Redraw command, so we only set the m_batchCommandOption if it's not already set to avoid it getting overwritten + if (m_batchCommand == BatchCommandOption.None) + { + m_batchCommand = BatchCommandOption.Redraw; + } + + } + + internal protected override void PrepareBatchedRender() + { + if (m_batchCommand == BatchCommandOption.None) + { + return; + } + + // We wait till LateUpdate (via Orchestrator) to redraw to ensure all render objects have been updated. + // We also do this because the native rive code might not be ready on the initial frame until LateUpdate. + + if (m_batchCommand == BatchCommandOption.RepackAndRedraw) + { + Repack(); + } + else if (m_batchCommand == BatchCommandOption.Redraw) + { + RedrawAtlas(); + + } + + m_batchCommand = BatchCommandOption.None; + } + + + + // We sort by height descending + System.Comparison comparison = (a, b) => b.WidgetContainer.rect.size.y.CompareTo(a.WidgetContainer.rect.size.y); + + private void Repack() + { + int currentWidth = m_startingSize.x; + int currentHeight = m_startingSize.y; + + m_renderObjectKeys.Clear(); + m_renderObjectKeys.AddRange(m_rivePanelData.Keys); + m_renderObjectKeys.Sort(comparison); + + bool packed = false; + + while (!packed) + { + packed = PackRects(currentWidth, currentHeight, m_renderObjectKeys); + + if (packed) + break; + + int maxAtlasWidth = m_maxAtlasSize.x; + int maxAtlasHeight = m_maxAtlasSize.y; + + // Decide how to grow the atlas + bool canIncreaseWidth = currentWidth < maxAtlasWidth; + bool canIncreaseHeight = currentHeight < maxAtlasHeight; + + if (!canIncreaseWidth && !canIncreaseHeight) + { + DebugLogger.Instance.LogWarning($"Atlas size cannot be increased further. Maximum dimensions reached: {maxAtlasWidth}x{maxAtlasHeight}."); + break; // Cannot grow further + } + + // Increase the smaller dimension first + if (canIncreaseWidth && (currentWidth <= currentHeight || !canIncreaseHeight)) + { + currentWidth = Mathf.Min(currentWidth * 2, maxAtlasWidth); + } + else if (canIncreaseHeight) + { + currentHeight = Mathf.Min(currentHeight * 2, maxAtlasHeight); + } + } + + if (!packed) + { + DebugLogger.Instance.LogWarning("Failed to pack all render objects into the atlas."); + return; + } + + if (m_atlasTexture == null || currentWidth != m_atlasTexture.width || currentHeight != m_atlasTexture.height) + { + CreateAtlasTexture(currentWidth, currentHeight); + } + + RedrawAtlas(); + + } + + + private bool PackRects(int width, int height, List panelsToPack) + { + m_packingStrategy.Initialize(width, height); + + foreach (var renderObject in panelsToPack) + { + Vector2Int scaledDimensions = GetOrCalculateScaledDimensions(renderObject, true); + + + int rectWidth = scaledDimensions.x + m_padding * 2; + int rectHeight = scaledDimensions.y + m_padding * 2; + + RectInt rect; + if (!m_packingStrategy.TryInsert(rectWidth, rectHeight, out rect)) + { + // Failed to place the rectangle + return false; + } + + // Store the position with padding included, but dimensions without padding + m_rivePanelData[renderObject].Position = new RectInt(rect.x + m_padding, rect.y + m_padding, scaledDimensions.x, scaledDimensions.y); + } + + return true; + } + + + + private void DestroyAndReleaseTexture() + { + if (m_atlasTexture != null) + { + ReleaseRenderTexture(m_atlasTexture); + Destroy(m_atlasTexture); + m_atlasTexture = null; + } + } + + + /// + /// Configures the atlas settings. Only works before the strategy is initialized e.g. before any panels are registered. + /// + /// The initial dimensions of the atlas texture + /// The maximum dimensions the atlas can grow to + /// Maximum resolution for a single panel + /// Padding between panels + /// True if settings were applied, false if strategy was already initialized + public bool Configure(Vector2Int startingSize, Vector2Int maxAtlasSize, int maxResolutionPerPanel = 512, int padding = 0) + { + if (m_isInitialized) + { + DebugLogger.Instance.LogWarning("Cannot configure AtlasRenderTargetStrategy after initialization"); + return false; + } + + if (startingSize.x <= 0 || startingSize.y <= 0) + { + DebugLogger.Instance.LogWarning("Starting size must be greater than 0."); + return false; + } + + if (maxAtlasSize.x <= 0 || maxAtlasSize.y <= 0) + { + DebugLogger.Instance.LogWarning("Max atlas size must be greater than 0."); + return false; + } + + if (maxResolutionPerPanel <= 0) + { + DebugLogger.Instance.LogWarning("Max resolution per panel must be greater than 0."); + return false; + } + + if (padding < 0) + { + DebugLogger.Instance.LogWarning("Padding must be greater than or equal to 0."); + return false; + } + + m_startingSize = startingSize; + m_maxAtlasSize = maxAtlasSize; + m_maxResolutionPerPanel = maxResolutionPerPanel; + m_padding = padding; + + return true; + } + + private void Cleanup() + { + m_renderObjectKeys.Clear(); + m_renderObjectKeys.AddRange(m_rivePanelData.Keys); + + for (int i = m_rivePanelData.Count - 1; i >= 0; i--) + { + var panel = m_renderObjectKeys[i]; + if (panel != null) + { + UnregisterPanel(panel); + } + } + + if (m_dataPool != null) + { + m_dataPool.Clear(); + } + + DestroyAndReleaseTexture(); + + if (m_renderer != null) + { + RendererUtils.ReleaseRenderer(m_renderer); + m_renderer = null; + } + } + + + protected override void OnDestroy() + { + Cleanup(); + base.OnDestroy(); + + } + + protected override IEnumerable GetRenderers() + { + if (m_renderer != null) + { + yield return m_renderer; + } + } + + + } + + + /// + // A shelf-based packing strategy that places rectangles side-by-side in horizontal shelves. Each shelf tracks its used width and stacks vertically in the atlas. When a rectangle doesn't fit in existing shelves, a new shelf is created below. + /// + internal class ShelfPackingStrategy : RenderTargetAtlasPackingProvider.IPackingStrategy + { + private int m_width; + private int m_height; + private List m_shelves; + + private struct Shelf + { + public int Y { get; private set; } + public int Height { get; private set; } + public int UsedWidth { get; private set; } + + public Shelf(int y, int height) + { + Y = y; + Height = height; + UsedWidth = 0; + } + + public bool TryFit(int width, int height, int shelfWidth, out int fitX) + { + if (height > Height || UsedWidth + width > shelfWidth) + { + fitX = 0; + return false; + } + + fitX = UsedWidth; + return true; + } + + public void AddBlock(int width) + { + UsedWidth += width; + } + } + + public void Initialize(int width, int height) + { + m_width = width; + m_height = height; + + if (m_shelves == null) + { + m_shelves = new List(); + } + else + { + m_shelves.Clear(); + } + } + + public bool TryInsert(int requestedWidth, int requestedHeight, out RectInt placementRect) + { + // First try to place in an existing shelf + for (int i = 0; i < m_shelves.Count; i++) + { + if (m_shelves[i].TryFit(requestedWidth, requestedHeight, m_width, out int fitX)) + { + placementRect = new RectInt(fitX, m_shelves[i].Y, requestedWidth, requestedHeight); + var updatedShelf = m_shelves[i]; + updatedShelf.AddBlock(requestedWidth); + m_shelves[i] = updatedShelf; + return true; + } + } + + // If no existing shelf fits, try to create a new shelf + bool hasExistingShelves = m_shelves.Count > 0; + int newShelfY; + if (hasExistingShelves) + { + Shelf lastShelf = m_shelves[m_shelves.Count - 1]; + newShelfY = lastShelf.Y + lastShelf.Height; // Stack new shelf below the last one + } + else + { + newShelfY = 0; // No shelves yet, start at the top + } + + bool hasRoomForNewShelf = newShelfY + requestedHeight <= m_height && requestedWidth <= m_width; + + if (hasRoomForNewShelf) + { + var newShelf = new Shelf(newShelfY, requestedHeight); + newShelf.AddBlock(requestedWidth); + m_shelves.Add(newShelf); + placementRect = new RectInt(0, newShelfY, requestedWidth, requestedHeight); + return true; + } + + // No room found in existing or new shelves + placementRect = new RectInt(0, 0, 0, 0); + return false; + } + } + + +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderTargetStategies/AtlasRenderTargetStrategy.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderTargetStategies/AtlasRenderTargetStrategy.cs.meta new file mode 100644 index 00000000..dab5de4c --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderTargetStategies/AtlasRenderTargetStrategy.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 77921bce798a84a44a54eecb6f99a783 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: f377684eb5623462e80ebba320696f74, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/RenderTargetStategies/AtlasRenderTargetStrategy.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderTargetStategies/IRenderTargetStrategy.cs b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderTargetStategies/IRenderTargetStrategy.cs new file mode 100644 index 00000000..acd7193e --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderTargetStategies/IRenderTargetStrategy.cs @@ -0,0 +1,92 @@ +using UnityEngine; + +namespace Rive.Components +{ + /// + /// Settings for controlling the timing of when render objects are drawn. + /// + public enum DrawTimingOption + { + + /// + /// Batch the render objects and draw them all at once. If a panel is requested to be drawn multiple times in a frame, the render objects will be drawn only once on the next frame. + /// + DrawBatched = 0, + /// + /// Draw the render objects immediately. If a panel is requested to be drawn multiple times in a frame, the render objects will be drawn multiple times. + /// + DrawImmediate = 1, + } + /// + /// Interface for classes that provide a strategy for rendering Rive panels to a render target. + /// + public interface IRenderTargetStrategy + { + public DrawTimingOption DrawTiming { get; set; } + + /// + /// Registers a panel to be rendered by this strategy. + /// + /// The panel to register the render object with. + /// True if the render object was successfully registered, false otherwise. + bool RegisterPanel(IRivePanel panel); + + /// + /// Removes a panel from being rendered by this strategy. + /// + /// The panel to remove the render object from. + /// True if the render object was successfully removed, false otherwise. + bool UnregisterPanel(IRivePanel panel); + + /// + /// Returns whether the given panel is registered with this strategy. + /// + /// The panel to check for the render object. + /// True if the render object is registered, false otherwise. + bool IsPanelRegistered(IRivePanel panel); + + /// + /// Returns the render texture for the given panel. + /// + /// The panel to get the render texture for. + /// The render texture for the given render object. + RenderTexture GetRenderTexture(IRivePanel panel); + + /// + /// Returns the offset for the given panel in UV space. + /// + /// The panel to get the offset for. + /// The offset for the given panel in UV space. + Vector2 GetPanelOffset(IRivePanel panel); + + /// + /// Returns the scale for the given panel within the render target. + /// + /// The panel to get the scale for. + /// The scale for the given panel within the render target. + Vector2 GetPanelScale(IRivePanel panel); + + /// + /// Draws the given panel to the render target. This should handle being called multiple times in a single frame. + /// + /// + void DrawPanel(IRivePanel panel); + + /// + /// Triggers when the render target is updated. + /// + event System.Action OnRenderTargetUpdated; + + /// + /// Triggers when a panel is registered. + /// + /// + event System.Action OnPanelRegistered; + + /// + /// Triggers when a panel is unregistered. + /// + /// + event System.Action OnPanelUnregistered; + } +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderTargetStategies/IRenderTargetStrategy.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderTargetStategies/IRenderTargetStrategy.cs.meta new file mode 100644 index 00000000..bea9ec98 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderTargetStategies/IRenderTargetStrategy.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 9fea341d37ce64a68ad84a7b77767c96 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/RenderTargetStategies/IRenderTargetStrategy.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderTargetStategies/PooledRenderTargetStrategy.cs b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderTargetStategies/PooledRenderTargetStrategy.cs new file mode 100644 index 00000000..c187956a --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderTargetStategies/PooledRenderTargetStrategy.cs @@ -0,0 +1,498 @@ +using System.Collections.Generic; +using Rive.Components.Utilities; +using Rive.EditorTools; +using Rive.Utils; +using UnityEngine; +using UnityEngine.Pool; + +namespace Rive.Components +{ + /// + /// A render target strategy that uses a pool of render textures and renderers to render Rive objects. If you want multiple RiveViews to share the same render texture pool, you can assign the same PoolRenderTargetStrategy reference to them. + /// + [AddComponentMenu("Rive/Render Target Strategies/Pooled Render Target Strategy")] + public class PooledRenderTargetStrategy : RenderTargetStrategy + { + private struct PanelOffsetScale + { + public Vector2 Offset; + public Vector2 Scale; + + public PanelOffsetScale(Vector2 offset, Vector2 scale) + { + Offset = offset; + Scale = scale; + } + } + + private class PanelMetadataInfo + { + public RenderTexture RenderTexture; + public Renderer Renderer; + public Vector2 Scale; + public Vector2 Offset; + + public void Initialize(RenderTexture renderTexture, Renderer renderer, Vector2 scale, Vector2 offset) + { + RenderTexture = renderTexture; + Renderer = renderer; + Scale = scale; + Offset = offset; + } + + public void Clear() + { + RenderTexture = null; + Renderer = null; + Scale = Vector2.zero; + Offset = Vector2.zero; + } + } + + /// + /// The behavior of the pool when there are no available render textures. + /// + public enum PoolOverflowBehavior + { + /// + /// Creates new objects when the pool is full and destroys them when they are released + /// + Flexible = 0, + + /// + /// If there are no available objects in the pool, prevent new panels from being rendered + /// + Fixed = 1, + + } + + [Tooltip("Controls when rendering occurs. In Batched mode, panels are rendered once per frame regardless of redraw requests. In Immediate mode, panels are rendered instantly when requested.")] + [SerializeField] private DrawTimingOption m_drawTiming = DrawTimingOption.DrawBatched; + + [WidthHeightDimensions("Texture Size")] + [Tooltip("The size of the pooled render textures. The rendered panels will be scaled to fit within this size.")] + [SerializeField] private Vector2Int m_pooledTextureSize = new Vector2Int(1024, 1024); + + [Tooltip("The initial allocated size of the pool.")] + [SerializeField] private int m_initialPoolSize = 2; + + [Tooltip("The maximum size the pool can grow to.")] + [SerializeField] private int m_maxPoolSize = 6; + + [Tooltip("The behavior of the pool when there are no available render textures. 'Flexible' creates new objects when the pool is full and destroys them when they are released. 'Fixed' prevents new panels from being rendered if there are no available objects in the pool.")] + [SerializeField] private PoolOverflowBehavior m_poolOverflowBehavior = PoolOverflowBehavior.Flexible; + + private ObjectPool m_renderTexturePool; + + private ObjectPool m_panelMetadataPool; + + private Dictionary m_rivePanelData = new Dictionary(); + + private Dictionary m_renderTextureRendererMap = new Dictionary(); + + private List m_panelsToRedraw = new List(); + + + private bool IsInitialized => m_renderTexturePool != null; + + + private RenderTargetSpaceOccupancy TargetSpaceOccupancy + { + get + { + return RenderTargetSpaceOccupancy.Exclusive; + } + } + + + + /// + /// The behavior of the pool when there are no available render textures. + /// + public PoolOverflowBehavior PoolOverflow { get => m_poolOverflowBehavior; set => m_poolOverflowBehavior = value; } + + /// + /// The size of the pooled render textures. + /// + public Vector2Int PooledTextureSize { get => m_pooledTextureSize; } + + /// + /// The initial allocated size of the pool. + /// + public int InitialPoolSize { get => m_initialPoolSize; } + + /// + /// The maximum size the pool can grow to. + /// + public int MaxPoolSize { get => m_maxPoolSize; } + public override DrawTimingOption DrawTiming { get => m_drawTiming; set => m_drawTiming = value; } + + private void InitializePoolIfNeeded() + { + if (IsInitialized) + { + return; + } + m_renderTexturePool = new ObjectPool( + createFunc: AllocateRenderTexture, + actionOnDestroy: HandleRenderTextureDestroyAction, + collectionCheck: true, + defaultCapacity: m_initialPoolSize, + maxSize: m_maxPoolSize + ); + + m_panelMetadataPool = new ObjectPool( + createFunc: () => new PanelMetadataInfo(), + actionOnRelease: info => info.Clear(), + actionOnDestroy: null, + defaultCapacity: m_initialPoolSize, + maxSize: m_maxPoolSize + ); + + + } + + /// + /// Configures the pool settings. Only works before the pool is initialized. + /// + /// The size of pooled render textures + /// Initial pool capacity + /// Maximum pool size + /// How to handle pool overflow + /// True if settings were applied, false if pool was already initialized + public bool Configure(Vector2Int textureSize, int initialPoolSize, int maxPoolSize, PoolOverflowBehavior overflowBehavior) + { + if (IsInitialized) + { + DebugLogger.Instance.LogWarning("Cannot configure PooledRenderTargetStrategy after initialization"); + return false; + } + + m_pooledTextureSize = textureSize; + m_initialPoolSize = initialPoolSize; + m_maxPoolSize = maxPoolSize; + m_poolOverflowBehavior = overflowBehavior; + return true; + } + + private RenderTexture AllocateRenderTexture() + { + return CreateRenderTexture(m_pooledTextureSize.x, m_pooledTextureSize.y); + } + + + private void HandleRenderTextureDestroyAction(RenderTexture rt) + { + ReleaseRenderTexture(rt); + Destroy(rt); + } + + private PanelOffsetScale CalculatePanelOffsetScale(IRivePanel rivePanel, RenderTexture renderTexture) + { + int pooledTextureWidth = m_pooledTextureSize.x; + int pooledTextureHeight = m_pooledTextureSize.y; + Vector2Int dimensions = new Vector2Int((int)rivePanel.WidgetContainer.rect.size.x, (int)rivePanel.WidgetContainer.rect.size.y); + float scaleX = (float)pooledTextureWidth / dimensions.x; + float scaleY = (float)pooledTextureHeight / dimensions.y; + float scale = Mathf.Min(scaleX, scaleY); + + Vector2 scaledSize = new Vector2(dimensions.x * scale, dimensions.y * scale); + // We calculate the offset to center the panel in the render texture + Vector2 offset = new Vector2( + (pooledTextureWidth - scaledSize.x) * 0.5f, + (pooledTextureHeight - scaledSize.y) * 0.5f + ); + + return new PanelOffsetScale(offset, new Vector2(scale, scale)); + } + + + private Renderer GetOrCreateRendererForRenderTexture(RenderTexture renderTexture) + { + if (m_renderTextureRendererMap.TryGetValue(renderTexture, out var renderer)) + { + return renderer; + } + + renderer = RendererUtils.CreateRenderer(renderTexture); + m_renderTextureRendererMap[renderTexture] = renderer; + return renderer; + } + + public override RenderTexture GetRenderTexture(IRivePanel rivePanel) + { + if (m_rivePanelData.TryGetValue(rivePanel, out var info)) + { + return info.RenderTexture; + } + return null; + } + + public override Vector2 GetPanelOffset(IRivePanel rivePanel) + { + int pooledTextureWidth = m_pooledTextureSize.x; + int pooledTextureHeight = m_pooledTextureSize.y; + if (m_rivePanelData.TryGetValue(rivePanel, out var info)) + { + // Calculate and return the normalized offset + // This ensures that the offset is correctly scaled to the texture size, + // allowing for proper positioning of the panel within the larger texture + // If we don't do this, the panel will be rendered at the wrong size within the material/raw image + var xOffset = info.Offset.x / pooledTextureWidth; + var yOffset = info.Offset.y / pooledTextureHeight; + + + return new Vector2( + xOffset, + yOffset + ); + } + return Vector2.zero; + } + + public override Vector2 GetPanelScale(IRivePanel rivePanel) + { + int pooledTextureWidth = m_pooledTextureSize.x; + int pooledTextureHeight = m_pooledTextureSize.y; + if (m_rivePanelData.TryGetValue(rivePanel, out var info)) + { + // Calculate and return the normalized scale + // This accounts for both the scaling applied to fit the render object + // into the pooled texture and the relative size of the render object + // compared to the full texture size + // If we don't do this, the render object will be rendered at the wrong size within the material/raw image + Vector2Int dimensions = new Vector2Int((int)rivePanel.WidgetContainer.rect.size.x, (int)rivePanel.WidgetContainer.rect.size.y); + return new Vector2( + (dimensions.x * info.Scale.x) / pooledTextureWidth, + (dimensions.y * info.Scale.y) / pooledTextureHeight + ); + } + return Vector2.one; + } + + + private void HandlePanelDrawing(IRivePanel panel) + { + if (m_rivePanelData.TryGetValue(panel, out var info)) + { + RefreshRenderTextureDimensions(panel); + var renderer = info.Renderer; + var offset = info.Offset; + var scale = info.Scale; + renderer.SetArtboardDirtCheckEnabled(panel.DrawOptimization == DrawOptimizationOptions.DrawWhenChanged); + renderer.Clear(); + + // Calculate the panel's allocated space within the render texture + Vector2Int dimensions = new Vector2Int((int)panel.WidgetContainer.rect.size.x, (int)panel.WidgetContainer.rect.size.y); + Vector2Int scaledDimensions = new Vector2Int( + Mathf.RoundToInt(dimensions.x * scale.x), + Mathf.RoundToInt(dimensions.y * scale.y) + ); + + var targetInfo = new RenderTargetInfo( + new Vector2Int(m_pooledTextureSize.x, m_pooledTextureSize.y), // Full texture size + scaledDimensions // Panel's allocated space after scaling + ); + + // Translate to the correct position. We need to do this because rendering the artboard within a frame that is offset and scaled to fit the render texture + // This allows us to pool render textures of the same size and reuse them for different render objects with different dimensions + renderer.Transform(System.Numerics.Matrix3x2.CreateTranslation(offset.x, offset.y)); + + // Apply scaling + renderer.Transform(System.Numerics.Matrix3x2.CreateScale(scale.x, scale.y)); + + + + DrawPanelWithRenderer(renderer, panel, targetInfo, TargetSpaceOccupancy); + TriggerRenderTargetUpdatedEvent(panel); + + + } + } + + + public override void DrawPanel(IRivePanel panel) + { + if (!IsPanelRegistered(panel)) + { + return; + } + + if (DrawTiming == DrawTimingOption.DrawImmediate) + { + HandlePanelDrawing(panel); + return; + } + + if (m_panelsToRedraw.Contains(panel)) + { + return; + } + + m_panelsToRedraw.Add(panel); + + } + internal protected override void PrepareBatchedRender() + { + if (DrawTiming != DrawTimingOption.DrawBatched) + { + return; + } + // We wait till LateUpdate (via Orchestrator) rather than the end of the current frame + // (e.g. WaitTillEndOfFrame) because using the latter can cause glitches in the rendering. + // We want to batch the drawing of all panels only once instead of drawing them multiple + // times in the same frame. + + if (m_panelsToRedraw.Count > 0) + { + for (int i = 0; i < m_panelsToRedraw.Count; i++) + { + HandlePanelDrawing(m_panelsToRedraw[i]); + } + m_panelsToRedraw.Clear(); + } + } + + + public override bool IsPanelRegistered(IRivePanel panel) + { + return m_rivePanelData.ContainsKey(panel); + + } + + public override bool RegisterPanel(IRivePanel panel) + { + if (panel == null || IsPanelRegistered(panel) || IsDestroyed) + { + return false; + } + InitializePoolIfNeeded(); + + + if (m_poolOverflowBehavior == PoolOverflowBehavior.Fixed && m_renderTexturePool.CountActive >= m_maxPoolSize) + { + DebugLogger.Instance.LogWarning("The render texture pool is empty. Please change the overflow behavior."); + return false; + } + + var renderTexture = m_renderTexturePool.Get(); + if (!renderTexture.IsCreated()) + { + renderTexture.Create(); + } + var offsetScale = CalculatePanelOffsetScale(panel, renderTexture); + + var renderer = GetOrCreateRendererForRenderTexture(renderTexture); + + if (!ReferenceEquals(renderer.RenderQueue.Texture, renderTexture)) + { + RenderPipelineHandler.SetRendererTexture(renderer, renderTexture); + + } + + + + PanelMetadataInfo meta = m_panelMetadataPool.Get(); + meta.Initialize(renderTexture, renderer, offsetScale.Scale, offsetScale.Offset); + + m_rivePanelData[panel] = meta; + + RegisterRenderer(renderer); + + DrawPanel(panel); + + return true; + } + + public override bool UnregisterPanel(IRivePanel panel) + { + if (m_rivePanelData.TryGetValue(panel, out var info)) + { + + UnregisterRenderer(info.Renderer); + m_renderTexturePool.Release(info.RenderTexture); + m_panelMetadataPool.Release(info); + m_rivePanelData.Remove(panel); + } + + return true; + } + + /// + /// Refreshes the render texture for the given panel if necessary. + /// + /// The panel to refresh the render texture for. + /// True if the render texture was refreshed, false otherwise. + private bool RefreshRenderTextureDimensions(IRivePanel panel) + { + bool neededRefresh = false; + + if (m_rivePanelData.TryGetValue(panel, out var info)) + { + PanelOffsetScale offsetScale = CalculatePanelOffsetScale(panel, info.RenderTexture); + + neededRefresh = offsetScale.Offset != info.Offset || offsetScale.Scale != info.Scale; + + if (!neededRefresh) + { + return false; + } + info.Offset = offsetScale.Offset; + info.Scale = offsetScale.Scale; + + + } + + + return neededRefresh; + } + + + + protected override IEnumerable GetRenderers() + { + foreach (var kvp in m_rivePanelData) + { + yield return kvp.Value.Renderer; + } + } + + private void Cleanup() + { + // Reuse this list for cleanup + m_panelsToRedraw.Clear(); + m_panelsToRedraw.AddRange(m_rivePanelData.Keys); + + + + for (int i = m_panelsToRedraw.Count - 1; i >= 0; i--) + { + var panel = m_panelsToRedraw[i]; + if (panel != null) + { + UnregisterPanel(panel); + } + } + + m_panelsToRedraw?.Clear(); + m_panelMetadataPool?.Clear(); + m_renderTexturePool?.Clear(); // This will destroy all render textures + + // Cleanup renderers + foreach (var kvp in m_renderTextureRendererMap) + { + RendererUtils.ReleaseRenderer(kvp.Value); + } + + m_renderTextureRendererMap.Clear(); + } + + protected override void OnDestroy() + { + Cleanup(); + base.OnDestroy(); + } + + + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderTargetStategies/PooledRenderTargetStrategy.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderTargetStategies/PooledRenderTargetStrategy.cs.meta new file mode 100644 index 00000000..40abc618 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderTargetStategies/PooledRenderTargetStrategy.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 3360aa709854e4363b38ea3b0fdc6353 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: f377684eb5623462e80ebba320696f74, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/RenderTargetStategies/PooledRenderTargetStrategy.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderTargetStategies/RenderTargetAtlasPackingProvider.cs b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderTargetStategies/RenderTargetAtlasPackingProvider.cs new file mode 100644 index 00000000..51456bae --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderTargetStategies/RenderTargetAtlasPackingProvider.cs @@ -0,0 +1,40 @@ +using UnityEngine; + +namespace Rive.Components +{ + /// + /// Base class for providing atlas packing strategies to the AtlasRenderTargetStrategy. + /// Allows customization of how render targets are packed into the atlas texture. + /// + public abstract class RenderTargetAtlasPackingProvider : MonoBehaviour + { + /// + /// Interface defining the required methods for an atlas packing strategy. + /// Implementations determine how rectangles are arranged within the atlas texture. + /// + public interface IPackingStrategy + { + /// + /// Initializes the packing strategy with the given dimensions. If already initialized, resets the packing area and clears any existing rectangles. + /// + /// The width of the packing area + /// The height of the packing area + void Initialize(int width, int height); + + /// + /// Attempts to insert a rectangle of the given dimensions into the packing area. + /// + /// The width of the rectangle to insert + /// The height of the rectangle to insert + /// The resulting position and dimensions if insertion succeeds + /// True if insertion succeeded, false if there was no room + bool TryInsert(int width, int height, out RectInt rect); + + + } + /// + /// The packing strategy to use when packing the render targets into the atlas. + /// + public abstract IPackingStrategy PackingStrategy { get; } + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderTargetStategies/RenderTargetAtlasPackingProvider.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderTargetStategies/RenderTargetAtlasPackingProvider.cs.meta new file mode 100644 index 00000000..d69d3291 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderTargetStategies/RenderTargetAtlasPackingProvider.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 300f21588ec524f668549e4250dbef8d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/RenderTargetStategies/RenderTargetAtlasPackingProvider.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderTargetStategies/RenderTargetStrategy.cs b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderTargetStategies/RenderTargetStrategy.cs new file mode 100644 index 00000000..5e21078d --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderTargetStategies/RenderTargetStrategy.cs @@ -0,0 +1,547 @@ +using System; +using System.Collections.Generic; +using Rive.Utils; +using UnityEngine; +using UnityEngine.Rendering; + +namespace Rive.Components +{ + + internal enum RenderTargetSpaceOccupancy + { + /// + /// The render target is being used by a single render object. + /// + Exclusive = 0, + + /// + /// The render target is occupied by multiple render objects. + /// + Shared = 1, + } + /// + /// A base for classes that provide a strategy for rendering Rive panels to a render target. + /// + public abstract class RenderTargetStrategy : MonoBehaviour, IRenderTargetStrategy + { + + + internal struct RenderTargetInfo : IEquatable + { + /// + /// The full dimensions of the render target. + /// + public Vector2Int TargetSize { get; private set; } + + /// + /// The dimensions allocated to this panel within the target. + /// + public Vector2Int PanelAllocation { get; private set; } + + /// + /// Creates a new RenderTargetInfo with the given render target size and panel allocation. + /// + /// The full dimensions of the render target. + /// The dimensions allocated to this panel within the target. + public RenderTargetInfo(Vector2Int renderTargetSize, Vector2Int panelAllocation) + { + TargetSize = renderTargetSize; + PanelAllocation = panelAllocation; + } + + public bool Equals(RenderTargetInfo other) + { + return TargetSize == other.TargetSize && + PanelAllocation == other.PanelAllocation; + } + + public override bool Equals(object obj) + { + return obj is RenderTargetInfo info && Equals(info); + } + + public override int GetHashCode() + { + return HashCode.Combine(TargetSize, PanelAllocation); + } + + public static bool operator ==(RenderTargetInfo left, RenderTargetInfo right) + { + return left.Equals(right); + } + + public static bool operator !=(RenderTargetInfo left, RenderTargetInfo right) + { + return !left.Equals(right); + } + } + + private bool m_isDestroyed = false; + + private IRenderPipelineHandler m_renderPipelineHandler; + + protected bool IsDestroyed => m_isDestroyed; + + internal Func ExternalPixelSizeProvider { get; set; } + internal Func ExternalDrawScaleProvider { get; set; } + + /// + /// The render pipeline handler to use for rendering panels. + /// + public IRenderPipelineHandler RenderPipelineHandler + { + get + { + if (m_renderPipelineHandler == null && !IsDestroyed) + { + m_renderPipelineHandler = RenderPipelineHelper.GetOrCreateHandler(); + } + + return m_renderPipelineHandler; + } + set + { + if (ReferenceEquals(m_renderPipelineHandler, value)) + { + return; + } + + // Unregister the renderers from the current handler + if (m_renderPipelineHandler != null) + { + // Unregister all renderers managed by the current handler + foreach (Renderer renderer in GetRenderers()) + { + if (m_renderPipelineHandler.IsRendererRegistered(renderer)) + { + m_renderPipelineHandler.Unregister(renderer); + } + } + } + + m_renderPipelineHandler = value; + + // Reregister all renderers managed with the new handler + if (m_renderPipelineHandler != null) + { + foreach (Renderer renderer in GetRenderers()) + { + if (!m_renderPipelineHandler.IsRendererRegistered(renderer)) + { + m_renderPipelineHandler.Register(renderer); + } + } + } + } + } + + + + /// + /// Controls when rendering occurs. In Batched mode, panels are rendered once per frame regardless of redraw requests. In Immediate mode, panels are rendered instantly when requested. + /// + public abstract DrawTimingOption DrawTiming { get; set; } + + + + + public event Action OnRenderTargetUpdated; + + public event Action OnPanelRegistered; + + public event Action OnPanelUnregistered; + + /// + /// Called once per frame (via Orchestrator) after ticking panels. + /// Override this to handle any batched render requests. + /// + internal protected virtual void PrepareBatchedRender() + { + } + + internal void PrepareRenderFromOrchestrator() + { + if (m_isDestroyed || !isActiveAndEnabled) + { + return; + } + + PrepareBatchedRender(); + } + + protected virtual void OnEnable() + { + Orchestrator.RegisterRenderTargetStrategy(this); + } + + protected virtual void OnDisable() + { + Orchestrator.UnregisterRenderTargetStrategy(this); + } + + + internal static void DrawPanelWithRenderer(Renderer renderer, IRivePanel panel, RenderTargetInfo targetInfo, RenderTargetSpaceOccupancy renderTargetSpaceOccupancy) + { + if (renderer == null || panel == null) + { + return; + } + + for (int i = 0; i < panel.Widgets.Count; i++) + { + IRiveWidget widget = panel.Widgets[i]; + if (widget == null || widget.RenderObject == null) continue; + + bool isAutoClippedByRenderTarget = false; + if (widget.RectTransform != null && panel.WidgetContainer != null) + { + isAutoClippedByRenderTarget = ShouldSkipClippingForWidget( + widget.RectTransform, + panel.WidgetContainer + ); + } + + RenderContext context = new RenderContext( + isAutoClippedByRenderTarget + ? RenderContext.ClippingModeSetting.SkipClipping + : RenderContext.ClippingModeSetting.CheckClipping + ); + DrawRenderObject(renderer, widget.RenderObject, panel, context); + } + } + + internal static bool ShouldSkipClippingForWidget(RectTransform widgetTransform, RectTransform containerTransform) + { + + containerTransform.GetWorldCorners(s_rectTransformCorners); + + // Check if all container corners are inside the widget's local rect + for (int i = 0; i < 4; i++) + { + Vector3 localPoint = widgetTransform.InverseTransformPoint(s_rectTransformCorners[i]); + if (!RectContainsInclusive(widgetTransform.rect, (Vector2)localPoint)) + { + // At least one corner is not covered, so we can't skip clipping + return false; + } + } + + // All corners are inside the widget, so it fully covers the container. We don't need to clip it because it will be clipped by the render target bounds or by whatever the render target strategy decides to do for panels that share space. + return true; + } + + internal static Vector3[] s_rectTransformCorners = new Vector3[4]; + + + + internal static bool DoesPanelNeedClipping(IRivePanel panel) + { + if (panel == null || panel.WidgetContainer == null) return false; + + for (int i = 0; i < panel.Widgets.Count; i++) + { + IRiveWidget widget = panel.Widgets[i]; + if (widget == null || widget.RectTransform == null) continue; + + if (DoesWidgetHavePointOutsidePanel(panel.WidgetContainer, widget.RectTransform)) + { + // Early out if any widget has a point outside the panel + return true; + } + + } + return false; + } + + + internal static bool DoesWidgetHavePointOutsidePanel(RectTransform containerTransform, RectTransform widgetTransform) + { + if (containerTransform == null || widgetTransform == null) return false; + + Vector3[] corners = s_rectTransformCorners; + Rect containerRect = containerTransform.rect; + + widgetTransform.GetWorldCorners(corners); + + for (int i = 0; i < 4; i++) + { + corners[i] = containerTransform.InverseTransformPoint(corners[i]); + Vector2 localPoint = new Vector2(corners[i].x, corners[i].y); + + // Using Rect.Contains would cause unnecessary clipping in this case because the widget's corners would be on the panel's edges and that method would consider that as outside the panel. + if (!RectContainsInclusive(containerRect, localPoint)) + { + return true; + } + } + + return false; + } + + private static bool RectContainsInclusive(Rect rect, Vector2 point) + { + return point.x >= rect.xMin && point.x <= rect.xMax && + point.y >= rect.yMin && point.y <= rect.yMax; + } + + + + /// + /// Determines if clipping should be skipped based on the widget size, container size, panel allocation and target size. + /// We skip clipping if the widget fills or exceeds the panel bounds and the panel allocation fills or exceeds the render target bounds because the widget will be clipped by the render target bounds. + /// + /// The size of the widget in pixels + /// The size of the widget container in pixels + /// The size allocated to the panel on the render target in pixels + /// The size of the render target in pixels + /// True if clipping should be skipped, false otherwise. + internal static bool ShouldSkipClipping(Vector2 widgetSize, Vector2 containerSize, Vector2Int panelAllocation, Vector2Int targetSize) + { + // Widget fills or exceeds panel bounds + bool widgetFillsPanel = widgetSize.x >= containerSize.x && + widgetSize.y >= containerSize.y; + + // Panel allocation fills or exceeds render target + bool panelFillsTarget = panelAllocation.x >= targetSize.x && + panelAllocation.y >= targetSize.y; + + return widgetFillsPanel && panelFillsTarget; + } + + + + internal static void DrawRenderObject(Renderer renderer, IRenderObject renderObject, IRivePanel panel, RenderContext renderContext) + { + if (renderer == null) + { + DebugLogger.Instance.LogError("Render method called with null renderer"); + return; + } + + if (renderObject == null) + { + DebugLogger.Instance.LogWarning("Render method called with null render object"); + return; + } + + // Save the current state of the renderer so we can restore it after drawing the render object. + + renderer.Save(); + + RenderTransform renderTransform = renderObject.RenderTransform; + + System.Numerics.Matrix3x2 localTransform = CalculateRenderObjectTransformMatrix(renderTransform); + + // Apply the final transformation + renderer.Transform(localTransform); + + // We draw the artboard if this is an ArtboardRenderObject, if this is a procedural drawing, we draw the procedural drawing. + renderObject.DrawContent(renderer, new AABB(0, 0, renderTransform.Size.x, renderTransform.Size.y), renderContext); + + renderer.Restore(); + + } + + /// + /// Calculates the transformation matrix for a render object based on its render transform properties. + /// + /// The render transform containing position, size, rotation, scale and pivot information. + /// The calculated transformation matrix. + protected static System.Numerics.Matrix3x2 CalculateRenderObjectTransformMatrix(RenderTransform renderTransform) + { + Vector2 Size = renderTransform.Size; + Vector2 Position = renderTransform.Position; + float Rotation = renderTransform.Rotation; + Vector2 Scale = renderTransform.Scale; + Vector2 Pivot = renderTransform.Pivot; + + float pivotOffsetX = Size.x * Pivot.x; + float pivotOffsetY = Size.y * Pivot.y; + + // Initialize the local transform to identity because we will be applying transformations in order. + System.Numerics.Matrix3x2 localTransform = System.Numerics.Matrix3x2.Identity; + + // Translate to Origin (Negative Pivot Offset) + localTransform *= System.Numerics.Matrix3x2.CreateTranslation(-pivotOffsetX, -pivotOffsetY); + + // Apply Scaling + if (Scale != Vector2.one) + { + localTransform *= System.Numerics.Matrix3x2.CreateScale(Scale.x, Scale.y); + } + + // Apply Rotation (Negated for Rive's coordinate system) + if (Rotation != 0) + { + localTransform *= System.Numerics.Matrix3x2.CreateRotation(Rotation); + } + + // Translate Back to Pivot Point (Positive Pivot Offset) + localTransform *= System.Numerics.Matrix3x2.CreateTranslation(pivotOffsetX, pivotOffsetY); + bool shouldFlipTexture = TextureHelper.ShouldFlipTexture(); + if (shouldFlipTexture) + { + // Flip the Y-axis by applying a scale of (1, -1) on the Y axis. + localTransform *= System.Numerics.Matrix3x2.CreateScale(1, -1); + + // Adjust the pivot offset translation after flipping to keep positioning correct. + localTransform *= System.Numerics.Matrix3x2.CreateTranslation(0, -Size.y); + } + + //Translate to Absolute Position + localTransform *= System.Numerics.Matrix3x2.CreateTranslation(Position.x, Position.y); + + return localTransform; + } + + /// + /// On Windows, OpenGL and D3D seem to have procedural drawings (and paths) rotated by 90 degrees, so we correct for that here + /// This could be because of something we're doing in RenderTargetStrategy.CalculateRenderObjectTransformMatrix, so this is a workaround for now + /// This issue doesn't happen in Android and WebGL builds with OpenGL. It also doesn't happen with Artboards, so it looks like it is specific to the procedural API. + /// + /// True if procedural drawing requires rotation correction, false otherwise. + internal static bool ProceduralDrawingRequiresRotationCorrection() + { +#if UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN + return TextureHelper.IsOpenGLPlatform() || TextureHelper.IsDirect3DPlatform() || SystemInfo.graphicsDeviceType == GraphicsDeviceType.Vulkan; +#else + return false; +#endif + } + + + /// + /// Creates a new render texture with the given width and height. + /// + /// The width of the render texture. + /// The height of the render texture. + /// The new render texture. + protected RenderTexture CreateRenderTexture(int width, int height) + { + return RenderPipelineHandler.AllocateRenderTexture(width, height); + } + + protected void ReleaseRenderTexture(RenderTexture renderTexture) + { + RenderPipelineHandler.ReleaseRenderTexture(renderTexture); + } + + protected RenderTexture ResizeRenderTexture(RenderTexture renderTexture, int width, int height) + { + return RenderPipelineHandler.ResizeRenderTexture(renderTexture, width, height); + } + + /// + /// Returns the renderers managed by this strategy. + /// + protected abstract IEnumerable GetRenderers(); + + /// + /// Registers the given renderer with the render pipeline to be rendered. + /// + /// + protected virtual void RegisterRenderer(Renderer renderer) + { + RenderPipelineHandler.Register(renderer); + } + + /// + /// Unregisters the given renderer from the render pipeline so it is no longer rendered. + /// + /// + protected virtual void UnregisterRenderer(Renderer renderer) + { + RenderPipelineHandler.Unregister(renderer); + } + + + + /// + /// Triggers the RenderTargetUpdated event for the given panel. + /// + /// The panel that was updated. + protected virtual void TriggerRenderTargetUpdatedEvent(IRivePanel panel) + { + OnRenderTargetUpdated?.Invoke(panel); + + } + + /// + /// Triggers the PanelRegistered event for the given panel. + /// + /// The panel that was registered. + protected virtual void TriggerPanelRegisteredEvent(IRivePanel panel) + { + OnPanelRegistered?.Invoke(panel); + } + + /// + /// Triggers the PanelUnregistered event for the given panel. + /// + /// The panel that was unregistered. + protected virtual void TriggerPanelUnregisteredEvent(IRivePanel panel) + { + OnPanelUnregistered?.Invoke(panel); + } + + protected virtual void OnDestroy() + { + m_isDestroyed = true; + Orchestrator.UnregisterRenderTargetStrategy(this); + } + + public abstract void DrawPanel(IRivePanel panel); + + public abstract Vector2 GetPanelOffset(IRivePanel panel); + + public abstract Vector2 GetPanelScale(IRivePanel panel); + + public abstract RenderTexture GetRenderTexture(IRivePanel panel); + + public abstract bool IsPanelRegistered(IRivePanel panel); + + public abstract bool RegisterPanel(IRivePanel panel); + + public abstract bool UnregisterPanel(IRivePanel panel); + + + } + + internal static class ClippingPathHelper + { + /// + /// Configures a clipping path based on the platform and given dimensions. This ensures that it looks correct on all platforms. + /// + /// The path to configure + /// Width of the clipping rectangle + /// Height of the clipping rectangle + public static void ConfigureClippingPath(Path path, float width, float height) + { + path.Reset(); + + + bool shouldFlipYClipPath = RenderTargetStrategy.ProceduralDrawingRequiresRotationCorrection(); + + + if (shouldFlipYClipPath) + { + // Swap width and height for OpenGL/D3D11 platforms, otherwise the rect will have the wrong orientation, e.g vertical instead of horizontal + path.MoveTo(0, 0); + path.LineTo(0, width); + path.LineTo(height, width); + path.LineTo(height, 0); + } + else + { + // Use normal coordinates for Metal + path.MoveTo(0, 0); + path.LineTo(width, 0); + path.LineTo(width, height); + path.LineTo(0, height); + } + + path.Close(); + } + } +} + diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderTargetStategies/RenderTargetStrategy.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderTargetStategies/RenderTargetStrategy.cs.meta new file mode 100644 index 00000000..fa554491 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderTargetStategies/RenderTargetStrategy.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: a86a6ae39b1ab42019fd62f3ee9b250b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/RenderTargetStategies/RenderTargetStrategy.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderTargetStategies/SimpleRenderTargetStrategy.cs b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderTargetStategies/SimpleRenderTargetStrategy.cs new file mode 100644 index 00000000..24bb8a78 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderTargetStategies/SimpleRenderTargetStrategy.cs @@ -0,0 +1,289 @@ +using System.Collections.Generic; +using Rive.Components.Utilities; +using Rive.Utils; +using UnityEngine; + +namespace Rive.Components +{ + /// + /// This render target strategy uses a single render texture for each panel. This is the default strategy used unless a custom strategy is specified. This component should be attached to the same GameObject as the RivePanel component it is managing. + /// + [AddComponentMenu("Rive/Render Target Strategies/Simple Render Target Strategy")] + [DisallowMultipleComponent] + public class SimpleRenderTargetStrategy : RenderTargetStrategy + { + + [SerializeField] private RivePanel m_panel; + + [Tooltip("Controls when rendering occurs. In Batched mode, panels are rendered once per frame regardless of redraw requests. In Immediate mode, panels are rendered instantly when requested.")] + [SerializeField] private DrawTimingOption m_drawTiming = DrawTimingOption.DrawBatched; + + + + private Renderer m_renderer; + private RenderTexture m_renderTexture; + private bool m_redrawRequested = false; + + + + protected override void OnEnable() + { + base.OnEnable(); + if (m_panel == null && !TryGetComponent(out m_panel)) + { + DebugLogger.Instance.LogError($"No {nameof(RivePanel)} component found on GameObject. {nameof(SimpleRenderTargetStrategy)} requires a {nameof(RivePanel)} component."); + } + + } + + private RenderTargetSpaceOccupancy TargetSpaceOccupancy + { + get + { + return RenderTargetSpaceOccupancy.Exclusive; + } + } + + public override DrawTimingOption DrawTiming { get => m_drawTiming; set => m_drawTiming = value; } + + public override bool RegisterPanel(IRivePanel panel) + { + if (panel == null) + { + DebugLogger.Instance.LogWarning("Trying to add a null panel to the strategy."); + return false; + } + + if (!ReferenceEquals(panel, m_panel)) + { + DebugLogger.Instance.LogWarning("Trying to register wrong panel with this strategy."); + return false; + } + + if (IsPanelRegistered(panel)) + { + DebugLogger.Instance.LogWarning("Panel is already registered with this strategy."); + return false; + } + + if (IsDestroyed) + { + return false; + } + + + CreateAndRegisterRendererForPanel(); + DrawPanel(panel); + TriggerPanelRegisteredEvent(panel); + + return true; + } + + public override bool UnregisterPanel(IRivePanel panel) + { + if (IsPanelRegistered(panel)) + { + UnregisterRenderer(m_renderer); + + TriggerPanelUnregisteredEvent(panel); + return true; + } + + return false; + } + + private void CreateAndRegisterRendererForPanel() + { + if (m_renderer == null) + { + m_renderer = RendererUtils.CreateRenderer(); + } + + RegisterRenderer(m_renderer); + } + + public override bool IsPanelRegistered(IRivePanel panel) + { + if (m_renderer == null || m_panel == null || panel == null) + { + return false; + } + return ReferenceEquals(panel, m_panel) && RenderPipelineHandler.IsRendererRegistered(m_renderer); + } + + public override RenderTexture GetRenderTexture(IRivePanel panel) + { + if (!IsPanelRegistered(panel)) + { + return null; + } + + return ReferenceEquals(panel, m_panel) ? m_renderTexture : null; + } + + + public override Vector2 GetPanelOffset(IRivePanel panel) + { + return Vector2.zero; + } + + public override Vector2 GetPanelScale(IRivePanel panel) + { + return Vector2.one; + } + + private bool RefreshRenderTexture(IRivePanel panel) + { + Vector2Int size = + ExternalPixelSizeProvider != null + ? ExternalPixelSizeProvider(panel) + : new Vector2Int( + Mathf.Max(1, (int)panel.WidgetContainer.rect.width), + Mathf.Max(1, (int)panel.WidgetContainer.rect.height) + ); + size.x = Mathf.Max(1, size.x); + size.y = Mathf.Max(1, size.y); + + // Use the persistent texture if it exists + if (m_renderTexture == null) + { + m_renderTexture = CreateRenderTexture(size.x, size.y); + if (m_renderTexture == null) + { + return false; + } + if (!m_renderTexture.IsCreated()) + { + m_renderTexture.Create(); + } + RenderPipelineHandler.SetRendererTexture(m_renderer, m_renderTexture); + return true; + } + + // Resize if needed + if (m_renderTexture.width != size.x || m_renderTexture.height != size.y) + { + m_renderTexture = ResizeRenderTexture(m_renderTexture, size.x, size.y); + if (!m_renderTexture.IsCreated()) + { + m_renderTexture.Create(); + } + RenderPipelineHandler.SetRendererTexture(m_renderer, m_renderTexture); + + return true; + } + + // If for some reason the renderer is not using the correct texture, update it + if (m_renderer != null && !ReferenceEquals(m_renderer.RenderQueue.Texture, m_renderTexture)) + { + RenderPipelineHandler.SetRendererTexture(m_renderer, m_renderTexture); + + } + + return false; + } + + protected override IEnumerable GetRenderers() + { + if (m_renderer != null) + { + yield return m_renderer; + } + } + + public override void DrawPanel(IRivePanel panel) + { + if (!IsPanelRegistered(panel)) + { + return; + } + + if (DrawTiming == DrawTimingOption.DrawImmediate) + { + HandlePanelDrawing(panel); + return; + } + + // For DrawBatched mode + m_redrawRequested = true; + + } + + private void HandlePanelDrawing(IRivePanel panel) + { + if (!IsPanelRegistered(panel)) + { + return; + } + + m_renderer.SetArtboardDirtCheckEnabled(panel.DrawOptimization == DrawOptimizationOptions.DrawWhenChanged); + + bool wasRefreshed = RefreshRenderTexture(panel); + m_renderer.Clear(); + + + if (ExternalDrawScaleProvider != null) + { + var s = ExternalDrawScaleProvider(panel); + if (Mathf.Abs(s.x - 1f) > 0.001f || Mathf.Abs(s.y - 1f) > 0.001f) + { + m_renderer.Transform(System.Numerics.Matrix3x2.CreateScale(s.x, s.y)); + } + } + + + var targetInfo = new RenderTargetInfo( + new Vector2Int(m_renderTexture.width, m_renderTexture.height), // Target size + new Vector2Int(m_renderTexture.width, m_renderTexture.height) // Panel allocation (same as target since panel uses entire texture) + ); + + + + DrawPanelWithRenderer(m_renderer, panel, targetInfo, TargetSpaceOccupancy); + + if (wasRefreshed) + { + TriggerRenderTargetUpdatedEvent(panel); + } + } + + internal protected override void PrepareBatchedRender() + { + if (DrawTiming != DrawTimingOption.DrawBatched) + { + return; + } + + if (m_redrawRequested) + { + HandlePanelDrawing(m_panel); + m_redrawRequested = false; + } + } + + private void Cleanup() + { + if (m_renderer != null) + { + UnregisterRenderer(m_renderer); + RendererUtils.ReleaseRenderer(m_renderer); + m_renderer = null; + } + + if (m_renderTexture != null) + { + ReleaseRenderTexture(m_renderTexture); + Destroy(m_renderTexture); + m_renderTexture = null; + } + } + + protected override void OnDestroy() + { + + Cleanup(); + base.OnDestroy(); + + } + } +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderTargetStategies/SimpleRenderTargetStrategy.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderTargetStategies/SimpleRenderTargetStrategy.cs.meta new file mode 100644 index 00000000..9afadce6 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderTargetStategies/SimpleRenderTargetStrategy.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 6742489ef610448bba14e8be35dc521b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: f377684eb5623462e80ebba320696f74, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/RenderTargetStategies/SimpleRenderTargetStrategy.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/Widgets.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/Widgets.meta new file mode 100644 index 00000000..8fde2cb3 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/Widgets.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ebf1e494e9648419b927af5d2d7dbe34 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/Widgets/DrawOptimizationOptions.cs b/Packages/app.rive.rive-unity/Runtime/Components/Public/Widgets/DrawOptimizationOptions.cs new file mode 100644 index 00000000..88914078 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/Widgets/DrawOptimizationOptions.cs @@ -0,0 +1,20 @@ +namespace Rive.Components +{ + /// + /// Controls how often a widget requests a redraw from its panel. + /// + public enum DrawOptimizationOptions + { + /// + /// The widget will request a redraw every frame. + /// + AlwaysDraw = 0, + + /// + /// The widget will only request redraws when its underlying content changes. + /// + DrawWhenChanged = 1 + } +} + + diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/Widgets/DrawOptimizationOptions.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/Widgets/DrawOptimizationOptions.cs.meta new file mode 100644 index 00000000..085d234a --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/Widgets/DrawOptimizationOptions.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 115f6f09fa46e48ebb2d1054898802b8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/Widgets/DrawOptimizationOptions.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/Widgets/IRiveWidget.cs b/Packages/app.rive.rive-unity/Runtime/Components/Public/Widgets/IRiveWidget.cs new file mode 100644 index 00000000..633b338e --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/Widgets/IRiveWidget.cs @@ -0,0 +1,93 @@ +using UnityEngine; + +namespace Rive.Components +{ + /// + /// Interface for widgets that can be rendered by a Rive Panel. + /// + public interface IRiveWidget + { + /// + /// This holds information about the object that will be rendered by the Rive renderer. + /// + IRenderObject RenderObject { get; } + + /// + /// The RectTransform of the widget. + /// + public RectTransform RectTransform { get; } + + /// + /// Whether the widget is enabled and its GameObject is active in the hierarchy. + /// + bool Enabled { get; } + + + /// + /// The hit test behavior of the widget. + /// + HitTestBehavior HitTestBehavior { get; set; } + + + /// + /// This controls the RiveWidget's update loop. + /// + /// The time since the last frame. + /// Returns true if the widget needs to be redrawn as a result of this tick; otherwise, false. + bool Tick(float deltaTime); + + + + /// + /// Tests if a given local position within the widget's rectangle hits any interactive elements. + /// + /// + /// The normalized point of the pointer position in the widget's rectangle. The coordinates are in the range [0,1] where (0,0) is the bottom-left corner and (1,1) is the top-right corner. + /// + /// + /// Returns true if the position hits an interactive element; otherwise, false. + /// + bool HitTest(Vector2 normalizedPointInRect); + + /// + /// Called when a pointer is pressed on the widget. + /// + /// The normalized point of the pointer press in the widget's rectangle. The coordinates are in the range [0,1] where (0,0) is the bottom-left corner and (1,1) is the top-right corner. + /// The unique id for the active pointer/touch. + /// Returns true if the pointer press hits an interactive element; otherwise, false. + bool OnPointerDown(Vector2 normalizedPointInRect, int pointerId); + + /// + /// Called when a pointer is moved on the widget. + /// + /// The normalized point of the pointer position in the widget's rectangle. The coordinates are in the range [0,1] where (0,0) is the bottom-left corner and (1,1) is the top-right corner. + /// The unique id for the active pointer/touch. + /// Returns true if the pointer move hits an interactive element; otherwise, false. + bool OnPointerMove(Vector2 normalizedPointInRect, int pointerId); + + /// + /// Called when a pointer is released on the widget. + /// + /// The normalized point of the pointer release in the widget's rectangle. The coordinates are in the range [0,1] where (0,0) is the bottom-left corner and (1,1) is the top-right corner. + /// The unique id for the active pointer/touch. + /// Returns true if the pointer release hits an interactive element; otherwise, false. + bool OnPointerUp(Vector2 normalizedPointInRect, int pointerId); + + /// + /// Called when a pointer exits the widget. + /// + /// The normalized point of the pointer exit in the widget's rectangle. The coordinates are in the range [0,1] where (0,0) is the bottom-left corner and (1,1) is the top-right corner. + /// The unique id for the active pointer/touch. + /// Returns true if the pointer exit hits an interactive element; otherwise, false. + bool OnPointerExit(Vector2 normalizedPointInRect, int pointerId); + + /// + /// Called when a pointer enters the widget. + /// + /// The normalized point of the pointer enter in the widget's rectangle. The coordinates are in the range [0,1] where (0,0) is the bottom-left corner and (1,1) is the top-right corner. + /// The unique id for the active pointer/touch. + /// Returns true if the pointer enter hits an interactive element; otherwise, false. + bool OnPointerEnter(Vector2 normalizedPointInRect, int pointerId); + + } +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/Widgets/IRiveWidget.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/Widgets/IRiveWidget.cs.meta new file mode 100644 index 00000000..d941a16c --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/Widgets/IRiveWidget.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: daa9d85f269554d7c9749157f1ed0493 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/Widgets/IRiveWidget.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/Widgets/ProceduralRiveWidget.cs b/Packages/app.rive.rive-unity/Runtime/Components/Public/Widgets/ProceduralRiveWidget.cs new file mode 100644 index 00000000..4ea953a2 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/Widgets/ProceduralRiveWidget.cs @@ -0,0 +1,138 @@ +using Rive.Utils; +using UnityEngine; + +namespace Rive.Components +{ + /// + /// Renders a ProceduralDrawing within a RivePanel. + /// + [AddComponentMenu("Rive/Procedural Rive Widget")] + public sealed class ProceduralRiveWidget : WidgetBehaviour + { + [SerializeField] private ProceduralDrawing m_proceduralDrawing; + + [Tooltip("The hit test behavior for the widget.")] + [SerializeField] private HitTestBehavior m_hitTestBehavior = HitTestBehavior.None; + + private ProceduralRenderObject m_renderObject; + + + public override IRenderObject RenderObject => m_renderObject; + + public ProceduralDrawing ProceduralDrawing => m_proceduralDrawing; + + public override HitTestBehavior HitTestBehavior { get => m_hitTestBehavior; set => m_hitTestBehavior = value; } + + void Start() + { + if (m_proceduralDrawing == null) + { + return; + } + + Load(m_proceduralDrawing); + } + + public override bool Tick(float deltaTime) + { + bool needsRedraw = base.Tick(deltaTime); + if (m_proceduralDrawing == null) + { + return needsRedraw; + } + if (m_proceduralDrawing.Advance(deltaTime)) + { + needsRedraw = true; + } + + return needsRedraw; + } + + public void Load(ProceduralDrawing proceduralDrawing) + { + if (proceduralDrawing == null) + { + DebugLogger.Instance.LogError("Can't load null procedural drawing."); + return; + } + + Status = WidgetStatus.Loading; + + m_proceduralDrawing = proceduralDrawing; + + + try + { + m_renderObject = new ProceduralRenderObject(m_proceduralDrawing); + } + catch (System.Exception e) + { + DebugLogger.Instance.LogError($"Error loading procedural drawing: {e.Message}"); + Status = WidgetStatus.Error; + return; + } + + HandleLoadComplete(); + + } + + public override bool HitTest(Vector2 normalizedPointInRect) + { + if (m_proceduralDrawing == null) + { + return base.HitTest(normalizedPointInRect); + } + + return m_proceduralDrawing.HitTest(normalizedPointInRect, RectTransform.rect); + } + + public override bool OnPointerDown(Vector2 normalizedPointInRect, int pointerId) + { + base.OnPointerDown(normalizedPointInRect, pointerId); + + if (m_proceduralDrawing == null) + { + return false; + } + + return m_proceduralDrawing.HandlePointerDown(normalizedPointInRect, RectTransform.rect); + } + + public override bool OnPointerMove(Vector2 normalizedPointInRect, int pointerId) + { + base.OnPointerMove(normalizedPointInRect, pointerId); + + if (m_proceduralDrawing == null) + { + return false; + } + + return m_proceduralDrawing.HandlePointerMove(normalizedPointInRect, RectTransform.rect); + } + + public override bool OnPointerUp(Vector2 normalizedPointInRect, int pointerId) + { + base.OnPointerUp(normalizedPointInRect, pointerId); + + if (m_proceduralDrawing == null) + { + return false; + } + + return m_proceduralDrawing.HandlePointerUp(normalizedPointInRect, RectTransform.rect); + } + + public override bool OnPointerExit(Vector2 normalizedPointInRect, int pointerId) + { + base.OnPointerExit(normalizedPointInRect, pointerId); + + if (m_proceduralDrawing == null) + { + return false; + } + + return m_proceduralDrawing.HandlePointerExit(normalizedPointInRect, RectTransform.rect); + } + + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/Widgets/ProceduralRiveWidget.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/Widgets/ProceduralRiveWidget.cs.meta new file mode 100644 index 00000000..b544652b --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/Widgets/ProceduralRiveWidget.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 9cd9a3f8258f648a1baa648cb5116f43 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: f377684eb5623462e80ebba320696f74, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/Widgets/ProceduralRiveWidget.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/Widgets/RiveWidget.cs b/Packages/app.rive.rive-unity/Runtime/Components/Public/Widgets/RiveWidget.cs new file mode 100644 index 00000000..0f38b00d --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/Widgets/RiveWidget.cs @@ -0,0 +1,1318 @@ +using System; +using System.Collections.Generic; + +#if UNITY_EDITOR +using System.Linq; +#endif +using Rive.EditorTools; +using Rive.Components.Utilities; +using Rive.Utils; +using UnityEngine; +using UnityEngine.Events; + +namespace Rive.Components +{ + /// + /// This component is used to display a Rive file within a Rive Panel. + /// +#if UNITY_EDITOR + [HelpURL(InspectorDocLinks.RiveWidget)] + [InspectorSection(WidgetInspectorSections.FileSettings, "File Settings")] + [InspectorSection(WidgetInspectorSections.Display, "Display")] + [InspectorSection(WidgetInspectorSections.Input, "Input")] + [InspectorSection(WidgetInspectorSections.Data, "Data")] +#endif + [AddComponentMenu("Rive/Rive Widget")] + public sealed class RiveWidget : WidgetBehaviour + { + /// + /// Determines whether ReportedEvents are pooled or not. + /// + public enum EventPoolingMode + { + /// + /// Events are pooled and reused. + /// + Enabled = 0, + /// + /// Events are not pooled. A new event is created each time an event is reported. + /// + Disabled = 1 + } + + /// + /// Controls how viewmodel instance property callbacks are fired. + /// + public enum DataBindingPropertyCallbackApproach + { + /// + /// Legacy behavior. Callbacks are handled by propagating from the root ViewModelInstance + /// after advancing a specific state machine (per-widget). + /// + Propagation = 0, + + /// + /// Orchestrator behavior. Callbacks are triggered after + /// all panels/widgets have ticked. + /// + Orchestrator = 1, + } + + /// + /// Temporary fallback hatch for callback handling. Defaults to . + /// + public static DataBindingPropertyCallbackApproach PropertyCallbackApproach { get; set; } = DataBindingPropertyCallbackApproach.Orchestrator; + +#if UNITY_EDITOR + // Account for Editor Domain Reload being disabled (static state persists across play sessions). + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] + private static void ResetStaticState() + { + PropertyCallbackApproach = DataBindingPropertyCallbackApproach.Orchestrator; + } +#endif + + /// + /// Determines how the widget should handle binding to a ViewModel instance. + /// + public enum DataBindingMode + { + /// + /// Automatically binds to the default instance if available + /// + AutoBindDefault = 0, + + /// + /// Automatically binds to a selected instance if available + /// + AutoBindSelected = 1, + + /// + /// No automatic binding + /// + Manual = 2 + } + + private static class WidgetInspectorSections + { + + public const string FileSettings = "file-settings"; + + public const string Display = "display"; + public const string Input = "input"; + + public const string Advanced = "advanced"; + + public const string Data = "data"; + + } + +#if UNITY_EDITOR + [OnValueChanged(nameof(OnAssetChangedInEditor))] + [InspectorField(WidgetInspectorSections.FileSettings, helpUrl: InspectorDocLinks.AddingRiveAssets)] +#endif + [Tooltip("The Rive file (.riv) to load.")] + [SerializeField] private Asset m_asset; + + + +#if UNITY_EDITOR + [HideIf(nameof(ShouldHideArtboardNameAndStateMachineName))] + [InspectorField(WidgetInspectorSections.FileSettings, helpUrl: InspectorDocLinks.Artboards)] + [Tooltip("The name of the artboard to load.")] + [OnValueChanged(nameof(OnArtboardChangedInEditor))] + [Dropdown(nameof(GetDisplayArtboardNames), trackChanges: true)] +#endif + [SerializeField] private string m_artboardName; + +#if UNITY_EDITOR + [HideIf(nameof(ShouldHideArtboardNameAndStateMachineName))] + [InspectorField(WidgetInspectorSections.FileSettings, helpUrl: InspectorDocLinks.StateMachines)] + [OnValueChanged(nameof(OnStateMachineChangedInEditor))] + [Dropdown(nameof(GetDisplayStateMachineNames), trackChanges: true)] +#endif + [Tooltip("The name of the state machine to load.")] + [SerializeField] private string m_stateMachineName; + + + +#if UNITY_EDITOR + [InspectorField(WidgetInspectorSections.Display, helpUrl: InspectorDocLinks.FitAndAlignment)] + [OnValueChanged(nameof(OnFitChangedInEditor))] +#endif + [Tooltip("The fit mode to use when drawing the artboard.")] + [SerializeField] private Fit m_fit = Fit.Contain; + +#if UNITY_EDITOR + [InspectorField(WidgetInspectorSections.Display, helpUrl: InspectorDocLinks.FitAndAlignment)] + [HideIf(nameof(ShouldHideAlignment))] + [OnValueChanged(nameof(OnAlignmentChangedInEditor))] + [Tooltip("The alignment to use when drawing the artboard.")] +#endif + [SerializeField] + private Alignment m_alignment = Alignment.Center; + +#if UNITY_EDITOR + [ShowIf(nameof(ShouldShowLayoutOptions))] + [InspectorField(WidgetInspectorSections.Display, helpUrl: InspectorDocLinks.LayoutScaleFactor)] + [OnValueChanged(nameof(OnScaleFactorChangedInEditor))] +#endif + [Tooltip("The scale factor to use when drawing the artboard when using the Layout fit mode. Increase this value to make the artboard appear larger.")] + [SerializeField] private float m_layoutScaleFactor = 1.0f; + +#if UNITY_EDITOR + [ShowIf(nameof(ShouldShowLayoutOptions))] + [InspectorField(WidgetInspectorSections.Display, helpUrl: InspectorDocLinks.LayoutScalingModes)] + [OnValueChanged(nameof(OnLayoutScalingModeChangedInEditor))] +#endif + [Tooltip("The layout scaling mode to use when drawing the artboard.")] + [SerializeField] private LayoutScalingMode m_layoutScalingMode = LayoutScalingMode.ReferenceArtboardSize; + + +#if UNITY_EDITOR + [InspectorField(WidgetInspectorSections.Display)] + [ShowIf(nameof(ShouldShowDpiFields))] + [OnValueChanged(nameof(OnFallbackDPIChanged))] +#endif + [Tooltip("Fallback DPI to use if the screen DPI is not available.")] + [SerializeField] private float m_fallbackDPI = 96f; + +#if UNITY_EDITOR + [InspectorField(WidgetInspectorSections.Display)] + [ShowIf(nameof(ShouldShowDpiFields))] + [OnValueChanged(nameof(OnReferenceDPIChanged))] +#endif + [Tooltip("Specifies the screen density (DPI) that your UI is targeting as its baseline. For example, if you're targeting standard desktop displays (96 DPI) as your 1x baseline, set this to 96. This will be used to calculate the Device Pixel Ratio (screen DPI / reference DPI) and scale your content accordingly. This ensures your UI appears at the intended physical size across different screen densities. Similar to how @1x, @2x, @3x works on the web, where a DPR of 2 means the screen is twice as dense as your reference.")] + [SerializeField] private float m_referenceDPI = 150f; + + +#if UNITY_EDITOR + + [Tooltip("Controls how hit testing is handled:\n" + + "\n" + + "- Opaque blocks all hits.\n" + + "\n" + + "- Translucent only blocks hits on listeners.\n" + + "\n" + + "- Transparent (deprecated) allows hits to pass through while still detecting listeners.\n" + + "\n" + + "- None disables hit testing completely.")] + [InspectorField(WidgetInspectorSections.Input, helpUrl: InspectorDocLinks.HitTesting)] +#endif + [SerializeField] private HitTestBehavior m_hitTestBehavior = HitTestBehavior.Opaque; + +#if UNITY_EDITOR + [Tooltip("Determines whether ReportedEvents are pooled or not. If disabled, a new event is created each time an event is reported.")] + [InspectorField(WidgetInspectorSections.Advanced)] +#endif + [SerializeField] private EventPoolingMode m_eventPoolingMode = EventPoolingMode.Enabled; + + [Tooltip("Controls the playback speed of the graphic. A value of 1 is normal speed, 2 is double speed, 0.5 is half speed")] + [InspectorField(WidgetInspectorSections.Advanced)] + [SerializeField] private float m_speed = 1.0f; + +#if UNITY_EDITOR + [Tooltip("Determines how the widget should handle binding to a ViewModel instance.")] + [InspectorField(WidgetInspectorSections.Data, helpUrl: InspectorDocLinks.UnityDataBindingOverview)] + [OnValueChanged(nameof(OnDataBindingModeChangedInEditor))] +#endif + [SerializeField] private DataBindingMode m_dataBindingMode = DataBindingMode.AutoBindDefault; + + + + [Tooltip("The ViewModel instance to bind to.")] + [InspectorField(WidgetInspectorSections.Data, displayName: "ViewModel Instance")] +#if UNITY_EDITOR + [ShowIf(nameof(ShouldShowDataBindingInstanceField))] + [Dropdown(nameof(GetViewModelInstanceNames), trackChanges: true)] +#endif + [SerializeField] private string m_viewModelInstanceName; + + + [Tooltip("Optional custom audio provider to use for audio playback. If not set, a shared global audio provider will be used.")] + [InspectorField(WidgetInspectorSections.Advanced)] + [SerializeField] private AudioProvider m_customAudioProvider = null; + + + bool m_needsLayoutRecalculationFix = false; + + + private ArtboardLoadHelper m_controller; + + +#if UNITY_EDITOR + [OnValueChanged(nameof(OnScaleFactorChangedInEditor))] +#endif + private bool m_useFallbackDPI = true; + + + + /// + /// If true, the widget will use the fallback DPI value when calculating the effective scale factor instead of the screen DPI. + /// + internal bool UseFallbackDPI + { + get => m_useFallbackDPI; + set + { + if (m_useFallbackDPI != value) + { + m_useFallbackDPI = value; + OnFallbackDPIChanged(); + } + } + } + + + private ArtboardLoadHelper Controller + { + get + { + if (m_isDestroyed) + { + return null; + } + + if (m_controller == null) + { + m_controller = new ArtboardLoadHelper(); + + SubscribeToControllerEvents(m_controller); + + } + + return m_controller; + } + } + + public override IRenderObject RenderObject { get => Controller?.RenderObject; } + + + /// + /// The Rive file that is currently loaded. + /// + public File File { get => Controller?.File; } + + + /// + /// The artboard that is currently loaded. + /// + public Artboard Artboard { get => Controller?.Artboard; } + + /// + /// The state machine that is currently loaded. + /// + public StateMachine StateMachine { get => Controller?.StateMachine; } + + + public Fit Fit + { + get => m_fit; set + { + if (m_fit != value) + { + m_fit = value; + OnFitChanged(); + } + } + } + + public Alignment Alignment + { + get => m_alignment; + set + { + if (m_alignment != value) + { + m_alignment = value; + OnAlignmentChanged(); + } + } + } + + /// + /// The scale factor to use when drawing the artboard when using the Layout fit mode. + /// + public float ScaleFactor + { + get + { + // We return the user set scale factor as that is what's used to calculate the effective scale factor. + return m_layoutScaleFactor; + } + set + { + if (m_layoutScaleFactor == value) + { + return; + } + m_layoutScaleFactor = value; + + OnScaleFactorChanged(); + + } + } + + + /// + /// The layout scaling mode to use when drawing the artboard. + /// + public LayoutScalingMode ScalingMode + { + get + { + if (RenderObjectWithArtboard == null) + { + return m_layoutScalingMode; + } + return m_layoutScalingMode; + } + set + { + if (m_layoutScalingMode == value) + { + return; + } + + m_layoutScalingMode = value; + + OnScaleModeChanged(); + } + } + + /// + /// The name of the artboard that is currently loaded. + /// + public string ArtboardName { get => m_artboardName; } + + /// + /// The name of the state machine that is currently loaded. + /// + public string StateMachineName { get => m_stateMachineName; } + + /// + /// The asset that is currently loaded. + /// + public Asset Asset { get => m_asset; } + + + private ArtboardRenderObject RenderObjectWithArtboard => Controller?.RenderObject; + + /// + /// The DPI to use if the screen DPI is not available. + /// + public float FallbackDPI + { + get => m_fallbackDPI; set + { + if (m_fallbackDPI != value) + { + m_fallbackDPI = value; + OnFallbackDPIChanged(); + } + } + } + + /// + /// Specifies the screen density (DPI) that your UI is targeting as its baseline. For example, if you're targeting standard desktop displays (96 DPI) as your 1x baseline, set this to 96. This will be used to calculate the Device Pixel Ratio (screen DPI / reference DPI) and scale your content accordingly. This ensures your UI appears at the intended physical size across different screen densities. Similar to how @1x, @2x, @3x works on the web, where a DPR of 2 means the screen is twice as dense as your reference. + /// + public float ReferenceDPI + { + get => m_referenceDPI; set + { + if (m_referenceDPI != value) + { + m_referenceDPI = value; + OnReferenceDPIChanged(); + } + } + } + + + public override HitTestBehavior HitTestBehavior { get => m_hitTestBehavior; set => m_hitTestBehavior = value; } + + /// + /// Determines whether ReportedEvents are pooled or not. + /// + public EventPoolingMode ReportedEventPoolingMode { get => m_eventPoolingMode; set => m_eventPoolingMode = value; } + + /// + /// Determines how the widget should handle binding to a ViewModel instance. + /// + public DataBindingMode BindingMode + { + get => m_dataBindingMode; + set + { + m_dataBindingMode = value; + } + } + + /// + /// The name of the ViewModel instance to bind to. + /// + public string ViewModelInstanceName { get => m_viewModelInstanceName; set => m_viewModelInstanceName = value; } + + /// + /// Controls the playback speed of the graphic. A value of 1 is normal speed, 2 is double speed, 0.5 is half speed. + /// + public float Speed + { + get => m_speed; + set + { + m_speed = value; + } + } + + /// + /// Event that is triggered when a Rive event is reported. + /// + public event Action OnRiveEventReported; + + + + private Asset m_fileLoadedFromAsset = null; + + private bool m_isDestroyed = false; + + private static AudioProvider s_globalAudioProvider = null; + + /// + /// The shared audio provider for all Rive widgets if the user has not assigned one to the widget. + /// + private static AudioProvider GlobalAudioProvider + { + get + { + if (!Application.isPlaying) + { + return null; + } + + if (s_globalAudioProvider == null) + { + // Since the rpHandler already exists, we can store the global audio provider on it. + MonoBehaviour rpHandler = RenderPipelineHelper.CurrentHandler as MonoBehaviour; + GameObject globalAudioProviderObject = rpHandler == null ? new GameObject("GlobalAudioProvider") : rpHandler.gameObject; + + // If we spawned the gameobject because the rpHandler wasn't in the scene, we need to set it to not destroy on load. + if (rpHandler == null) + { + DontDestroyOnLoad(globalAudioProviderObject); + } + + s_globalAudioProvider = globalAudioProviderObject.AddComponent(); + } + + return s_globalAudioProvider; + } + } + + /// + /// The AudioProvider currently used by this widget for audio playback. + /// This will be the custom provider if one has been assigned; otherwise, it will be the shared global provider. + /// On WebGL builds, this will always be null since AudioProvider is not supported on that platform. + /// + internal AudioProvider AudioProvider => m_customAudioProvider == null ? GlobalAudioProvider : m_customAudioProvider; + + /// + /// An optional custom AudioProvider override for this widget. + /// When set to a non-null value, the widget will use this provider instead of the shared global provider. + /// When set to null, the widget will fall back to using the shared global provider. + /// + /// On WebGL, custom AudioProviders are not supported. Audio will be routed through the system instead of Unity's AudioSource. + public AudioProvider CustomAudioProvider + { + get => m_customAudioProvider; + set + { + m_customAudioProvider = value; + SetUpAudioIfNeeded(Controller?.Artboard); + } + } + + + protected override void OnEnable() + { + base.OnEnable(); + + } + + + private void Start() + { + if (m_asset != null && Status == WidgetStatus.Uninitialized) + { + LoadFromAssetIfNeeded(); + } + } + + + public override bool Tick(float deltaTime) + { + + bool needsRedraw = base.Tick(deltaTime); + + if (Controller == null || Status != WidgetStatus.Loaded) + { + return needsRedraw; + } + + ApplyLayoutRecalculationFixIfNeeded();// Do this before Controller.Tick because doing it after affects triggers on the first frame + Controller.Tick(deltaTime, ReportedEventPoolingMode, Speed); + return needsRedraw; + + } + + private void SubscribeToControllerEvents(ArtboardLoadHelper controller) + { + if (controller == null) + { + return; + } + + controller.OnRiveEventReported += HandleRiveEventReported; + } + private void UnsubscribeFromControllerEvents(ArtboardLoadHelper controller) + { + if (controller == null) + { + return; + } + controller.OnRiveEventReported -= HandleRiveEventReported; + + } + + private void HandleRiveEventReported(ReportedEvent report) + { + OnRiveEventReported?.Invoke(report); + } + + private void HandleLoadError(ArtboardLoadHelper.LoadErrorEventData eventData) + { + Status = WidgetStatus.Error; + } + + + + /// + /// Flips the normalized point on the y-axis if needed, based on the graphics API. If we don't do this, the pointer interaction will be positioned incorrectly on some platforms. + /// + /// + /// The normalized point with the y-axis flipped if needed. + private Vector2 FlipNormalizedPointIfNeeded(Vector2 normalizedPoint) + { + bool shouldFlip = TextureHelper.ShouldFlipInput(); + + if (shouldFlip) + { + normalizedPoint.y = 1 - normalizedPoint.y; + } + + return normalizedPoint; + } + + /// + /// Tries to get the Rive point from the local normalized point in the frame. + /// + /// The local normalized point in the frame. + /// The point in Rive coordinates. + /// True if the Rive point was successfully retrieved, false otherwise. + private bool TryGetRivePoint(Vector2 localNormalizedPointInFrame, out Vector2 rivePoint) + { + rivePoint = Vector2.zero; + + + // Flip Y coordinate if needed + localNormalizedPointInFrame = FlipNormalizedPointIfNeeded(localNormalizedPointInFrame); + + var rect = RectTransform.rect; + + // When in Layout fit mode, we need to account for the effective scale + if (Fit == Fit.Layout) + { + float effectiveScale = GetEffectiveScaleFactor(); + // Scale the rect dimensions by the effective scale factor + rect = new Rect( + 0, + 0, + rect.width / effectiveScale, + rect.height / effectiveScale + ); + } + else + { + // For other fit modes, use the regular rect with 0,0 origin + rect = new Rect(0, 0, rect.width, rect.height); + } + + + Fit fit = RenderObjectWithArtboard.Fit; + Alignment alignment = RenderObjectWithArtboard.Alignment; + Artboard artboard = RenderObjectWithArtboard.Artboard; + + Vector2 riveScreenPosition = new Vector2(localNormalizedPointInFrame.x * rect.width, localNormalizedPointInFrame.y * rect.height); + + rivePoint = artboard.LocalCoordinate( + riveScreenPosition, + rect, + fit, + alignment + ); + + return true; + } + + + public override bool HitTest(Vector2 normalizedPointInRect) + { + Vector2 rivePoint; + + if (!TryGetRivePoint(normalizedPointInRect, out rivePoint)) + { + return false; + } + + return StateMachine.HitTest(rivePoint); + } + + + + + public override bool OnPointerDown(Vector2 normalizedPointInRect, int pointerId) + { + if (StateMachine == null) + { + return false; + } + Vector2 rivePoint; + if (!TryGetRivePoint(normalizedPointInRect, out rivePoint)) + { + return false; + } + + HitResult hitResult = StateMachine.PointerDown(rivePoint, pointerId); + + return hitResult != HitResult.None; + } + + /// + /// Called when a pointer is released on the widget. + /// + /// The normalized point of the pointer release in the widget's rectangle. The coordinates are in the range [0,1] where (0,0) is the bottom-left corner and (1,1) is the top-right corner. + /// The unique id for the active pointer/touch. + public override bool OnPointerUp(Vector2 normalizedPointInRect, int pointerId) + { + if (StateMachine == null) + { + return false; + } + Vector2 rivePoint; + if (!TryGetRivePoint(normalizedPointInRect, out rivePoint)) + { + return false; + } + + HitResult hitResult = StateMachine.PointerUp(rivePoint, pointerId); + + return hitResult != HitResult.None; + + } + + /// + /// Called when a pointer is moved on the widget. + /// + /// The normalized point of the pointer position in the widget's rectangle. The coordinates are in the range [0,1] where (0,0) is the bottom-left corner and (1,1) is the top-right corner. + /// The unique id for the active pointer/touch. + public override bool OnPointerMove(Vector2 normalizedPointInRect, int pointerId) + { + if (StateMachine == null) + { + return false; + } + + Vector2 rivePoint; + if (!TryGetRivePoint(normalizedPointInRect, out rivePoint)) + { + return false; + } + + HitResult hitResult = StateMachine.PointerMove(rivePoint, pointerId); + + return hitResult != HitResult.None; + + } + + public override bool OnPointerExit(Vector2 normalizedPointInRect, int pointerId) + { + if (StateMachine == null) + { + return false; + } + + Vector2 rivePoint; + if (!TryGetRivePoint(normalizedPointInRect, out rivePoint)) + { + return false; + } + HitResult hitResult = StateMachine.PointerExit(rivePoint, pointerId); + + return hitResult != HitResult.None; + + } + + public override bool OnPointerEnter(Vector2 normalizedPointInRect, int pointerId) + { + if (StateMachine == null) + { + return false; + } + + Vector2 rivePoint; + if (!TryGetRivePoint(normalizedPointInRect, out rivePoint)) + { + return false; + } + + // There's no specific StateMachine.PointerEnter method, so we use PointerMove instead to inform rive of the current pointer position. + HitResult hitResult = StateMachine.PointerMove(rivePoint, pointerId); + + return hitResult != HitResult.None; + + } + + + /// + /// Internal method to handle loading from either an asset or direct file + /// + private void LoadInternal(File file, Asset fromAsset = null) + { + + if (file == null) + { + Status = WidgetStatus.Error; + + DebugLogger.Instance.LogError("Attempted to load a null Rive file."); + return; + } + + Status = WidgetStatus.Loading; + m_fileLoadedFromAsset = fromAsset; + ArtboardLoadHelper.LoadResult result = Controller.Load(file, m_fit, m_alignment, m_artboardName, m_stateMachineName, GetEffectiveScaleFactor(), new ArtboardLoadHelper.DataBindingLoadInfo(BindingMode, ViewModelInstanceName)); + + if (result.Success) + { + SetUpAudioIfNeeded(Controller.Artboard); + HandleLoadComplete(); + } + else + { + HandleLoadError(result.ErrorData); + } + } + + /// + /// Loads a Rive file and specified artboard and state machine. + /// + /// The Rive file to load. + /// The fit mode to use. + /// The alignment to use. + /// The name of the artboard to load. + /// The name of the state machine to load. + public void Load(File file, string artboardName, string stateMachineName) + { + m_artboardName = artboardName; + m_stateMachineName = stateMachineName; + + ReleaseFileIfResponsibleForLoading(); + + LoadInternal(file, null); + } + + + /// + /// Loads a Rive file using the default artboard and state machine. + /// + /// The Rive file to load. + public void Load(File file) + { + ResetToDefaultArtboardAndStateMachineName(); + + ReleaseFileIfResponsibleForLoading(); + + LoadInternal(file, null); + } + + /// + /// Loads from a Rive asset and specified artboard and state machine. + /// + /// The Rive asset to load. + /// The name of the artboard to load. + /// The name of the state machine to load. + public void Load(Asset asset, string artboardName, string stateMachineName) + { + + m_asset = asset; + m_artboardName = artboardName; + m_stateMachineName = stateMachineName; + + LoadFromAssetIfNeeded(); + } + + /// + /// Loads from a Rive asset using the default artboard and state machine. + /// + /// The Rive asset to load. + public void Load(Asset asset) + { + m_asset = asset; + ResetToDefaultArtboardAndStateMachineName(); + LoadFromAssetIfNeeded(); + } + + private void ResetToDefaultArtboardAndStateMachineName() + { + m_artboardName = null; + m_stateMachineName = null; + } + + + private void LoadFromAssetIfNeeded() + { + if (m_asset == null) + { + Status = WidgetStatus.Error; + return; + } + + // If we already have a loaded file from this asset then we can use it directly to avoid updating the asset ref count + if (m_fileLoadedFromAsset != null && ReferenceEquals(m_asset, m_fileLoadedFromAsset)) + { + LoadInternal(File, m_fileLoadedFromAsset); + + return; + } + + ReleaseFileIfResponsibleForLoading(); + + + Status = WidgetStatus.Loading; + var loadedFile = File.Load(Asset); + + if (loadedFile == null) + { + Status = WidgetStatus.Error; + return; + } + + LoadInternal(loadedFile, m_asset); + } + + + + private void OnScaleFactorChanged() + { + if (RenderObjectWithArtboard != null && Fit == Fit.Layout) + { + ResizeArtboardForLayoutIfNeeded(); + TriggerRedrawNeededEvent(); + } + } + + private void OnAlignmentChanged() + { + if (RenderObjectWithArtboard != null) + { + RenderObjectWithArtboard.Alignment = Alignment; + TriggerRedrawNeededEvent(); + } + } + + private void OnFitChanged() + { + if (RenderObjectWithArtboard != null) + { + + RenderObjectWithArtboard.Fit = Fit; + + if (Artboard != null) + { + // Check if the original artboard size is different from the current artboard size + // When outside of layout mode, we should reset the artboard size to the original size if it has been changed. + + bool artboardSizeIsDifferentFromOriginal = (Artboard.Width != Controller.OriginalArtboardWidth || Artboard.Height != Controller.OriginalArtboardHeight); + + bool shouldResetArtboardSize = Fit != Fit.Layout && artboardSizeIsDifferentFromOriginal; + + if (shouldResetArtboardSize) + { + Artboard.ResetArtboardSize(); + } + } + + + + ResizeArtboardForLayoutIfNeeded(); + TriggerRedrawNeededEvent(); + } + } + + private void OnScaleModeChanged() + { + if (Artboard != null && Fit == Fit.Layout) + { + ResizeArtboardForLayoutIfNeeded(); + TriggerRedrawNeededEvent(); + } + } + + private void OnFallbackDPIChanged() + { + if (RenderObjectWithArtboard != null && Fit == Fit.Layout && m_layoutScalingMode == LayoutScalingMode.ConstantPhysicalSize) + { + ResizeArtboardForLayoutIfNeeded(); + TriggerRedrawNeededEvent(); + } + } + + private void OnReferenceDPIChanged() + { + if (RenderObjectWithArtboard != null && Fit == Fit.Layout && m_layoutScalingMode == LayoutScalingMode.ConstantPhysicalSize) + { + ResizeArtboardForLayoutIfNeeded(); + TriggerRedrawNeededEvent(); + } + } + + private float GetEffectiveScaleFactor() + { + if (Controller == null) + { + return 1.0f; + } + + Vector2 ogArtboardSize = new Vector2(Controller.OriginalArtboardWidth, Controller.OriginalArtboardHeight); + var screenDPI = UseFallbackDPI ? m_fallbackDPI : Screen.dpi; + return ArtboardLoadHelper.CalculateEffectiveScaleFactor(m_layoutScalingMode, m_layoutScaleFactor, ogArtboardSize, RectTransform.rect, m_referenceDPI, fallbackDPI: m_fallbackDPI, screenDPI: screenDPI); + + } + + private void ResizeArtboardForLayoutIfNeeded() + { + if (Artboard != null && Fit == Fit.Layout && RenderObjectWithArtboard != null) + { + + float effectiveScale = GetEffectiveScaleFactor(); + var rect = RectTransform.rect; + + if (ArtboardLoadHelper.CalculateArtboardDimensionsForLayout(rect, effectiveScale, out float newWidth, out float newHeight)) + { + RenderObjectWithArtboard.EffectiveLayoutScaleFactor = effectiveScale; + + Artboard.Width = newWidth; + + Artboard.Height = newHeight; + + + } + + + } + } + + private void SetUpAudioIfNeeded(Artboard artboard) + { + if (m_isDestroyed) + { + return; + } + +#if UNITY_WEBGL && !UNITY_EDITOR +// WebGL doesn't support OnAudioFilterRead, so don't use the audio engine in this case. On WebGL, rive will use system audio instead, which bypasses Unity's audio system. +return; +#endif + + + if (artboard == null || !artboard.HasAudio) + { + return; + } + + var provider = m_customAudioProvider ?? GlobalAudioProvider; + + if (provider == null) + { + return; + } + + artboard.SetAudioEngine(provider.AudioEngine); + } + + + protected override void HandleLoadComplete() + { + ResizeArtboardForLayoutIfNeeded(); + TriggerWidgetLoadedEvent(); + + m_needsLayoutRecalculationFix = true; + + ApplyLayoutRecalculationFixIfNeeded(); + } + + + private void TriggerWidgetLoadedEvent() + { + base.HandleLoadComplete(); + } + + private void ApplyLayoutRecalculationFixIfNeeded() + { + // This is a workaround for a bug where the layout is not recalculated correctly when the widget is first loaded. This seems to only happen with some files, like duelist.riv where we see the initial layout shift if we don't do this. + // TODO: check if we need to do something in the C++ layer to fix this instead of doing it here. + if (m_needsLayoutRecalculationFix && StateMachine != null) + { + m_needsLayoutRecalculationFix = false; + // On the initial frame, force the state machine to update the layout. We do this after base.HandleLoadComplete(); because that's where the OnWidgetStatusChanged event is triggered, and we want values that were set there to be applied before we advance the state machine. + // If we do this before base.HandleLoadComplete(); the values set in the OnWidgetStatusChanged event will not be applied on the first frame. + StateMachine.Advance(0f); + } + } + + protected override void OnRectTransformDimensionsChange() + { + // Do this before the base call so that the base call can recalculate the widget layout before we tell the panel to redraw + ResizeArtboardForLayoutIfNeeded(); + + base.OnRectTransformDimensionsChange(); + + + } + + private void ReleaseFileIfResponsibleForLoading() + { + if (File != null && m_fileLoadedFromAsset) + { + File.Dispose(); + m_fileLoadedFromAsset = null; + } + } + + + + protected override void OnDestroy() + { + base.OnDestroy(); + + ReleaseFileIfResponsibleForLoading(); + + if (m_controller != null) + { + UnsubscribeFromControllerEvents(m_controller); + m_controller.Dispose(); + } + m_isDestroyed = true; + } + + + + +#if UNITY_EDITOR + // Inspector-specific methods (used for custom inspector logic) + + /// + /// Sets the asset reference in the editor. + /// + /// The Rive asset to set. + internal void SetEditorAssetReference(Asset asset) + { + if (Application.isPlaying) + { + return; + } + m_asset = asset; + + OnAssetChangedInEditor(); + } + + private bool ShouldHideArtboardNameAndStateMachineName() + { + return Asset == null; + } + + private string[] GetDisplayArtboardNames() + { + if (Asset == null) return new string[0]; + return Asset.EditorOnlyMetadata.GetArtboardNames(); + } + + private string[] GetDisplayStateMachineNames() + { + if (Asset == null || string.IsNullOrEmpty(ArtboardName)) return new string[0]; + return Asset.EditorOnlyMetadata.GetStateMachineNames(ArtboardName); + } + + private void OnAssetChangedInEditor() + { + // If in play mode, make sure we haven't already loaded the asset or this might cause a double load + if (Application.isPlaying && Status == WidgetStatus.Loaded) + { + return; + } + + var names = GetDisplayArtboardNames(); + // If the artboard name is not in the list of artboards, set it to the first artboard in the list. + // We only want to do this if the user manually changes the asset, not if the asset is changed by the system. + if (names.Length > 0 && !names.Contains(ArtboardName)) + { + m_artboardName = names[0]; + } + OnArtboardChangedInEditor(); + + + } + + private void OnArtboardChangedInEditor() + { + + var names = GetDisplayStateMachineNames(); + // If the state machine name is not in the list of state machines for the current artboard, set it to the first state machine in the list. + if (names.Length > 0 && !names.Contains(StateMachineName)) + { + m_stateMachineName = names[0]; + } + + OnStateMachineChangedInEditor(); + } + + private void OnStateMachineChangedInEditor() + { + // If we're in play mode, reload the asset + if (Application.isPlaying && Status != WidgetStatus.Loaded && m_asset != null) + { + LoadFromAssetIfNeeded(); + return; + } + } + + + private void OnLayoutScalingModeChangedInEditor() + { + if (!Application.isPlaying) + { + return; + } + OnScaleModeChanged(); + + } + + private void OnScaleFactorChangedInEditor() + { + if (!Application.isPlaying) + { + return; + } + OnScaleFactorChanged(); + } + + private void OnFitChangedInEditor() + { + if (!Application.isPlaying) + { + return; + } + OnFitChanged(); + } + + private void OnAlignmentChangedInEditor() + { + if (!Application.isPlaying) + { + return; + } + + OnAlignmentChanged(); + } + + private void OnDataBindingModeChangedInEditor() + { + // If we're not in play mode, then set the view model instance name to default + if (Application.isPlaying) + { + return; + } + + // Set the view model instance name to default if we're not in auto bind mode + if (m_dataBindingMode == DataBindingMode.AutoBindSelected) + { + m_viewModelInstanceName = GetInitialViewModelNameForArtboard(); + } + } + + + private bool ShouldShowDpiFields() + { + if (!ShouldShowLayoutOptions()) + { + return false; + } + return m_layoutScalingMode == LayoutScalingMode.ConstantPhysicalSize; + } + + private bool ShouldShowLayoutOptions() + { + return Fit == Fit.Layout; + } + + private bool ShouldHideAlignment() + { + return Fit == Fit.Layout; + } + + private bool ShouldShowDataBindingInstanceField() + { + return m_dataBindingMode == DataBindingMode.AutoBindSelected; + } + + private List GetViewModelInstanceNames() + { + if (Asset == null || string.IsNullOrEmpty(ArtboardName)) + { + return new List(); + } + + var metadata = Asset.EditorOnlyMetadata.GetArtboard(m_artboardName); + if (metadata == null) + { + return new List(); + } + + return metadata.DefaultViewModel.InstanceNames; + } + + private string GetInitialViewModelNameForArtboard() + { + if (Asset == null || string.IsNullOrEmpty(ArtboardName)) + { + return string.Empty; + } + + var metadata = Asset.EditorOnlyMetadata.GetArtboard(m_artboardName); + if (metadata == null) + { + return string.Empty; + } + + if (metadata.DefaultViewModel.InstanceNames.Count == 0) + { + return string.Empty; + } + + return metadata.DefaultViewModel.InstanceNames[0]; + } + + +#endif + + } +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/Widgets/RiveWidget.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/Widgets/RiveWidget.cs.meta new file mode 100644 index 00000000..92a71505 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/Widgets/RiveWidget.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 30b5bc34e03734ee49f044caba90a384 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: f377684eb5623462e80ebba320696f74, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/Widgets/RiveWidget.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/Widgets/WidgetBehaviour.cs b/Packages/app.rive.rive-unity/Runtime/Components/Public/Widgets/WidgetBehaviour.cs new file mode 100644 index 00000000..94e14e43 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/Widgets/WidgetBehaviour.cs @@ -0,0 +1,405 @@ +using System; +using Rive.EditorTools; +using Rive.Utils; +using UnityEngine; +using UnityEngine.Events; + + +namespace Rive.Components +{ + /// + /// Base class for creating custom RiveWidgets for different contexts. + /// + [DisallowMultipleComponent] + [InspectorSection(InspectorSections.Advanced, "Advanced", order: 1, style: SectionStyle.Foldout)] + [RequireComponent(typeof(RectTransform))] + public abstract class WidgetBehaviour : MonoBehaviour, IRiveWidget + { + protected static class InspectorSections + { + + public const string Advanced = "advanced"; + } + + + [HideInInspector] + [SerializeField] private RivePanel m_rivePanel; + + + private WidgetStatus m_status = WidgetStatus.Uninitialized; + + + private int m_cachedSiblingIndex; + + private bool m_shouldTriggerRedraw = false; + + + + public abstract IRenderObject RenderObject { get; } + + + /// + /// The current loading status of the widget. + /// + public WidgetStatus Status + { + get => m_status; protected set + { + + if (m_status == value) + { + return; + } + + m_status = value; + + OnWidgetStatusChanged?.Invoke(); + } + } + + public bool Enabled => this != null && this.enabled && this.gameObject != null && this.gameObject.activeInHierarchy; + + + // These events are used to notify the RivePanel that the widget's sorting might need to be updated. + public event Action OnSiblingIndexChanged; + + public event Action OnParentChanged; + + + + public RivePanel RivePanel + { + get => m_rivePanel; private set + { + if (ReferenceEquals(m_rivePanel, value)) + { + return; + } + + if (m_rivePanel != null) + { + UnsubscribeFromPanelEvents(m_rivePanel); + } + + m_rivePanel = value; + + if (m_rivePanel != null) + { + SubscribeToPanelEvents(m_rivePanel); + } + + } + } + + public RectTransform RectTransform => this.transform as RectTransform; + + public abstract HitTestBehavior HitTestBehavior { get; set; } + + + + + public event Action OnWidgetStatusChanged; + + + + protected virtual void OnEnable() + { + if (RivePanel == null || !IsDescendantOfPanel(RivePanel)) + { + RivePanel = GetComponentInParent(); + } + + + m_cachedSiblingIndex = this.transform.GetSiblingIndex(); + + UpdateRenderTransform(); + + if (RivePanel != null) + { + RivePanel.RegisterWidgetForRendering(this); + } + + + } + + + protected virtual void OnDisable() + { + if (m_rivePanel != null) + { + m_rivePanel.UnregisterWidgetFromRendering(this); + } + } + + + + private void SubscribeToPanelEvents(RivePanel panel) + { + if (panel == null) + { + return; + } + + panel.OnWidgetRemoved += HandleWidgetRemoved; + } + + private void UnsubscribeFromPanelEvents(RivePanel panel) + { + if (panel == null) + { + return; + } + + panel.OnWidgetRemoved -= HandleWidgetRemoved; + } + + + /// + /// This is called after the RiveWidget has finished loading but before the OnLoad event is triggered. Use this to perform any additional setup after the RiveWidget has loaded. + /// + protected virtual void HandleLoadComplete() + { + + // Do this to account for any changes in the RectTransform that may have occurred before the RiveWidget was loaded. + UpdateRenderTransform(); + TriggerRedrawNeededEvent(); + + Status = WidgetStatus.Loaded; + + } + + + + + + /// + /// Called when the RectTransform dimensions change. We resize the RenderTexture to match the new dimensions. + /// + protected virtual void OnRectTransformDimensionsChange() + { + if (m_rivePanel == null || !this.gameObject.activeInHierarchy) + { + return; + } + + if (RenderObject == null) + { + return; + } + + // Make sure we update the rect in the RenderObject as that is what is used to calculate the dimensions. + UpdateRenderTransform(); + + TriggerRedrawNeededEvent(); + + + } + + + + protected void TriggerRedrawNeededEvent() + { + m_shouldTriggerRedraw = true; + } + + private void HandleWidgetRemoved(IRiveWidget widget) + { + if (!ReferenceEquals(widget, this)) + { + return; + } + + if (RivePanel != null && !RivePanel.ContainsWidget(this)) + { + RivePanel = null; + } + + + } + + private void UpdateRenderTransform() + { + if (RenderObject == null) + { + return; + } + + RectTransform panelRectTransform = RivePanel != null ? RivePanel.WidgetContainer : null; + + if (panelRectTransform == null) + { + return; + } + + + + RenderObject.RenderTransform = RenderTransform.FromRectTransform(RectTransform, panelRectTransform); + } + + + + public virtual bool Tick(float deltaTime) + { + bool needsRedraw = false; + + if (Status != WidgetStatus.Loaded) + { + return needsRedraw; + } + + if (RectTransform.hasChanged) + { + RectTransform.hasChanged = false; + UpdateRenderTransform(); + OnRectTransformDimensionsChange(); + needsRedraw = true; + } + + int currentSiblingIndex = this.transform.GetSiblingIndex(); + if (currentSiblingIndex != m_cachedSiblingIndex) + { + m_cachedSiblingIndex = currentSiblingIndex; + OnSiblingIndexChanged?.Invoke(); + needsRedraw = true; + } + + if (m_shouldTriggerRedraw) + { + m_shouldTriggerRedraw = false; + needsRedraw = true; + } + + return needsRedraw; + } + + /// + /// This is called when a direct or indirect parent of the transform of the GameObject has changed. + /// + protected virtual void OnTransformParentChanged() + { + var currentParentPanel = GetComponentInParent(); + + + // Unregister from the old panel if the widget is not a child of it anymore + // or if the widget is a child of a different panel now. + if (RivePanel != null && !ReferenceEquals(currentParentPanel, RivePanel)) + { + RivePanel.UnregisterWidgetFromRendering(this); + } + + // Register with the new panel if there is one + if (currentParentPanel != null && !currentParentPanel.ContainsWidget(this)) + { + currentParentPanel.RegisterWidgetForRendering(this); + + RivePanel = currentParentPanel; + + } + + OnParentChanged?.Invoke(); + + } + + /// + /// Tests if a given local position within the widget's rectangle hits any interactive elements. + /// + /// + /// The normalized point of the pointer position in the widget's rectangle. The coordinates are in the range [0,1] where (0,0) is the bottom-left corner and (1,1) is the top-right corner. + /// + /// + /// Returns true if the position hits an interactive element; otherwise, false. + /// + public virtual bool HitTest(Vector2 normalizedPointInRect) + { + return false; + + } + + + /// + /// Called when a pointer is pressed on the widget. + /// + /// The normalized point of the pointer press in the widget's rectangle. The coordinates are in the range [0,1] where (0,0) is the bottom-left corner and (1,1) is the top-right corner. + /// The unique id for the active pointer/touch. + /// Returns true if the pointer press hits an interactive element; otherwise, false. + public virtual bool OnPointerDown(Vector2 normalizedPointInRect, int pointerId) + { + return false; + } + + /// + /// Called when a pointer is released on the widget. + /// + /// The normalized point of the pointer release in the widget's rectangle. The coordinates are in the range [0,1] where (0,0) is the bottom-left corner and (1,1) is the top-right corner. + /// The unique id for the active pointer/touch. + /// Returns true if the pointer release hits an interactive element; otherwise, false. + public virtual bool OnPointerUp(Vector2 normalizedPointInRect, int pointerId) + { + return false; + } + + /// + /// Called when a pointer is moved on the widget. + /// + /// The normalized point of the pointer position in the widget's rectangle. The coordinates are in the range [0,1] where (0,0) is the bottom-left corner and (1,1) is the top-right corner. + /// The unique id for the active pointer/touch. + /// Returns true if the pointer move hits an interactive element; otherwise, false. + public virtual bool OnPointerMove(Vector2 normalizedPointInRect, int pointerId) + { + return false; + } + + /// + /// Called when a pointer exits the widget. + /// + /// The normalized point of the pointer exit in the widget's rectangle. The coordinates are in the range [0,1] where (0,0) is the bottom-left corner and (1,1) is the top-right corner. + /// The unique id for the active pointer/touch. + /// Returns true if the pointer exit hits an interactive element; otherwise, false. + public virtual bool OnPointerExit(Vector2 normalizedPointInRect, int pointerId) + { + return false; + } + + /// + /// Called when a pointer enters the widget. + /// + /// The normalized point of the pointer enter in the widget's rectangle. The coordinates are in the range [0,1] where (0,0) is the bottom-left corner and (1,1) is the top-right corner. + /// The unique id for the active pointer/touch. + /// Returns true if the pointer enter hits an interactive element; otherwise, false. + public virtual bool OnPointerEnter(Vector2 normalizedPointInRect, int pointerId) + { + return false; + } + + protected virtual void OnDestroy() + { + + } + private bool IsDescendantOfPanel(RivePanel rivePanel) + { + if (rivePanel == null) + { + return false; + } + + return this.transform.IsChildOf(rivePanel.WidgetContainer); + } + +#if UNITY_EDITOR + + protected virtual void OnValidate() + { + + + if (RivePanel == null || !IsDescendantOfPanel(RivePanel)) + { + RivePanel = GetComponentInParent(); + } + + + } + +#endif + + } +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/Widgets/WidgetBehaviour.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/Widgets/WidgetBehaviour.cs.meta new file mode 100644 index 00000000..081724c4 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/Widgets/WidgetBehaviour.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 856e0d19fa5914d6e9fc470ba4d5c2a8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/Widgets/WidgetBehaviour.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/Widgets/WidgetStatus.cs b/Packages/app.rive.rive-unity/Runtime/Components/Public/Widgets/WidgetStatus.cs new file mode 100644 index 00000000..0be9b6cb --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/Widgets/WidgetStatus.cs @@ -0,0 +1,32 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace Rive.Components +{ + /// + /// Represents the current status of a Rive widget. + /// + public enum WidgetStatus + { + /// + /// The widget has not yet been initialized. This is the default state. + /// + Uninitialized = 0, + + /// + /// The widget is currently setting up the Rive graphic. + /// + Loading = 1, + + /// + /// The widget is ready to display the Rive graphic. + /// + Loaded = 2, + + /// + /// An error occurred while loading the Rive graphic. + /// + Error = 3 + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Public/Widgets/WidgetStatus.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/Public/Widgets/WidgetStatus.cs.meta new file mode 100644 index 00000000..ce729d21 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Public/Widgets/WidgetStatus.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: c6ff4924453f8439e9ecdf2548668cfb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/Widgets/WidgetStatus.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/RenderPipelineHelper.cs b/Packages/app.rive.rive-unity/Runtime/Components/RenderPipelineHelper.cs new file mode 100644 index 00000000..679cd48b --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/RenderPipelineHelper.cs @@ -0,0 +1,84 @@ +using Rive.Utils; +using UnityEngine; + + +namespace Rive.Components +{ + /// + /// This class is responsible for handling the rendering of Rive objects depending on the current Unity render pipeline. + /// + internal class RenderPipelineHelper + { + + private static IRenderPipelineHandler s_currentHandler; + + public static IRenderPipelineHandler CurrentHandler => s_currentHandler; + + /// + /// Checks if the handler reference is valid, accounting for Unity's object lifecycle (when using Unity as a Library) + /// This is necessary because s_currentHandler is typed as an interface, which bypasses + /// Unity's custom == operator that detects destroyed objects. + /// + private static bool IsHandlerValid => s_currentHandler is Object obj && obj != null; + + + /// + /// Gets or creates a render pipeline handler for the current render pipeline. + /// + /// The current render pipeline handler. + public static IRenderPipelineHandler GetOrCreateHandler() + { + if (!IsHandlerValid) + { + + s_currentHandler = null; + +#if RIVE_USING_URP + s_currentHandler = SpawnHandlerObject("[Rive] URP Handler"); +#elif RIVE_USING_HDRP + s_currentHandler = SpawnHandlerObject("[Rive] HDRP Handler"); +#else + s_currentHandler = SpawnHandlerObject("[Rive] BuiltInRP Handler"); + +#endif + + } + + if (!IsHandlerValid) + { + DebugLogger.Instance.LogError("No render pipeline handler found."); + } + + return s_currentHandler; + } + + /// + /// Spawns a handler object of the specified type. + /// + /// + /// + /// + internal static T SpawnHandlerObject(string name) where T : MonoBehaviour + { + GameObject handlerObject = new GameObject(name); + Object.DontDestroyOnLoad(handlerObject); + var handler = handlerObject.AddComponent(); + return handler; + } + + + +#if UNITY_EDITOR + // We need to account for Domain Reload in the editor being disabled, so we reset the current handler when the domain reloads. + // If we don't do this, Rive Widgets won't render after domain reload and will show a white screen instead. + // More info: https://docs.unity3d.com/6000.0/Documentation/Manual/domain-reloading.html + // Note: This does NOT help with Unity as a Library reloads. IsHandlerValid handles that case. + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] + static void Init() + { + s_currentHandler = null; + } +#endif + + } +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Runtime/Components/RenderPipelineHelper.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/RenderPipelineHelper.cs.meta new file mode 100644 index 00000000..35ac2afd --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/RenderPipelineHelper.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: d220c9d0600014ce481cc4928ed1f9cf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/RenderPipelineHelper.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Rive.Runtime.Components.asmdef b/Packages/app.rive.rive-unity/Runtime/Components/Rive.Runtime.Components.asmdef new file mode 100644 index 00000000..3e85e6cb --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Rive.Runtime.Components.asmdef @@ -0,0 +1,38 @@ +{ + "name": "Rive.Runtime.Components", + "rootNamespace": "Rive.Components", + "references": [ + "GUID:15fc0a57446b3144c949da3e2b9737a9", + "GUID:df380645f10b7bc4b97d4f5eb6303d95", + "GUID:75469ad4d38634e559750d17036d5f7c", + "GUID:457756d89b35d2941b3e7b37b4ece6f1", + "GUID:0a82aeb665886483c867b7d137563619" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [ + "RIVE_USING_UGUI" + ], + "versionDefines": [ + { + "name": "com.unity.render-pipelines.universal", + "expression": "12.1.15", + "define": "RIVE_USING_URP" + }, + { + "name": "com.unity.render-pipelines.high-definition", + "expression": "12.1.15", + "define": "RIVE_USING_HDRP" + }, + { + "name": "com.unity.ugui", + "expression": "1.0.0", + "define": "RIVE_USING_UGUI" + } + ], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Rive.Runtime.Components.asmdef.meta b/Packages/app.rive.rive-unity/Runtime/Components/Rive.Runtime.Components.asmdef.meta new file mode 100644 index 00000000..95618c9a --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Rive.Runtime.Components.asmdef.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 4d624505c28284c90a482e4d6ec34ada +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Rive.Runtime.Components.asmdef + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/SerializedDictionary.cs b/Packages/app.rive.rive-unity/Runtime/Components/SerializedDictionary.cs new file mode 100644 index 00000000..aa5f02e5 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/SerializedDictionary.cs @@ -0,0 +1,43 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace Rive.Utils +{ + [System.Serializable] + internal class SerializedDictionary : Dictionary, ISerializationCallbackReceiver + { + [SerializeField] + private List m_keys = new List(); + + [SerializeField] + private List m_values = new List(); + + + public void OnBeforeSerialize() + { + m_keys.Clear(); + m_values.Clear(); + foreach (KeyValuePair pair in this) + { + m_keys.Add(pair.Key); + m_values.Add(pair.Value); + } + } + + public void OnAfterDeserialize() + { + this.Clear(); + + if (m_keys.Count != m_values.Count) + throw new System.Exception($"Key count ({m_keys.Count}) does not match value count ({m_values.Count}). Verify that both key and value types can be serialized."); + + for (int i = 0; i < m_keys.Count; i++) + this.Add(m_keys[i], m_values[i]); + } + +#if UNITY_EDITOR + internal static string BindingPath_Keys => nameof(m_keys); + internal static string BindingPath_Values => nameof(m_values); +#endif + } +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Runtime/Components/SerializedDictionary.cs.meta b/Packages/app.rive.rive-unity/Runtime/Components/SerializedDictionary.cs.meta new file mode 100644 index 00000000..45826b6c --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/SerializedDictionary.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 1b4cdf0a209ed4291b8f3ab1f1cf608e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/SerializedDictionary.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Shaders.meta b/Packages/app.rive.rive-unity/Runtime/Components/Shaders.meta new file mode 100644 index 00000000..3750933d --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Shaders.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b08baea7d81994a079ee05c520411f86 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Shaders/SubGraphs.meta b/Packages/app.rive.rive-unity/Runtime/Components/Shaders/SubGraphs.meta new file mode 100644 index 00000000..075c8e92 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Shaders/SubGraphs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5703e47da1dcf4bac9f5256170f6cc9c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Shaders/SubGraphs/SRGBDecode_Auto.shadersubgraph b/Packages/app.rive.rive-unity/Runtime/Components/Shaders/SubGraphs/SRGBDecode_Auto.shadersubgraph new file mode 100644 index 00000000..5335f1fb --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Shaders/SubGraphs/SRGBDecode_Auto.shadersubgraph @@ -0,0 +1,1782 @@ +{ + "m_SGVersion": 3, + "m_Type": "UnityEditor.ShaderGraph.GraphData", + "m_ObjectId": "eb88a84afc214c0fa1d68263741d611b", + "m_Properties": [ + { + "m_Id": "295e96d016b14e9290fd81de528ca096" + }, + { + "m_Id": "59a055fdbc4c477cbc764edafe6f786f" + } + ], + "m_Keywords": [], + "m_Dropdowns": [], + "m_CategoryData": [ + { + "m_Id": "49596b91ed64443c8035c7fc265d0880" + } + ], + "m_Nodes": [ + { + "m_Id": "d8c8767d04e04428938c836ebfecee85" + }, + { + "m_Id": "43d49b32d0e946949d413b8e0a97e77f" + }, + { + "m_Id": "e448003cc3364f6d852d70ba1b1f3bf3" + }, + { + "m_Id": "6f1cc8c3428b441b9a910c604a286f10" + }, + { + "m_Id": "bd59a8f7dd8b4936bf21b041a9aa0c31" + }, + { + "m_Id": "e9124f6db5aa42419684d4e4589070ea" + }, + { + "m_Id": "677beffccf0547e5ad62e57e6a7bce25" + }, + { + "m_Id": "5c81447017ab4256ad3a7a4793dd7725" + }, + { + "m_Id": "91468eda37c34d8798f4c5687fc2dd18" + }, + { + "m_Id": "632f266def044498b9a87bc416085cd8" + }, + { + "m_Id": "533cbe6502ff40d6bb0efb3ffca0b2e0" + }, + { + "m_Id": "8b4383e8f5d8469ab3a01595a44e31b0" + } + ], + "m_GroupDatas": [], + "m_StickyNoteDatas": [], + "m_Edges": [ + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "43d49b32d0e946949d413b8e0a97e77f" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "533cbe6502ff40d6bb0efb3ffca0b2e0" + }, + "m_SlotId": 0 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "533cbe6502ff40d6bb0efb3ffca0b2e0" + }, + "m_SlotId": 1 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "6f1cc8c3428b441b9a910c604a286f10" + }, + "m_SlotId": 0 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "5c81447017ab4256ad3a7a4793dd7725" + }, + "m_SlotId": 1 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "677beffccf0547e5ad62e57e6a7bce25" + }, + "m_SlotId": 0 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "5c81447017ab4256ad3a7a4793dd7725" + }, + "m_SlotId": 2 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "677beffccf0547e5ad62e57e6a7bce25" + }, + "m_SlotId": 1 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "5c81447017ab4256ad3a7a4793dd7725" + }, + "m_SlotId": 3 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "677beffccf0547e5ad62e57e6a7bce25" + }, + "m_SlotId": 2 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "632f266def044498b9a87bc416085cd8" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "91468eda37c34d8798f4c5687fc2dd18" + }, + "m_SlotId": 0 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "677beffccf0547e5ad62e57e6a7bce25" + }, + "m_SlotId": 5 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "8b4383e8f5d8469ab3a01595a44e31b0" + }, + "m_SlotId": 0 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "6f1cc8c3428b441b9a910c604a286f10" + }, + "m_SlotId": 1 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "bd59a8f7dd8b4936bf21b041a9aa0c31" + }, + "m_SlotId": 0 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "6f1cc8c3428b441b9a910c604a286f10" + }, + "m_SlotId": 2 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "bd59a8f7dd8b4936bf21b041a9aa0c31" + }, + "m_SlotId": 1 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "6f1cc8c3428b441b9a910c604a286f10" + }, + "m_SlotId": 3 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "bd59a8f7dd8b4936bf21b041a9aa0c31" + }, + "m_SlotId": 2 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "6f1cc8c3428b441b9a910c604a286f10" + }, + "m_SlotId": 4 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "677beffccf0547e5ad62e57e6a7bce25" + }, + "m_SlotId": 3 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "6f1cc8c3428b441b9a910c604a286f10" + }, + "m_SlotId": 4 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "8b4383e8f5d8469ab3a01595a44e31b0" + }, + "m_SlotId": 1 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "8b4383e8f5d8469ab3a01595a44e31b0" + }, + "m_SlotId": 2 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "d8c8767d04e04428938c836ebfecee85" + }, + "m_SlotId": 1 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "91468eda37c34d8798f4c5687fc2dd18" + }, + "m_SlotId": 1 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "e9124f6db5aa42419684d4e4589070ea" + }, + "m_SlotId": 0 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "bd59a8f7dd8b4936bf21b041a9aa0c31" + }, + "m_SlotId": 5 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "e448003cc3364f6d852d70ba1b1f3bf3" + }, + "m_SlotId": 0 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "bd59a8f7dd8b4936bf21b041a9aa0c31" + }, + "m_SlotId": 5 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "e9124f6db5aa42419684d4e4589070ea" + }, + "m_SlotId": 2 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "e448003cc3364f6d852d70ba1b1f3bf3" + }, + "m_SlotId": 1 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "e9124f6db5aa42419684d4e4589070ea" + }, + "m_SlotId": 1 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "e9124f6db5aa42419684d4e4589070ea" + }, + "m_SlotId": 3 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "5c81447017ab4256ad3a7a4793dd7725" + }, + "m_SlotId": 0 + } + } + ], + "m_VertexContext": { + "m_Position": { + "x": 0.0, + "y": 0.0 + }, + "m_Blocks": [] + }, + "m_FragmentContext": { + "m_Position": { + "x": 0.0, + "y": 0.0 + }, + "m_Blocks": [] + }, + "m_PreviewData": { + "serializedMesh": { + "m_SerializedMesh": "{\"mesh\":{\"instanceID\":0}}", + "m_Guid": "" + }, + "preventRotation": false + }, + "m_Path": "Sub Graphs", + "m_GraphPrecision": 1, + "m_PreviewMode": 2, + "m_OutputNode": { + "m_Id": "d8c8767d04e04428938c836ebfecee85" + }, + "m_SubDatas": [], + "m_ActiveTargets": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "04ac3f954860444b865878cdad1a4d11", + "m_Id": 4, + "m_DisplayName": "A", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "A", + "m_StageCapability": 3, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.DynamicVectorMaterialSlot", + "m_ObjectId": "0a8fe9da917d4fde9dea2e25ecfa323f", + "m_Id": 3, + "m_DisplayName": "Out", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out", + "m_StageCapability": 3, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector3MaterialSlot", + "m_ObjectId": "125e245f40c8421ba8835759c4fe7320", + "m_Id": 5, + "m_DisplayName": "RGB", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "RGB", + "m_StageCapability": 3, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "141dc913c18e4169aa2ecc0303082fbe", + "m_Id": 2, + "m_DisplayName": "G", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "G", + "m_StageCapability": 3, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector2MaterialSlot", + "m_ObjectId": "16ee05169b6f41009b749221280a570c", + "m_Id": 6, + "m_DisplayName": "RG", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "RG", + "m_StageCapability": 3, + "m_Value": { + "x": 0.0, + "y": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "16fb5b3a9e9d419b8bef70b16eac7433", + "m_Id": 4, + "m_DisplayName": "A", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "A", + "m_StageCapability": 3, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "1780727428214f2f90b7305964f511a1", + "m_Id": 2, + "m_DisplayName": "G", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "G", + "m_StageCapability": 3, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.DynamicValueMaterialSlot", + "m_ObjectId": "1c3c50e0f60a426c8b4531f18dd6cc95", + "m_Id": 2, + "m_DisplayName": "Out", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out", + "m_StageCapability": 3, + "m_Value": { + "e00": 0.0, + "e01": 0.0, + "e02": 0.0, + "e03": 0.0, + "e10": 0.0, + "e11": 0.0, + "e12": 0.0, + "e13": 0.0, + "e20": 0.0, + "e21": 0.0, + "e22": 0.0, + "e23": 0.0, + "e30": 0.0, + "e31": 0.0, + "e32": 0.0, + "e33": 0.0 + }, + "m_DefaultValue": { + "e00": 1.0, + "e01": 0.0, + "e02": 0.0, + "e03": 0.0, + "e10": 0.0, + "e11": 1.0, + "e12": 0.0, + "e13": 0.0, + "e20": 0.0, + "e21": 0.0, + "e22": 1.0, + "e23": 0.0, + "e30": 0.0, + "e31": 0.0, + "e32": 0.0, + "e33": 1.0 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "235e61712dfa46d7828cb0d21236e80e", + "m_Id": 1, + "m_DisplayName": "R", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "R", + "m_StageCapability": 3, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 1, + "m_Type": "UnityEditor.ShaderGraph.Internal.Vector4ShaderProperty", + "m_ObjectId": "295e96d016b14e9290fd81de528ca096", + "m_Guid": { + "m_GuidSerialized": "a7292d5e-7e6d-42f7-9e9c-223d6cad8047" + }, + "m_Name": "ColorIn", + "m_DefaultRefNameVersion": 1, + "m_RefNameGeneratedByDisplayName": "ColorIn", + "m_DefaultReferenceName": "_ColorIn", + "m_OverrideReferenceName": "", + "m_GeneratePropertyBlock": true, + "m_UseCustomSlotLabel": false, + "m_CustomSlotLabel": "", + "m_DismissedVersion": 0, + "m_Precision": 0, + "overrideHLSLDeclaration": false, + "hlslDeclarationOverride": 0, + "m_Hidden": false, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BooleanMaterialSlot", + "m_ObjectId": "2cd34ab23c154a4680c51ece76953b7e", + "m_Id": 0, + "m_DisplayName": "Predicate", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Predicate", + "m_StageCapability": 3, + "m_Value": false, + "m_DefaultValue": false +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "2eff41287d124212b0729f362e2dde0d", + "m_Id": 2, + "m_DisplayName": "B", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "B", + "m_StageCapability": 3, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector4MaterialSlot", + "m_ObjectId": "3703d4c4568f4b47afb4b1bde80e12cd", + "m_Id": 0, + "m_DisplayName": "PremulColor", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "PremulColor", + "m_StageCapability": 3, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector4MaterialSlot", + "m_ObjectId": "3907a874d6a344e287e7fc9179e8f62e", + "m_Id": 1, + "m_DisplayName": "StraightColor", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "StraightColor", + "m_StageCapability": 3, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector4MaterialSlot", + "m_ObjectId": "3c5699d1fc4344129975458a40be1fb2", + "m_Id": 4, + "m_DisplayName": "RGBA", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "RGBA", + "m_StageCapability": 3, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.PropertyNode", + "m_ObjectId": "43d49b32d0e946949d413b8e0a97e77f", + "m_Group": { + "m_Id": "" + }, + "m_Name": "Property", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -723.9999389648438, + "y": -961.9999389648438, + "width": 114.5, + "height": 34.00006103515625 + } + }, + "m_Slots": [ + { + "m_Id": "f2cf0350f5054a40b09a7a566025e999" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_Property": { + "m_Id": "295e96d016b14e9290fd81de528ca096" + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.CategoryData", + "m_ObjectId": "49596b91ed64443c8035c7fc265d0880", + "m_Name": "", + "m_ChildObjectList": [ + { + "m_Id": "295e96d016b14e9290fd81de528ca096" + }, + { + "m_Id": "59a055fdbc4c477cbc764edafe6f786f" + } + ] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "4b558ad07956457ea80b0adc5d6f0188", + "m_Id": 2, + "m_DisplayName": "B", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "B", + "m_StageCapability": 3, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 1, + "m_Type": "UnityEditor.ShaderGraph.CustomFunctionNode", + "m_ObjectId": "533cbe6502ff40d6bb0efb3ffca0b2e0", + "m_Group": { + "m_Id": "" + }, + "m_Name": "RiveUnpremultiply (Custom Function)", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -521.5000610351563, + "y": -857.5, + "width": 258.0, + "height": 278.00006103515627 + } + }, + "m_Slots": [ + { + "m_Id": "3703d4c4568f4b47afb4b1bde80e12cd" + }, + { + "m_Id": "3907a874d6a344e287e7fc9179e8f62e" + } + ], + "synonyms": [ + "code", + "HLSL" + ], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SourceType": 1, + "m_FunctionName": "RiveUnpremultiply", + "m_FunctionSource": "", + "m_FunctionBody": "float3 rgb;\nif (PremulColor.a > 0.0)\n rgb = saturate(PremulColor.rgb / PremulColor.a);\nelse\n rgb = float3(0, 0, 0);\nStraightColor = float4(rgb, PremulColor.a);" +} + +{ + "m_SGVersion": 1, + "m_Type": "UnityEditor.ShaderGraph.Internal.Vector1ShaderProperty", + "m_ObjectId": "59a055fdbc4c477cbc764edafe6f786f", + "m_Guid": { + "m_GuidSerialized": "cb2852af-b565-4de2-964c-573df4bce630" + }, + "m_Name": "DecodeMode", + "m_DefaultRefNameVersion": 1, + "m_RefNameGeneratedByDisplayName": "DecodeMode", + "m_DefaultReferenceName": "_DecodeMode", + "m_OverrideReferenceName": "", + "m_GeneratePropertyBlock": true, + "m_UseCustomSlotLabel": false, + "m_CustomSlotLabel": "", + "m_DismissedVersion": 0, + "m_Precision": 0, + "overrideHLSLDeclaration": false, + "hlslDeclarationOverride": 2, + "m_Hidden": false, + "m_Value": -1.0, + "m_FloatType": 0, + "m_RangeValues": { + "x": 0.0, + "y": 1.0 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector3MaterialSlot", + "m_ObjectId": "5a73031683fe445bad9cb59da7292dd5", + "m_Id": 1, + "m_DisplayName": "Out", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out", + "m_StageCapability": 3, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.SplitNode", + "m_ObjectId": "5c81447017ab4256ad3a7a4793dd7725", + "m_Group": { + "m_Id": "" + }, + "m_Name": "Split", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 644.0, + "y": -609.5, + "width": 119.0, + "height": 149.0 + } + }, + "m_Slots": [ + { + "m_Id": "a46ba1ebd27b4e4aa25e948a08339b12" + }, + { + "m_Id": "da6aed685460449587e50ec32767f0d7" + }, + { + "m_Id": "1780727428214f2f90b7305964f511a1" + }, + { + "m_Id": "b50f9b3a08574d7184ec40d554b5105e" + }, + { + "m_Id": "04ac3f954860444b865878cdad1a4d11" + } + ], + "synonyms": [ + "separate" + ], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "5ee7fb17b1e34d4989e7695d0deb57a9", + "m_Id": 0, + "m_DisplayName": "R", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "R", + "m_StageCapability": 3, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector3MaterialSlot", + "m_ObjectId": "5f573c4cc0984586a5a0d709187d09c8", + "m_Id": 5, + "m_DisplayName": "RGB", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "RGB", + "m_StageCapability": 3, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.PropertyNode", + "m_ObjectId": "632f266def044498b9a87bc416085cd8", + "m_Group": { + "m_Id": "" + }, + "m_Name": "Property", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -308.0, + "y": -460.50006103515627, + "width": 145.0, + "height": 33.99993896484375 + } + }, + "m_Slots": [ + { + "m_Id": "98737829801745fa8e84d62ce24b791d" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_Property": { + "m_Id": "59a055fdbc4c477cbc764edafe6f786f" + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.CombineNode", + "m_ObjectId": "677beffccf0547e5ad62e57e6a7bce25", + "m_Group": { + "m_Id": "" + }, + "m_Name": "Combine", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 895.9999389648438, + "y": -857.5, + "width": 208.00018310546876, + "height": 350.00006103515627 + } + }, + "m_Slots": [ + { + "m_Id": "5ee7fb17b1e34d4989e7695d0deb57a9" + }, + { + "m_Id": "99d7018de4cb40dd8a3e3d8596e2ebb5" + }, + { + "m_Id": "2eff41287d124212b0729f362e2dde0d" + }, + { + "m_Id": "d4a88f44d94f42ef8eab3082b676dee0" + }, + { + "m_Id": "7ed391068a9f4ca98630274e6e914897" + }, + { + "m_Id": "125e245f40c8421ba8835759c4fe7320" + }, + { + "m_Id": "16ee05169b6f41009b749221280a570c" + } + ], + "synonyms": [ + "append" + ], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "693aaea30d11433a856b593fcb154cfa", + "m_Id": 3, + "m_DisplayName": "B", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "B", + "m_StageCapability": 3, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.DynamicVectorMaterialSlot", + "m_ObjectId": "69530a7be86f4289b97d8a2ee8581436", + "m_Id": 1, + "m_DisplayName": "True", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "True", + "m_StageCapability": 3, + "m_Value": { + "x": 1.0, + "y": 1.0, + "z": 1.0, + "w": 1.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "69d87020a4f54f5681496a5d8d0935e7", + "m_Id": 1, + "m_DisplayName": "G", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "G", + "m_StageCapability": 3, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.SplitNode", + "m_ObjectId": "6f1cc8c3428b441b9a910c604a286f10", + "m_Group": { + "m_Id": "" + }, + "m_Name": "Split", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -235.5, + "y": -1130.4998779296875, + "width": 119.0, + "height": 148.99993896484376 + } + }, + "m_Slots": [ + { + "m_Id": "88b9cd298dcf446cadcba9ad2afb23d6" + }, + { + "m_Id": "235e61712dfa46d7828cb0d21236e80e" + }, + { + "m_Id": "141dc913c18e4169aa2ecc0303082fbe" + }, + { + "m_Id": "693aaea30d11433a856b593fcb154cfa" + }, + { + "m_Id": "16fb5b3a9e9d419b8bef70b16eac7433" + } + ], + "synonyms": [ + "separate" + ], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector4MaterialSlot", + "m_ObjectId": "7ed391068a9f4ca98630274e6e914897", + "m_Id": 4, + "m_DisplayName": "RGBA", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "RGBA", + "m_StageCapability": 3, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.DynamicVectorMaterialSlot", + "m_ObjectId": "88b9cd298dcf446cadcba9ad2afb23d6", + "m_Id": 0, + "m_DisplayName": "In", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "In", + "m_StageCapability": 3, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector4MaterialSlot", + "m_ObjectId": "8914a6582f264ad8b7cb557063eafb70", + "m_Id": 1, + "m_DisplayName": "Out_Vector4", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "OutVector4", + "m_StageCapability": 3, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector2MaterialSlot", + "m_ObjectId": "89d00dfe012145da9bbe98c35bc58bd8", + "m_Id": 6, + "m_DisplayName": "RG", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "RG", + "m_StageCapability": 3, + "m_Value": { + "x": 0.0, + "y": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.MultiplyNode", + "m_ObjectId": "8b4383e8f5d8469ab3a01595a44e31b0", + "m_Group": { + "m_Id": "" + }, + "m_Name": "Multiply", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 1284.0, + "y": -833.5, + "width": 208.0, + "height": 301.99993896484377 + } + }, + "m_Slots": [ + { + "m_Id": "e606fc2619824b7abe84e451d90f6076" + }, + { + "m_Id": "b4fc9de280ad457d8f84ef3dd774436e" + }, + { + "m_Id": "1c3c50e0f60a426c8b4531f18dd6cc95" + } + ], + "synonyms": [ + "multiplication", + "times", + "x" + ], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + } +} + +{ + "m_SGVersion": 1, + "m_Type": "UnityEditor.ShaderGraph.CustomFunctionNode", + "m_ObjectId": "91468eda37c34d8798f4c5687fc2dd18", + "m_Group": { + "m_Id": "" + }, + "m_Name": "RiveShouldDecode_bool (Custom Function)", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -12.499969482421875, + "y": -482.00006103515627, + "width": 292.0, + "height": 278.00006103515627 + } + }, + "m_Slots": [ + { + "m_Id": "e841b5793af64b85ac48448432307f6b" + }, + { + "m_Id": "a2b3687558c049bb8088440c1e58e63e" + } + ], + "synonyms": [ + "code", + "HLSL" + ], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SourceType": 1, + "m_FunctionName": "RiveShouldDecode_bool", + "m_FunctionSource": "", + "m_FunctionBody": "// UNITY_COLORSPACE_GAMMA is defined in Gamma projects\n bool isLinearProject = false;\n #if !defined(UNITY_COLORSPACE_GAMMA)\n isLinearProject = true;\n #endif\n\n // DecodeMode: -1 = Auto, 0 = Force Off, 1 = Force On\n if (DecodeMode < -0.5)\n ShouldDecode = isLinearProject;\n else if (DecodeMode < 0.5)\n ShouldDecode = false;\n else\n ShouldDecode = true;\n" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "98737829801745fa8e84d62ce24b791d", + "m_Id": 0, + "m_DisplayName": "DecodeMode", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out", + "m_StageCapability": 3, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "99d7018de4cb40dd8a3e3d8596e2ebb5", + "m_Id": 1, + "m_DisplayName": "G", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "G", + "m_StageCapability": 3, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BooleanMaterialSlot", + "m_ObjectId": "a2b3687558c049bb8088440c1e58e63e", + "m_Id": 1, + "m_DisplayName": "ShouldDecode", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "ShouldDecode", + "m_StageCapability": 3, + "m_Value": false, + "m_DefaultValue": false +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.DynamicVectorMaterialSlot", + "m_ObjectId": "a46ba1ebd27b4e4aa25e948a08339b12", + "m_Id": 0, + "m_DisplayName": "In", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "In", + "m_StageCapability": 3, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector3MaterialSlot", + "m_ObjectId": "a869ce0ef75044e2a059b4b50e90a09a", + "m_Id": 0, + "m_DisplayName": "In", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "In", + "m_StageCapability": 3, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "afed049c2861446ab19716616aad3b35", + "m_Id": 0, + "m_DisplayName": "R", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "R", + "m_StageCapability": 3, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.DynamicValueMaterialSlot", + "m_ObjectId": "b4fc9de280ad457d8f84ef3dd774436e", + "m_Id": 1, + "m_DisplayName": "B", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "B", + "m_StageCapability": 3, + "m_Value": { + "e00": 2.0, + "e01": 2.0, + "e02": 2.0, + "e03": 2.0, + "e10": 2.0, + "e11": 2.0, + "e12": 2.0, + "e13": 2.0, + "e20": 2.0, + "e21": 2.0, + "e22": 2.0, + "e23": 2.0, + "e30": 2.0, + "e31": 2.0, + "e32": 2.0, + "e33": 2.0 + }, + "m_DefaultValue": { + "e00": 1.0, + "e01": 0.0, + "e02": 0.0, + "e03": 0.0, + "e10": 0.0, + "e11": 1.0, + "e12": 0.0, + "e13": 0.0, + "e20": 0.0, + "e21": 0.0, + "e22": 1.0, + "e23": 0.0, + "e30": 0.0, + "e31": 0.0, + "e32": 0.0, + "e33": 1.0 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "b50f9b3a08574d7184ec40d554b5105e", + "m_Id": 3, + "m_DisplayName": "B", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "B", + "m_StageCapability": 3, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.CombineNode", + "m_ObjectId": "bd59a8f7dd8b4936bf21b041a9aa0c31", + "m_Group": { + "m_Id": "" + }, + "m_Name": "Combine", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -52.0, + "y": -1032.5001220703125, + "width": 207.9998779296875, + "height": 350.0001220703125 + } + }, + "m_Slots": [ + { + "m_Id": "afed049c2861446ab19716616aad3b35" + }, + { + "m_Id": "69d87020a4f54f5681496a5d8d0935e7" + }, + { + "m_Id": "4b558ad07956457ea80b0adc5d6f0188" + }, + { + "m_Id": "bf942619f69241729398bf7a76db544b" + }, + { + "m_Id": "3c5699d1fc4344129975458a40be1fb2" + }, + { + "m_Id": "5f573c4cc0984586a5a0d709187d09c8" + }, + { + "m_Id": "89d00dfe012145da9bbe98c35bc58bd8" + } + ], + "synonyms": [ + "append" + ], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "bf942619f69241729398bf7a76db544b", + "m_Id": 3, + "m_DisplayName": "A", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "A", + "m_StageCapability": 3, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "d4a88f44d94f42ef8eab3082b676dee0", + "m_Id": 3, + "m_DisplayName": "A", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "A", + "m_StageCapability": 3, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.SubGraphOutputNode", + "m_ObjectId": "d8c8767d04e04428938c836ebfecee85", + "m_Group": { + "m_Id": "" + }, + "m_Name": "Output", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 1492.0, + "y": -1042.0, + "width": 120.5, + "height": 77.0 + } + }, + "m_Slots": [ + { + "m_Id": "8914a6582f264ad8b7cb557063eafb70" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "IsFirstSlotValid": true +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "da6aed685460449587e50ec32767f0d7", + "m_Id": 1, + "m_DisplayName": "R", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "R", + "m_StageCapability": 3, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.ColorspaceConversionNode", + "m_ObjectId": "e448003cc3364f6d852d70ba1b1f3bf3", + "m_Group": { + "m_Id": "" + }, + "m_Name": "Colorspace Conversion", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 279.4998779296875, + "y": -1032.4998779296875, + "width": 211.0001220703125, + "height": 130.4998779296875 + } + }, + "m_Slots": [ + { + "m_Id": "a869ce0ef75044e2a059b4b50e90a09a" + }, + { + "m_Id": "5a73031683fe445bad9cb59da7292dd5" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": false, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_Conversion": { + "from": 0, + "to": 1 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.DynamicValueMaterialSlot", + "m_ObjectId": "e606fc2619824b7abe84e451d90f6076", + "m_Id": 0, + "m_DisplayName": "A", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "A", + "m_StageCapability": 3, + "m_Value": { + "e00": 0.0, + "e01": 0.0, + "e02": 0.0, + "e03": 0.0, + "e10": 0.0, + "e11": 0.0, + "e12": 0.0, + "e13": 0.0, + "e20": 0.0, + "e21": 0.0, + "e22": 0.0, + "e23": 0.0, + "e30": 0.0, + "e31": 0.0, + "e32": 0.0, + "e33": 0.0 + }, + "m_DefaultValue": { + "e00": 1.0, + "e01": 0.0, + "e02": 0.0, + "e03": 0.0, + "e10": 0.0, + "e11": 1.0, + "e12": 0.0, + "e13": 0.0, + "e20": 0.0, + "e21": 0.0, + "e22": 1.0, + "e23": 0.0, + "e30": 0.0, + "e31": 0.0, + "e32": 0.0, + "e33": 1.0 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "e841b5793af64b85ac48448432307f6b", + "m_Id": 0, + "m_DisplayName": "DecodeMode", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "DecodeMode", + "m_StageCapability": 3, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BranchNode", + "m_ObjectId": "e9124f6db5aa42419684d4e4589070ea", + "m_Group": { + "m_Id": "" + }, + "m_Name": "Branch", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 385.0, + "y": -682.4999389648438, + "width": 208.0, + "height": 326.0 + } + }, + "m_Slots": [ + { + "m_Id": "2cd34ab23c154a4680c51ece76953b7e" + }, + { + "m_Id": "69530a7be86f4289b97d8a2ee8581436" + }, + { + "m_Id": "fdedada47da74942bf705a755b9b430f" + }, + { + "m_Id": "0a8fe9da917d4fde9dea2e25ecfa323f" + } + ], + "synonyms": [ + "switch", + "if", + "else" + ], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector4MaterialSlot", + "m_ObjectId": "f2cf0350f5054a40b09a7a566025e999", + "m_Id": 0, + "m_DisplayName": "ColorIn", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out", + "m_StageCapability": 3, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.DynamicVectorMaterialSlot", + "m_ObjectId": "fdedada47da74942bf705a755b9b430f", + "m_Id": 2, + "m_DisplayName": "False", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "False", + "m_StageCapability": 3, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + } +} + diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Shaders/SubGraphs/SRGBDecode_Auto.shadersubgraph.meta b/Packages/app.rive.rive-unity/Runtime/Components/Shaders/SubGraphs/SRGBDecode_Auto.shadersubgraph.meta new file mode 100644 index 00000000..41d03a43 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Shaders/SubGraphs/SRGBDecode_Auto.shadersubgraph.meta @@ -0,0 +1,17 @@ +fileFormatVersion: 2 +guid: a2b967a2d741d41f0892c3328200244a +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: 60072b568d64c40a485e0fc55012dc9f, type: 3} +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Shaders/SubGraphs/SRGBDecode_Auto.shadersubgraph + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Shaders/SubGraphs/SampleEmission.shadersubgraph b/Packages/app.rive.rive-unity/Runtime/Components/Shaders/SubGraphs/SampleEmission.shadersubgraph new file mode 100644 index 00000000..f6432ac3 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Shaders/SubGraphs/SampleEmission.shadersubgraph @@ -0,0 +1,760 @@ +{ + "m_SGVersion": 3, + "m_Type": "UnityEditor.ShaderGraph.GraphData", + "m_ObjectId": "6b619450691d4acd8bb2e2ede69d3b11", + "m_Properties": [ + { + "m_Id": "e41d6edd101b49f38ddd3fe98cbe839d" + }, + { + "m_Id": "ec0ba007f0bc41e6b7507ffab93a4e81" + } + ], + "m_Keywords": [], + "m_Dropdowns": [], + "m_CategoryData": [ + { + "m_Id": "d1ede69802af4f6cad6f3067ef22d601" + } + ], + "m_Nodes": [ + { + "m_Id": "f11c51012e9e49c48347c1ed01688305" + }, + { + "m_Id": "c3c7f2aaaa834aeaaac17e8f6edbf4ee" + }, + { + "m_Id": "916e8be24dd940b9a815617014fea622" + }, + { + "m_Id": "fe5f2e41089241ddb9665cdfded52ead" + }, + { + "m_Id": "a6ca5138a21040c88fbbb604dacfbb52" + } + ], + "m_GroupDatas": [ + { + "m_Id": "31a187406d544c71addcb5f2ec60f0dd" + } + ], + "m_StickyNoteDatas": [], + "m_Edges": [ + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "916e8be24dd940b9a815617014fea622" + }, + "m_SlotId": 2 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "f11c51012e9e49c48347c1ed01688305" + }, + "m_SlotId": 1 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "a6ca5138a21040c88fbbb604dacfbb52" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "916e8be24dd940b9a815617014fea622" + }, + "m_SlotId": 0 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "c3c7f2aaaa834aeaaac17e8f6edbf4ee" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "916e8be24dd940b9a815617014fea622" + }, + "m_SlotId": 1 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "fe5f2e41089241ddb9665cdfded52ead" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "c3c7f2aaaa834aeaaac17e8f6edbf4ee" + }, + "m_SlotId": 1 + } + } + ], + "m_VertexContext": { + "m_Position": { + "x": 0.0, + "y": 0.0 + }, + "m_Blocks": [] + }, + "m_FragmentContext": { + "m_Position": { + "x": 0.0, + "y": 0.0 + }, + "m_Blocks": [] + }, + "m_PreviewData": { + "serializedMesh": { + "m_SerializedMesh": "{\"mesh\":{\"instanceID\":0}}", + "m_Guid": "" + }, + "preventRotation": false + }, + "m_Path": "Sub Graphs", + "m_GraphPrecision": 1, + "m_PreviewMode": 2, + "m_OutputNode": { + "m_Id": "f11c51012e9e49c48347c1ed01688305" + }, + "m_ActiveTargets": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector4MaterialSlot", + "m_ObjectId": "127ce91b3943483c9de5b1070447418b", + "m_Id": 0, + "m_DisplayName": "EmissionColor", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out", + "m_StageCapability": 3, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector4MaterialSlot", + "m_ObjectId": "2db0a2a145da4be2836e69c5a0108f7c", + "m_Id": 0, + "m_DisplayName": "RGBA", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "RGBA", + "m_StageCapability": 2, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.UVMaterialSlot", + "m_ObjectId": "30051f629c374179a6fd13d9fb476e26", + "m_Id": 2, + "m_DisplayName": "UV", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "UV", + "m_StageCapability": 3, + "m_Value": { + "x": 0.0, + "y": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0 + }, + "m_Labels": [], + "m_Channel": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.GroupData", + "m_ObjectId": "31a187406d544c71addcb5f2ec60f0dd", + "m_Title": "Emission", + "m_Position": { + "x": -509.9999694824219, + "y": -73.99996948242188 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Texture2DInputMaterialSlot", + "m_ObjectId": "43ec2b868c7f481eb85bf08eed225c8d", + "m_Id": 1, + "m_DisplayName": "Texture", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Texture", + "m_StageCapability": 3, + "m_BareResource": false, + "m_Texture": { + "m_SerializedTexture": "{\"texture\":{\"instanceID\":0}}", + "m_Guid": "" + }, + "m_DefaultType": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector4MaterialSlot", + "m_ObjectId": "82c0444a2bf14afc8b1e33e64a389ab2", + "m_Id": 1, + "m_DisplayName": "Out_Emission", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Out_Emission", + "m_StageCapability": 2, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.MultiplyNode", + "m_ObjectId": "916e8be24dd940b9a815617014fea622", + "m_Group": { + "m_Id": "31a187406d544c71addcb5f2ec60f0dd" + }, + "m_Name": "Multiply", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 143.49993896484376, + "y": 378.4999694824219, + "width": 208.0, + "height": 302.0000305175781 + } + }, + "m_Slots": [ + { + "m_Id": "cf892bd3a2a042fe9432dcb3df524adb" + }, + { + "m_Id": "edaa132f45f240b5ba2c0389af96056a" + }, + { + "m_Id": "ba915cd2e5d2465197c7177a4fd7d429" + } + ], + "synonyms": [ + "multiplication", + "times", + "x" + ], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "9ed77e23228848baafc8f9ae0cf6ae5c", + "m_Id": 7, + "m_DisplayName": "A", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "A", + "m_StageCapability": 2, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.PropertyNode", + "m_ObjectId": "a6ca5138a21040c88fbbb604dacfbb52", + "m_Group": { + "m_Id": "31a187406d544c71addcb5f2ec60f0dd" + }, + "m_Name": "Property", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -301.49993896484377, + "y": 236.49996948242188, + "width": 151.0, + "height": 34.00006103515625 + } + }, + "m_Slots": [ + { + "m_Id": "127ce91b3943483c9de5b1070447418b" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_Property": { + "m_Id": "e41d6edd101b49f38ddd3fe98cbe839d" + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Texture2DMaterialSlot", + "m_ObjectId": "a7afdcba447646dda5deb46af76ab0b2", + "m_Id": 0, + "m_DisplayName": "EmissionMap", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out", + "m_StageCapability": 3, + "m_BareResource": false +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.DynamicValueMaterialSlot", + "m_ObjectId": "ba915cd2e5d2465197c7177a4fd7d429", + "m_Id": 2, + "m_DisplayName": "Out", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out", + "m_StageCapability": 3, + "m_Value": { + "e00": 0.0, + "e01": 0.0, + "e02": 0.0, + "e03": 0.0, + "e10": 0.0, + "e11": 0.0, + "e12": 0.0, + "e13": 0.0, + "e20": 0.0, + "e21": 0.0, + "e22": 0.0, + "e23": 0.0, + "e30": 0.0, + "e31": 0.0, + "e32": 0.0, + "e33": 0.0 + }, + "m_DefaultValue": { + "e00": 1.0, + "e01": 0.0, + "e02": 0.0, + "e03": 0.0, + "e10": 0.0, + "e11": 1.0, + "e12": 0.0, + "e13": 0.0, + "e20": 0.0, + "e21": 0.0, + "e22": 1.0, + "e23": 0.0, + "e30": 0.0, + "e31": 0.0, + "e32": 0.0, + "e33": 1.0 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.SampleTexture2DNode", + "m_ObjectId": "c3c7f2aaaa834aeaaac17e8f6edbf4ee", + "m_Group": { + "m_Id": "31a187406d544c71addcb5f2ec60f0dd" + }, + "m_Name": "Sample Texture 2D", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -247.0, + "y": 324.4999694824219, + "width": 208.0, + "height": 434.0001525878906 + } + }, + "m_Slots": [ + { + "m_Id": "2db0a2a145da4be2836e69c5a0108f7c" + }, + { + "m_Id": "dccd4f03ee2a45b2ab70812f50729cc7" + }, + { + "m_Id": "c79bc36d84c443f5abc70525a05bdae0" + }, + { + "m_Id": "f69e71976a2d4ecea22a95028807dbeb" + }, + { + "m_Id": "9ed77e23228848baafc8f9ae0cf6ae5c" + }, + { + "m_Id": "43ec2b868c7f481eb85bf08eed225c8d" + }, + { + "m_Id": "30051f629c374179a6fd13d9fb476e26" + }, + { + "m_Id": "fbfb207e7d1149d980d5acae2b983f1c" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_TextureType": 0, + "m_NormalMapSpace": 0, + "m_EnableGlobalMipBias": true +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "c79bc36d84c443f5abc70525a05bdae0", + "m_Id": 5, + "m_DisplayName": "G", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "G", + "m_StageCapability": 2, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.DynamicValueMaterialSlot", + "m_ObjectId": "cf892bd3a2a042fe9432dcb3df524adb", + "m_Id": 0, + "m_DisplayName": "A", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "A", + "m_StageCapability": 3, + "m_Value": { + "e00": 0.0, + "e01": 0.0, + "e02": 0.0, + "e03": 0.0, + "e10": 0.0, + "e11": 0.0, + "e12": 0.0, + "e13": 0.0, + "e20": 0.0, + "e21": 0.0, + "e22": 0.0, + "e23": 0.0, + "e30": 0.0, + "e31": 0.0, + "e32": 0.0, + "e33": 0.0 + }, + "m_DefaultValue": { + "e00": 1.0, + "e01": 0.0, + "e02": 0.0, + "e03": 0.0, + "e10": 0.0, + "e11": 1.0, + "e12": 0.0, + "e13": 0.0, + "e20": 0.0, + "e21": 0.0, + "e22": 1.0, + "e23": 0.0, + "e30": 0.0, + "e31": 0.0, + "e32": 0.0, + "e33": 1.0 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.CategoryData", + "m_ObjectId": "d1ede69802af4f6cad6f3067ef22d601", + "m_Name": "", + "m_ChildObjectList": [ + { + "m_Id": "e41d6edd101b49f38ddd3fe98cbe839d" + }, + { + "m_Id": "ec0ba007f0bc41e6b7507ffab93a4e81" + } + ] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "dccd4f03ee2a45b2ab70812f50729cc7", + "m_Id": 4, + "m_DisplayName": "R", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "R", + "m_StageCapability": 2, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 3, + "m_Type": "UnityEditor.ShaderGraph.Internal.ColorShaderProperty", + "m_ObjectId": "e41d6edd101b49f38ddd3fe98cbe839d", + "m_Guid": { + "m_GuidSerialized": "417ee71e-80a1-414f-b809-df8c19e3743f" + }, + "m_Name": "EmissionColor", + "m_DefaultRefNameVersion": 1, + "m_RefNameGeneratedByDisplayName": "EmissionColor", + "m_DefaultReferenceName": "_EmissionColor", + "m_OverrideReferenceName": "", + "m_GeneratePropertyBlock": true, + "m_UseCustomSlotLabel": false, + "m_CustomSlotLabel": "", + "m_Precision": 0, + "overrideHLSLDeclaration": false, + "hlslDeclarationOverride": 0, + "m_Hidden": false, + "m_Value": { + "r": 0.0, + "g": 0.0, + "b": 0.0, + "a": 0.0 + }, + "isMainColor": false, + "m_ColorMode": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Internal.Texture2DShaderProperty", + "m_ObjectId": "ec0ba007f0bc41e6b7507ffab93a4e81", + "m_Guid": { + "m_GuidSerialized": "9fae8bf3-f659-4d48-8efb-5f8bda92ca8e" + }, + "m_Name": "EmissionMap", + "m_DefaultRefNameVersion": 1, + "m_RefNameGeneratedByDisplayName": "EmissionMap", + "m_DefaultReferenceName": "_EmissionMap", + "m_OverrideReferenceName": "", + "m_GeneratePropertyBlock": true, + "m_UseCustomSlotLabel": false, + "m_CustomSlotLabel": "", + "m_Precision": 0, + "overrideHLSLDeclaration": false, + "hlslDeclarationOverride": 0, + "m_Hidden": false, + "m_Value": { + "m_SerializedTexture": "{\"texture\":{\"instanceID\":0}}", + "m_Guid": "" + }, + "isMainTexture": false, + "useTilingAndOffset": false, + "m_Modifiable": true, + "m_DefaultType": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.DynamicValueMaterialSlot", + "m_ObjectId": "edaa132f45f240b5ba2c0389af96056a", + "m_Id": 1, + "m_DisplayName": "B", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "B", + "m_StageCapability": 3, + "m_Value": { + "e00": 2.0, + "e01": 2.0, + "e02": 2.0, + "e03": 2.0, + "e10": 2.0, + "e11": 2.0, + "e12": 2.0, + "e13": 2.0, + "e20": 2.0, + "e21": 2.0, + "e22": 2.0, + "e23": 2.0, + "e30": 2.0, + "e31": 2.0, + "e32": 2.0, + "e33": 2.0 + }, + "m_DefaultValue": { + "e00": 1.0, + "e01": 0.0, + "e02": 0.0, + "e03": 0.0, + "e10": 0.0, + "e11": 1.0, + "e12": 0.0, + "e13": 0.0, + "e20": 0.0, + "e21": 0.0, + "e22": 1.0, + "e23": 0.0, + "e30": 0.0, + "e31": 0.0, + "e32": 0.0, + "e33": 1.0 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.SubGraphOutputNode", + "m_ObjectId": "f11c51012e9e49c48347c1ed01688305", + "m_Group": { + "m_Id": "31a187406d544c71addcb5f2ec60f0dd" + }, + "m_Name": "Output", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 1002.4999389648438, + "y": -15.499969482421875, + "width": 120.50006103515625, + "height": 76.99996948242188 + } + }, + "m_Slots": [ + { + "m_Id": "82c0444a2bf14afc8b1e33e64a389ab2" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "IsFirstSlotValid": true +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "f69e71976a2d4ecea22a95028807dbeb", + "m_Id": 6, + "m_DisplayName": "B", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "B", + "m_StageCapability": 2, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.SamplerStateMaterialSlot", + "m_ObjectId": "fbfb207e7d1149d980d5acae2b983f1c", + "m_Id": 3, + "m_DisplayName": "Sampler", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Sampler", + "m_StageCapability": 3, + "m_BareResource": false +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.PropertyNode", + "m_ObjectId": "fe5f2e41089241ddb9665cdfded52ead", + "m_Group": { + "m_Id": "31a187406d544c71addcb5f2ec60f0dd" + }, + "m_Name": "Property", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -484.99993896484377, + "y": 253.49993896484376, + "width": 152.5, + "height": 34.00006103515625 + } + }, + "m_Slots": [ + { + "m_Id": "a7afdcba447646dda5deb46af76ab0b2" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_Property": { + "m_Id": "ec0ba007f0bc41e6b7507ffab93a4e81" + } +} + diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Shaders/SubGraphs/SampleEmission.shadersubgraph.meta b/Packages/app.rive.rive-unity/Runtime/Components/Shaders/SubGraphs/SampleEmission.shadersubgraph.meta new file mode 100644 index 00000000..c59a8eba --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Shaders/SubGraphs/SampleEmission.shadersubgraph.meta @@ -0,0 +1,17 @@ +fileFormatVersion: 2 +guid: c3bbcf1d5b5ee446baa01a87b8e5dadf +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: 60072b568d64c40a485e0fc55012dc9f, type: 3} +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Shaders/SubGraphs/SampleEmission.shadersubgraph + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Shaders/SubGraphs/SampleMainRiveTexture.shadersubgraph b/Packages/app.rive.rive-unity/Runtime/Components/Shaders/SubGraphs/SampleMainRiveTexture.shadersubgraph new file mode 100644 index 00000000..2346b57d --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Shaders/SubGraphs/SampleMainRiveTexture.shadersubgraph @@ -0,0 +1,906 @@ +{ + "m_SGVersion": 3, + "m_Type": "UnityEditor.ShaderGraph.GraphData", + "m_ObjectId": "6b29bc6e2a604c9caa97ea94b2c80736", + "m_Properties": [ + { + "m_Id": "f77bdba097f842efacf27ee2c4c0d506" + }, + { + "m_Id": "9e1655f2e4744921b0d82d5ae5c86246" + } + ], + "m_Keywords": [], + "m_Dropdowns": [], + "m_CategoryData": [ + { + "m_Id": "2af809f4bc1c4e169b56f6b34177881a" + } + ], + "m_Nodes": [ + { + "m_Id": "5481f71ba5c04b1aaaeeaa510f770155" + }, + { + "m_Id": "505b646d4b1240998d1eb00bbdd63c14" + }, + { + "m_Id": "bd9926b765cb4f02ad6cd149c7c0d5b8" + }, + { + "m_Id": "2445892a52404f54bda48a2e9e6f84af" + }, + { + "m_Id": "b2635025e83d4585a80610c8cebd24b7" + }, + { + "m_Id": "607f8b4df7c04211abb8275f1a1b3632" + } + ], + "m_GroupDatas": [], + "m_StickyNoteDatas": [], + "m_Edges": [ + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "2445892a52404f54bda48a2e9e6f84af" + }, + "m_SlotId": 1 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "bd9926b765cb4f02ad6cd149c7c0d5b8" + }, + "m_SlotId": 1 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "505b646d4b1240998d1eb00bbdd63c14" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "2445892a52404f54bda48a2e9e6f84af" + }, + "m_SlotId": -1619238207 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "505b646d4b1240998d1eb00bbdd63c14" + }, + "m_SlotId": 7 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "5481f71ba5c04b1aaaeeaa510f770155" + }, + "m_SlotId": 2 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "607f8b4df7c04211abb8275f1a1b3632" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "bd9926b765cb4f02ad6cd149c7c0d5b8" + }, + "m_SlotId": 0 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "b2635025e83d4585a80610c8cebd24b7" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "505b646d4b1240998d1eb00bbdd63c14" + }, + "m_SlotId": 1 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "bd9926b765cb4f02ad6cd149c7c0d5b8" + }, + "m_SlotId": 2 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "5481f71ba5c04b1aaaeeaa510f770155" + }, + "m_SlotId": 1 + } + } + ], + "m_VertexContext": { + "m_Position": { + "x": 0.0, + "y": 0.0 + }, + "m_Blocks": [] + }, + "m_FragmentContext": { + "m_Position": { + "x": 0.0, + "y": 0.0 + }, + "m_Blocks": [] + }, + "m_PreviewData": { + "serializedMesh": { + "m_SerializedMesh": "{\"mesh\":{\"instanceID\":0}}", + "m_Guid": "" + }, + "preventRotation": false + }, + "m_Path": "Sub Graphs", + "m_GraphPrecision": 1, + "m_PreviewMode": 2, + "m_OutputNode": { + "m_Id": "5481f71ba5c04b1aaaeeaa510f770155" + }, + "m_ActiveTargets": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "0900fee3a8314ee7bf356afe790b2885", + "m_Id": 5, + "m_DisplayName": "G", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "G", + "m_StageCapability": 2, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.DynamicValueMaterialSlot", + "m_ObjectId": "1999b6ca2dfc46cb86e9f177fbe9c7ea", + "m_Id": 2, + "m_DisplayName": "Out", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out", + "m_StageCapability": 3, + "m_Value": { + "e00": 0.0, + "e01": 0.0, + "e02": 0.0, + "e03": 0.0, + "e10": 0.0, + "e11": 0.0, + "e12": 0.0, + "e13": 0.0, + "e20": 0.0, + "e21": 0.0, + "e22": 0.0, + "e23": 0.0, + "e30": 0.0, + "e31": 0.0, + "e32": 0.0, + "e33": 0.0 + }, + "m_DefaultValue": { + "e00": 1.0, + "e01": 0.0, + "e02": 0.0, + "e03": 0.0, + "e10": 0.0, + "e11": 1.0, + "e12": 0.0, + "e13": 0.0, + "e20": 0.0, + "e21": 0.0, + "e22": 1.0, + "e23": 0.0, + "e30": 0.0, + "e31": 0.0, + "e32": 0.0, + "e33": 1.0 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "1e279a64e0d8445e9dcc1ca48dd9b837", + "m_Id": 6, + "m_DisplayName": "B", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "B", + "m_StageCapability": 2, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "227ffc2d7fd74fda928a1a5210a76fb4", + "m_Id": -1954867288, + "m_DisplayName": "DecodeMode", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "_DecodeMode", + "m_StageCapability": 3, + "m_Value": -1.0, + "m_DefaultValue": 0.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.SubGraphNode", + "m_ObjectId": "2445892a52404f54bda48a2e9e6f84af", + "m_Group": { + "m_Id": "" + }, + "m_Name": "SRGBDecode_Auto", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 159.99996948242188, + "y": 178.99996948242188, + "width": 236.50006103515626, + "height": 303.00006103515627 + } + }, + "m_Slots": [ + { + "m_Id": "55463da6ae114689a62afe9ec10d8861" + }, + { + "m_Id": "227ffc2d7fd74fda928a1a5210a76fb4" + }, + { + "m_Id": "c2170d8deef24038a6f385610b82ea6f" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedSubGraph": "{\n \"subGraph\": {\n \"fileID\": -5475051401550479605,\n \"guid\": \"a2b967a2d741d41f0892c3328200244a\",\n \"type\": 3\n }\n}", + "m_PropertyGuids": [ + "a7292d5e-7e6d-42f7-9e9c-223d6cad8047", + "cb2852af-b565-4de2-964c-573df4bce630" + ], + "m_PropertyIds": [ + -1619238207, + -1954867288 + ], + "m_Dropdowns": [], + "m_DropdownSelectedEntries": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.CategoryData", + "m_ObjectId": "2af809f4bc1c4e169b56f6b34177881a", + "m_Name": "", + "m_ChildObjectList": [ + { + "m_Id": "f77bdba097f842efacf27ee2c4c0d506" + }, + { + "m_Id": "9e1655f2e4744921b0d82d5ae5c86246" + } + ] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Texture2DMaterialSlot", + "m_ObjectId": "3a6362af5b004bf1b69e3453ae880c72", + "m_Id": 0, + "m_DisplayName": "BaseMap", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out", + "m_StageCapability": 3, + "m_BareResource": false +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.UVMaterialSlot", + "m_ObjectId": "3e523ac5b8554e74ab113b284819a44f", + "m_Id": 2, + "m_DisplayName": "UV", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "UV", + "m_StageCapability": 3, + "m_Value": { + "x": 0.0, + "y": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0 + }, + "m_Labels": [], + "m_Channel": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector4MaterialSlot", + "m_ObjectId": "44d7cb15a43840deac9bb0dc0b0da372", + "m_Id": 0, + "m_DisplayName": "BaseColor", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out", + "m_StageCapability": 3, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.SampleTexture2DNode", + "m_ObjectId": "505b646d4b1240998d1eb00bbdd63c14", + "m_Group": { + "m_Id": "" + }, + "m_Name": "Sample Texture 2D", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -185.666748046875, + "y": 432.33306884765627, + "width": 208.0, + "height": 434.0 + } + }, + "m_Slots": [ + { + "m_Id": "6f56033305d54403997dd878f352ef65" + }, + { + "m_Id": "d50e6707a0d24a41bba05216869f3b5c" + }, + { + "m_Id": "0900fee3a8314ee7bf356afe790b2885" + }, + { + "m_Id": "1e279a64e0d8445e9dcc1ca48dd9b837" + }, + { + "m_Id": "74e719677b154a188176354162d741fa" + }, + { + "m_Id": "d5baa588bf2c4058b79977aaf0edb5d4" + }, + { + "m_Id": "3e523ac5b8554e74ab113b284819a44f" + }, + { + "m_Id": "d2c1613a82b9444ca4a7060e817c28b0" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_TextureType": 0, + "m_NormalMapSpace": 0, + "m_EnableGlobalMipBias": true +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.SubGraphOutputNode", + "m_ObjectId": "5481f71ba5c04b1aaaeeaa510f770155", + "m_Group": { + "m_Id": "" + }, + "m_Name": "Output", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 860.5, + "y": 381.0, + "width": 132.5001220703125, + "height": 77.0 + } + }, + "m_Slots": [ + { + "m_Id": "7c49812314c74d799b8304c558adc231" + }, + { + "m_Id": "ee88d84e52414d64a7233d06dfb9e8a3" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "IsFirstSlotValid": true +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector4MaterialSlot", + "m_ObjectId": "55463da6ae114689a62afe9ec10d8861", + "m_Id": -1619238207, + "m_DisplayName": "ColorIn", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "_ColorIn", + "m_StageCapability": 3, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.PropertyNode", + "m_ObjectId": "607f8b4df7c04211abb8275f1a1b3632", + "m_Group": { + "m_Id": "" + }, + "m_Name": "Property", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -14.159423828125, + "y": 16.1822509765625, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "44d7cb15a43840deac9bb0dc0b0da372" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_Property": { + "m_Id": "9e1655f2e4744921b0d82d5ae5c86246" + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector4MaterialSlot", + "m_ObjectId": "6f56033305d54403997dd878f352ef65", + "m_Id": 0, + "m_DisplayName": "RGBA", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "RGBA", + "m_StageCapability": 2, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.DynamicValueMaterialSlot", + "m_ObjectId": "6ff3db6ad8354a52aa21ceb81cdd2335", + "m_Id": 1, + "m_DisplayName": "B", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "B", + "m_StageCapability": 3, + "m_Value": { + "e00": 2.0, + "e01": 2.0, + "e02": 2.0, + "e03": 2.0, + "e10": 2.0, + "e11": 2.0, + "e12": 2.0, + "e13": 2.0, + "e20": 2.0, + "e21": 2.0, + "e22": 2.0, + "e23": 2.0, + "e30": 2.0, + "e31": 2.0, + "e32": 2.0, + "e33": 2.0 + }, + "m_DefaultValue": { + "e00": 1.0, + "e01": 0.0, + "e02": 0.0, + "e03": 0.0, + "e10": 0.0, + "e11": 1.0, + "e12": 0.0, + "e13": 0.0, + "e20": 0.0, + "e21": 0.0, + "e22": 1.0, + "e23": 0.0, + "e30": 0.0, + "e31": 0.0, + "e32": 0.0, + "e33": 1.0 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.DynamicValueMaterialSlot", + "m_ObjectId": "71354cc8f9bc4cd486ca15638fb7d6e8", + "m_Id": 0, + "m_DisplayName": "A", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "A", + "m_StageCapability": 3, + "m_Value": { + "e00": 0.0, + "e01": 0.0, + "e02": 0.0, + "e03": 0.0, + "e10": 0.0, + "e11": 0.0, + "e12": 0.0, + "e13": 0.0, + "e20": 0.0, + "e21": 0.0, + "e22": 0.0, + "e23": 0.0, + "e30": 0.0, + "e31": 0.0, + "e32": 0.0, + "e33": 0.0 + }, + "m_DefaultValue": { + "e00": 1.0, + "e01": 0.0, + "e02": 0.0, + "e03": 0.0, + "e10": 0.0, + "e11": 1.0, + "e12": 0.0, + "e13": 0.0, + "e20": 0.0, + "e21": 0.0, + "e22": 1.0, + "e23": 0.0, + "e30": 0.0, + "e31": 0.0, + "e32": 0.0, + "e33": 1.0 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "74e719677b154a188176354162d741fa", + "m_Id": 7, + "m_DisplayName": "A", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "A", + "m_StageCapability": 2, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector3MaterialSlot", + "m_ObjectId": "7c49812314c74d799b8304c558adc231", + "m_Id": 1, + "m_DisplayName": "Out_BaseColor", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Out_BaseColor", + "m_StageCapability": 2, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 3, + "m_Type": "UnityEditor.ShaderGraph.Internal.ColorShaderProperty", + "m_ObjectId": "9e1655f2e4744921b0d82d5ae5c86246", + "m_Guid": { + "m_GuidSerialized": "0dafdea0-1c0d-40c7-9a2f-3553ae8cb358" + }, + "m_Name": "BaseColor", + "m_DefaultRefNameVersion": 1, + "m_RefNameGeneratedByDisplayName": "BaseColor", + "m_DefaultReferenceName": "_BaseColor", + "m_OverrideReferenceName": "", + "m_GeneratePropertyBlock": true, + "m_UseCustomSlotLabel": false, + "m_CustomSlotLabel": "", + "m_Precision": 0, + "overrideHLSLDeclaration": false, + "hlslDeclarationOverride": 0, + "m_Hidden": false, + "m_Value": { + "r": 0.0, + "g": 0.0, + "b": 0.0, + "a": 0.0 + }, + "isMainColor": false, + "m_ColorMode": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.PropertyNode", + "m_ObjectId": "b2635025e83d4585a80610c8cebd24b7", + "m_Group": { + "m_Id": "" + }, + "m_Name": "Property", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -477.5, + "y": 474.5, + "width": 128.5, + "height": 34.0 + } + }, + "m_Slots": [ + { + "m_Id": "3a6362af5b004bf1b69e3453ae880c72" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_Property": { + "m_Id": "f77bdba097f842efacf27ee2c4c0d506" + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.MultiplyNode", + "m_ObjectId": "bd9926b765cb4f02ad6cd149c7c0d5b8", + "m_Group": { + "m_Id": "" + }, + "m_Name": "Multiply", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 578.0001220703125, + "y": -84.00006103515625, + "width": 208.0, + "height": 302.00006103515627 + } + }, + "m_Slots": [ + { + "m_Id": "71354cc8f9bc4cd486ca15638fb7d6e8" + }, + { + "m_Id": "6ff3db6ad8354a52aa21ceb81cdd2335" + }, + { + "m_Id": "1999b6ca2dfc46cb86e9f177fbe9c7ea" + } + ], + "synonyms": [ + "multiplication", + "times", + "x" + ], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector4MaterialSlot", + "m_ObjectId": "c2170d8deef24038a6f385610b82ea6f", + "m_Id": 1, + "m_DisplayName": "Out_Vector4", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "OutVector4", + "m_StageCapability": 3, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.SamplerStateMaterialSlot", + "m_ObjectId": "d2c1613a82b9444ca4a7060e817c28b0", + "m_Id": 3, + "m_DisplayName": "Sampler", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Sampler", + "m_StageCapability": 3, + "m_BareResource": false +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "d50e6707a0d24a41bba05216869f3b5c", + "m_Id": 4, + "m_DisplayName": "R", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "R", + "m_StageCapability": 2, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Texture2DInputMaterialSlot", + "m_ObjectId": "d5baa588bf2c4058b79977aaf0edb5d4", + "m_Id": 1, + "m_DisplayName": "Texture", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Texture", + "m_StageCapability": 3, + "m_BareResource": false, + "m_Texture": { + "m_SerializedTexture": "{\"texture\":{\"instanceID\":0}}", + "m_Guid": "" + }, + "m_DefaultType": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "ee88d84e52414d64a7233d06dfb9e8a3", + "m_Id": 2, + "m_DisplayName": "Out_Alpha", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Out_Alpha", + "m_StageCapability": 2, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Internal.Texture2DShaderProperty", + "m_ObjectId": "f77bdba097f842efacf27ee2c4c0d506", + "m_Guid": { + "m_GuidSerialized": "4b65a152-6b9e-429e-bbc1-bebac7fac8fc" + }, + "m_Name": "BaseMap", + "m_DefaultRefNameVersion": 1, + "m_RefNameGeneratedByDisplayName": "BaseMap", + "m_DefaultReferenceName": "_BaseMap", + "m_OverrideReferenceName": "", + "m_GeneratePropertyBlock": true, + "m_UseCustomSlotLabel": false, + "m_CustomSlotLabel": "", + "m_Precision": 0, + "overrideHLSLDeclaration": false, + "hlslDeclarationOverride": 0, + "m_Hidden": false, + "m_Value": { + "m_SerializedTexture": "{\"texture\":{\"instanceID\":0}}", + "m_Guid": "" + }, + "isMainTexture": false, + "useTilingAndOffset": false, + "m_Modifiable": true, + "m_DefaultType": 0 +} + diff --git a/Packages/app.rive.rive-unity/Runtime/Components/Shaders/SubGraphs/SampleMainRiveTexture.shadersubgraph.meta b/Packages/app.rive.rive-unity/Runtime/Components/Shaders/SubGraphs/SampleMainRiveTexture.shadersubgraph.meta new file mode 100644 index 00000000..91f22db6 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Components/Shaders/SubGraphs/SampleMainRiveTexture.shadersubgraph.meta @@ -0,0 +1,17 @@ +fileFormatVersion: 2 +guid: 287ae8d259edf47cf9ec073950debe11 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: 60072b568d64c40a485e0fc55012dc9f, type: 3} +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Components/Shaders/SubGraphs/SampleMainRiveTexture.shadersubgraph + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/CustomFileAssetLoader.cs b/Packages/app.rive.rive-unity/Runtime/CustomFileAssetLoader.cs new file mode 100644 index 00000000..c0dc7b09 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/CustomFileAssetLoader.cs @@ -0,0 +1,32 @@ + +using static Rive.File; + +namespace Rive +{ + /// + /// The Custom file asset loader allows you to pass in a custom handler for loading assets from the Rive file. + /// + internal class CustomFileAssetLoader : IFileAssetLoader + { + + + private CustomAssetLoaderCallback customLoader; + public CustomFileAssetLoader(CustomAssetLoaderCallback loader) + { + customLoader = loader; + } + + + public bool LoadContents(EmbeddedAssetReference assetReference) + { + // If the custom loader is null, then let the default loader handle it. + if (customLoader == null) + { + return false; + } + return customLoader(assetReference); + } + + + } +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Runtime/CustomFileAssetLoader.cs.meta b/Packages/app.rive.rive-unity/Runtime/CustomFileAssetLoader.cs.meta new file mode 100644 index 00000000..e0fe7fb5 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/CustomFileAssetLoader.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 467f4f194b6a94f3f8ba73a0bc8ba949 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/CustomFileAssetLoader.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/DataBinding.meta b/Packages/app.rive.rive-unity/Runtime/DataBinding.meta new file mode 100644 index 00000000..8adf233e --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/DataBinding.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 62a7e65f2d9ca49fba3c240c3b816001 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Runtime/DataBinding/BindableArtboard.cs b/Packages/app.rive.rive-unity/Runtime/DataBinding/BindableArtboard.cs new file mode 100644 index 00000000..5e671430 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/DataBinding/BindableArtboard.cs @@ -0,0 +1,108 @@ +using System; +using System.Runtime.InteropServices; + +namespace Rive +{ + /// + /// An artboard that can be bound to view model properties. + /// + public class BindableArtboard : IDisposable + { + private IntPtr m_nativeBindableArtboard; + private string m_artboardName; + private bool m_isDisposed = false; + private readonly ViewModelInstanceSafeHandle m_viewModelInstanceHandle; + + internal IntPtr NativeBindableArtboard + { + get { return m_nativeBindableArtboard; } + } + + internal ViewModelInstanceSafeHandle ViewModelInstanceHandle + { + get { return m_viewModelInstanceHandle; } + } + + + + /// + /// Constructor for the BindableArtboard class. + /// + /// Pointer to the native bindable artboard. + internal BindableArtboard(IntPtr nativeBindableArtboard) + : this(nativeBindableArtboard, null) + { + } + + /// + /// Constructor for the BindableArtboard class with an optional bound ViewModel instance. + /// + /// Pointer to the native bindable artboard. + /// Optional ViewModel instance to bind to this artboard. + internal BindableArtboard(IntPtr nativeBindableArtboard, ViewModelInstance viewModelInstance) + { + m_nativeBindableArtboard = nativeBindableArtboard; + if (viewModelInstance != null && + viewModelInstance.NativeSafeHandle != null && + !viewModelInstance.NativeSafeHandle.IsInvalid) + { + m_viewModelInstanceHandle = viewModelInstance.NativeSafeHandle; + } + else + { + m_viewModelInstanceHandle = ViewModelInstanceSafeHandle.Null; + } + } + + /// + /// Dispose of the BindableArtboard and release native resources. + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (!m_isDisposed) + { + if (m_nativeBindableArtboard != IntPtr.Zero) + { + unrefBindableArtboard(m_nativeBindableArtboard); + m_nativeBindableArtboard = IntPtr.Zero; + } + + m_isDisposed = true; + } + } + + ~BindableArtboard() + { + Dispose(false); + } + + /// + /// Gets the name of the artboard. + /// + public string Name + { + get + { + if (m_artboardName == null && !m_isDisposed) + { + m_artboardName = Marshal.PtrToStringAnsi(getBindableArtboardName(m_nativeBindableArtboard)); + } + return m_artboardName; + } + } + + #region Native Methods + [DllImport(NativeLibrary.name)] + private static extern void unrefBindableArtboard(IntPtr artboard); + + [DllImport(NativeLibrary.name)] + private static extern IntPtr getBindableArtboardName(IntPtr artboard); + #endregion + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/DataBinding/BindableArtboard.cs.meta b/Packages/app.rive.rive-unity/Runtime/DataBinding/BindableArtboard.cs.meta new file mode 100644 index 00000000..e4024e6b --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/DataBinding/BindableArtboard.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 4ee424928a0bf4f0e9854f2f7f56ee2f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/DataBinding/BindableArtboard.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/DataBinding/Helpers.meta b/Packages/app.rive.rive-unity/Runtime/DataBinding/Helpers.meta new file mode 100644 index 00000000..9da39009 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/DataBinding/Helpers.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f78ba466da39f420fbcb95e887ef22c4 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Runtime/DataBinding/Helpers/PropertyCallbacksHub.cs b/Packages/app.rive.rive-unity/Runtime/DataBinding/Helpers/PropertyCallbacksHub.cs new file mode 100644 index 00000000..38ff4ad3 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/DataBinding/Helpers/PropertyCallbacksHub.cs @@ -0,0 +1,153 @@ +using System; +using System.Collections.Generic; +using Rive.Utils; + +namespace Rive +{ + /// + /// Centralized callback pump for view model instance properties. Used by the Orchestrator + /// to trigger callbacks for all subscribed properties instead of traversing the ViewModelInstance hierarchy. + /// Uses weak references so it does not prevent properties from being garbage collected; + /// the owning is responsible for keeping subscribed properties alive. + /// + internal sealed class PropertyCallbacksHub + { + private static PropertyCallbacksHub s_instance; + + internal static PropertyCallbacksHub Instance + { + get + { + if (s_instance == null) + { + s_instance = new PropertyCallbacksHub(); + } + return s_instance; + } + } + + private readonly Dictionary> m_subscribedProperties = + new Dictionary>(); + private readonly List m_changedScratch = new List(); + private readonly List m_captureScratch = new List(); + private readonly List m_deadPointersScratch = new List(); + private readonly object m_lock = new object(); + + private PropertyCallbacksHub() { } + + /// + /// Registers a property with the hub via a weak reference. + /// The owning keeps the property alive. + /// + /// The property to register. + internal void Register(ViewModelInstancePrimitiveProperty property) + { + if (property == null) + { + return; + } + + IntPtr ptr = property.InstancePropertyPtr; + if (ptr == IntPtr.Zero) + { + return; + } + + lock (m_lock) + { + m_subscribedProperties[ptr] = new WeakReference(property); + } + } + + /// + /// Unregisters a property from the hub. + /// + /// The pointer to the property to unregister. + internal void Unregister(IntPtr instancePropertyPtr) + { + if (instancePropertyPtr == IntPtr.Zero) + { + return; + } + + lock (m_lock) + { + m_subscribedProperties.Remove(instancePropertyPtr); + } + } + + /// + /// Captures changed properties and clears their change flags. + /// This should run in the same frame as panel/state machine advancement. + /// + /// True if any changed properties were captured. + internal bool CaptureChanges() + { + m_changedScratch.Clear(); + m_deadPointersScratch.Clear(); + + lock (m_lock) + { + m_captureScratch.Clear(); + foreach (var kvp in m_subscribedProperties) + { + if (kvp.Value.TryGetTarget(out var property)) + { + m_captureScratch.Add(property); + } + else + { + m_deadPointersScratch.Add(kvp.Key); + } + } + + for (int i = 0; i < m_deadPointersScratch.Count; i++) + { + m_subscribedProperties.Remove(m_deadPointersScratch[i]); + } + } + + for (int i = 0; i < m_captureScratch.Count; i++) + { + var property = m_captureScratch[i]; + + if (property.HasChanged) + { + property.ClearChanges(); + m_changedScratch.Add(property); + } + } + + return m_changedScratch.Count > 0; + } + + /// + /// Dispatches callbacks that were previously captured by . + /// + internal void FlushCapturedCallbacks() + { + for (int i = 0; i < m_changedScratch.Count; i++) + { + try + { + m_changedScratch[i].RaiseChangedEvent(); + } + catch (Exception e) + { + DebugLogger.Instance.LogException(e); + } + } + + m_changedScratch.Clear(); + } + +#if UNITY_EDITOR + // Account for Editor Domain Reload being disabled. + [UnityEngine.RuntimeInitializeOnLoadMethod(UnityEngine.RuntimeInitializeLoadType.SubsystemRegistration)] + private static void Init() + { + s_instance = null; + } +#endif + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/DataBinding/Helpers/PropertyCallbacksHub.cs.meta b/Packages/app.rive.rive-unity/Runtime/DataBinding/Helpers/PropertyCallbacksHub.cs.meta new file mode 100644 index 00000000..8ab152d5 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/DataBinding/Helpers/PropertyCallbacksHub.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 875e81c443b0b469aacdddeb11dd0d2a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/DataBinding/Helpers/PropertyCallbacksHub.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/DataBinding/Helpers/ViewModelInstancePropertyHandlersFactory.cs b/Packages/app.rive.rive-unity/Runtime/DataBinding/Helpers/ViewModelInstancePropertyHandlersFactory.cs new file mode 100644 index 00000000..2fd66a8b --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/DataBinding/Helpers/ViewModelInstancePropertyHandlersFactory.cs @@ -0,0 +1,421 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using Rive.Utils; + +namespace Rive +{ + /// + /// Factory class responsible for creating property handlers for the ViewModelInstance class. + /// This centralizes all property-related functionality outside of ViewModelInstance. + /// + internal static class ViewModelInstancePropertyHandlersFactory + { + #region Property Result Types + + /// + /// Represents the result of a property getter operation. + /// + private readonly struct PropertyGetterResult + { + public enum EnumTypeOption + { + None = 0, + CustomEnum = 1, + SystemEnum = 2 + } + + public readonly IntPtr PropertyPtr { get; } + public readonly EnumTypeOption EnumType { get; } + public readonly nuint? EnumIndex { get; } + public ViewModelInstance RootViewModelInstance { get; } + + public PropertyGetterResult(IntPtr property, ViewModelInstance rootVmInstance, EnumTypeOption enumType = EnumTypeOption.None, nuint? enumIndex = null) + { + PropertyPtr = property; + EnumType = enumType; + EnumIndex = enumIndex; + RootViewModelInstance = rootVmInstance; + } + } + + /// + /// Delegate for property getter functions + /// + private delegate PropertyGetterResult PropertyGetter(ViewModelInstance instanceToGetPropertyFrom, string path, ViewModelInstance rootInstance); + + #endregion + + #region Property Cache + + + + #endregion + + #region Property Handlers + + private static readonly Dictionary creator)> + PropertyHandlers = InitializePropertyHandlers(); + + private static Dictionary creator)> InitializePropertyHandlers() + { + return new Dictionary)> + { + { typeof(ViewModelInstanceEnumProperty), CreateEnumPropertyHandler() }, + { typeof(ViewModelInstanceTriggerProperty), CreateTriggerPropertyHandler() }, + { typeof(ViewModelInstanceBooleanProperty), CreateBooleanPropertyHandler() }, + { typeof(ViewModelInstanceNumberProperty), CreateNumberPropertyHandler() }, + { typeof(ViewModelInstanceStringProperty), CreateStringPropertyHandler() }, + { typeof(ViewModelInstanceColorProperty), CreateColorPropertyHandler() }, + { typeof(ViewModelInstanceImageProperty), CreateImagePropertyHandler() }, + { typeof(ViewModelInstanceListProperty), CreateListPropertyHandler() }, + { typeof(ViewModelInstanceArtboardProperty), CreateArtboardPropertyHandler() } + }; + } + + /// + /// Creates a handler for enum properties + /// + private static (PropertyGetter getter, + Func creator) CreateEnumPropertyHandler() + { + return ( + (instance, path, rootInstance) => + { + // If the file that the instance was loaded from is no longer available, this will be null + IntPtr nativeFilePtr = instance.RiveFile != null ? instance.RiveFile.NativeFile : IntPtr.Zero; + var info = getEnumPropertyInfoFromViewModelInstance( + instance.NativeSafeHandle, + nativeFilePtr, + path); + + + + return new PropertyGetterResult( + info.propertyPtr, + rootInstance, + PropertyGetterResult.EnumTypeOption.CustomEnum, + info.enumIndex); + }, + (result) => + { + // If the property was not found, or if the property is not an enum, this will be true + if (result.PropertyPtr == IntPtr.Zero) + { + return null; + } + + IReadOnlyList enumsForFile = result.RootViewModelInstance.RiveFile != null ? result.RootViewModelInstance.RiveFile.ViewModelEnums : null; + + + bool isValidIndex = result.EnumIndex.HasValue && result.EnumIndex.Value >= 0 && (int)result.EnumIndex.Value < enumsForFile.Count; + + // If the enums are included in the file, we can reuse them across multiple instances + // Otherwise, we'll have to fetch the enum values from the instance. This happens in the ViewModelInstanceEnumProperty constructor if we don't have the enum values already. + if (isValidIndex && enumsForFile != null) + { + string[] enumValues = enumsForFile[(int)result.EnumIndex.Value].ValuesArray; + return new ViewModelInstanceEnumProperty( + result.PropertyPtr, + result.RootViewModelInstance, + enumValues); + } + else + { + return new ViewModelInstanceEnumProperty( + result.PropertyPtr, + result.RootViewModelInstance); + } + } + ); + } + + /// + /// Creates a handler for trigger properties + /// + private static (PropertyGetter getter, + Func creator) CreateTriggerPropertyHandler() + { + return ( + (instance, path, rootInstance) => new PropertyGetterResult( + getViewModelInstanceTriggerProperty(instance.NativeSafeHandle, path), + rootInstance, + PropertyGetterResult.EnumTypeOption.None), + (result) => new ViewModelInstanceTriggerProperty( + result.PropertyPtr, + result.RootViewModelInstance) + ); + } + + /// + /// Creates a handler for boolean properties + /// + private static (PropertyGetter getter, + Func creator) CreateBooleanPropertyHandler() + { + return ( + (instance, path, rootInstance) => new PropertyGetterResult( + getViewModelInstanceBooleanProperty(instance.NativeSafeHandle, path), + rootInstance, + PropertyGetterResult.EnumTypeOption.None), + (result) => new ViewModelInstanceBooleanProperty( + result.PropertyPtr, + result.RootViewModelInstance) + ); + } + + /// + /// Creates a handler for number properties + /// + private static (PropertyGetter getter, + Func creator) CreateNumberPropertyHandler() + { + return ( + (instance, path, rootInstance) => new PropertyGetterResult( + getViewModelInstanceNumberProperty(instance.NativeSafeHandle, path), + rootInstance, + PropertyGetterResult.EnumTypeOption.None), + (result) => new ViewModelInstanceNumberProperty( + result.PropertyPtr, + result.RootViewModelInstance) + ); + } + + /// + /// Creates a handler for string properties + /// + private static (PropertyGetter getter, + Func creator) CreateStringPropertyHandler() + { + return ( + (instance, path, rootInstance) => new PropertyGetterResult( + getViewModelInstanceStringProperty(instance.NativeSafeHandle, path), + rootInstance, + PropertyGetterResult.EnumTypeOption.None), + (result) => new ViewModelInstanceStringProperty( + result.PropertyPtr, + result.RootViewModelInstance) + ); + } + + /// + /// Creates a handler for color properties + /// + private static (PropertyGetter getter, + Func creator) CreateColorPropertyHandler() + { + return ( + (instance, path, rootInstance) => new PropertyGetterResult( + getViewModelInstanceColorProperty(instance.NativeSafeHandle, path), + rootInstance, + PropertyGetterResult.EnumTypeOption.None), + (result) => new ViewModelInstanceColorProperty( + result.PropertyPtr, + result.RootViewModelInstance) + ); + } + + /// + /// Creates a handler for image properties + /// + private static (PropertyGetter getter, + Func creator) CreateImagePropertyHandler() + { + return ( + (instance, path, rootInstance) => new PropertyGetterResult( + getViewModelInstanceImageProperty(instance.NativeSafeHandle, path), + rootInstance), + (result) => new ViewModelInstanceImageProperty( + result.PropertyPtr, + result.RootViewModelInstance) + ); + } + + private static (PropertyGetter getter, + Func creator) CreateListPropertyHandler() + { + return ( + (instance, path, rootInstance) => new PropertyGetterResult( + getViewModelInstanceListProperty(instance.NativeSafeHandle, path), + rootInstance, + PropertyGetterResult.EnumTypeOption.None), + (result) => new ViewModelInstanceListProperty( + result.PropertyPtr, + result.RootViewModelInstance) + ); + } + + private static (PropertyGetter getter, + Func creator) CreateArtboardPropertyHandler() + { + return ( + (instance, path, rootInstance) => new PropertyGetterResult( + getViewModelInstanceArtboardProperty(instance.NativeSafeHandle, path), + rootInstance), + (result) => new ViewModelInstanceArtboardProperty( + result.PropertyPtr, + result.RootViewModelInstance) + ); + } + + #endregion + + #region Public Property Fetching API + + /// + /// Gets a property of the specified type from a view model instance. + /// + /// The type of property to get + /// The view model instance to get the property from + /// The path to the property + /// The property instance or null if not found + public static T GetPrimitiveProperty(ViewModelInstance instance, string path) where T : ViewModelInstanceProperty + { + if (!PropertyHandlers.TryGetValue(typeof(T), out var handler)) + { + DebugLogger.Instance.LogError("Property type not supported: " + typeof(T).Name); + return null; + } + + var result = GetPropertyPointer(handler.getter, instance, path, instance); + + if (result.PropertyPtr == IntPtr.Zero) + { + DebugLogger.Instance.LogError("Property not found: " + path); + return null; + } + + T instanceAsExpectedType = null; + + // Check if we have already created an instance of this property + if (ViewModelInstanceProperty.TryGetGloballyCachedVMPropertyForPointer(result.PropertyPtr, out var cachedProperty)) + { + bool isStale = cachedProperty is ViewModelInstancePrimitiveProperty cachedPrim && + cachedPrim.RootInstance != instance; + + // We want to catch cases where the property was created as a different type than expected + if (isStale) + { + ViewModelInstanceProperty.RemoveCachedPropertyForPointer(result.PropertyPtr); + } + else + { + instanceAsExpectedType = cachedProperty as T; + + if (instanceAsExpectedType == null) + { + DebugLogger.Instance.LogError("Failed to get property: " + path + ". Expected type: " + typeof(T).Name); + return null; + } + return instanceAsExpectedType; + } + } + + // Create a new property instance + var propInstance = handler.creator(result); + ViewModelInstanceProperty.AddGloballyCachedVMPropertyForPointer(result.PropertyPtr, propInstance); + + instanceAsExpectedType = propInstance as T; + return instanceAsExpectedType; + } + + private static PropertyGetterResult GetPropertyPointer( + PropertyGetter getter, + ViewModelInstance instance, + string path, + ViewModelInstance rootInstance) + { + return getter(instance, path, rootInstance); + } +#if UNITY_EDITOR + /// + /// Editor-only utility to get the enum data for a property at a given path. + /// + /// + /// + /// + internal static ViewModelEnumData GetEnumForPropertyAtPath(ViewModelInstance vmInstance, string path) + { + if (vmInstance == null || vmInstance.RiveFile == null) + { + return null; + } + + IntPtr nativeFilePtr = vmInstance.RiveFile != null ? vmInstance.RiveFile.NativeFile : IntPtr.Zero; + var info = getEnumPropertyInfoFromViewModelInstance( + vmInstance.NativeSafeHandle, + nativeFilePtr, + path); + + if (info.propertyPtr == IntPtr.Zero) + { + return null; + } + if (info.enumIndex < 0) + { + return null; + } + + IReadOnlyList enumsForFile = vmInstance.RiveFile.ViewModelEnums; + + if (enumsForFile == null || (int)info.enumIndex >= enumsForFile.Count) + { + return null; + } + + return enumsForFile[(int)info.enumIndex]; + + + } +#endif + #endregion + #region Native Calls + [StructLayout(LayoutKind.Sequential)] + private struct ViewModelInstanceEnumPropertyInfo + { + /// + /// The pointer to the instance property. + /// + public IntPtr propertyPtr; + + /// + /// The index of the enum value in the Rive file. Allows us to share the same enum value across multiple instances. + /// + public nuint enumIndex; + } + + [DllImport(NativeLibrary.name)] + private static extern IntPtr getViewModelInstanceNumberProperty(ViewModelInstanceSafeHandle instanceValue, string path); + + [DllImport(NativeLibrary.name)] + private static extern IntPtr getViewModelInstanceBooleanProperty(ViewModelInstanceSafeHandle instanceValue, string path); + + + [DllImport(NativeLibrary.name)] + private static extern IntPtr getViewModelInstanceTriggerProperty(ViewModelInstanceSafeHandle instanceValue, string path); + + [DllImport(NativeLibrary.name)] + private static extern IntPtr getViewModelInstanceStringProperty(ViewModelInstanceSafeHandle instanceValue, string path); + + [DllImport(NativeLibrary.name)] + private static extern IntPtr getViewModelInstanceColorProperty(ViewModelInstanceSafeHandle instanceValue, string path); + + [DllImport(NativeLibrary.name)] + private static extern IntPtr getViewModelInstanceImageProperty(ViewModelInstanceSafeHandle instanceValue, string path); + + [DllImport(NativeLibrary.name)] + private static extern IntPtr getViewModelInstanceListProperty(ViewModelInstanceSafeHandle instanceValue, string path); + [DllImport(NativeLibrary.name)] + private static extern IntPtr getViewModelInstanceArtboardProperty(ViewModelInstanceSafeHandle instanceValue, string path); + + + [DllImport(NativeLibrary.name)] + private static extern ViewModelInstanceEnumPropertyInfo getEnumPropertyInfoFromViewModelInstance( + ViewModelInstanceSafeHandle instanceValue, + IntPtr fileWrapper, + string path); + + #endregion + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/DataBinding/Helpers/ViewModelInstancePropertyHandlersFactory.cs.meta b/Packages/app.rive.rive-unity/Runtime/DataBinding/Helpers/ViewModelInstancePropertyHandlersFactory.cs.meta new file mode 100644 index 00000000..f5dc34f7 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/DataBinding/Helpers/ViewModelInstancePropertyHandlersFactory.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: d4295ddd1329940a49d3e05ce5f2c87b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/DataBinding/Helpers/ViewModelInstancePropertyHandlersFactory.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/DataBinding/Values.meta b/Packages/app.rive.rive-unity/Runtime/DataBinding/Values.meta new file mode 100644 index 00000000..ce7132c6 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/DataBinding/Values.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4be6ae8d2b4094dc88f1be677ae62ba7 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceArtboardProperty.cs b/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceArtboardProperty.cs new file mode 100644 index 00000000..d9d4d9f4 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceArtboardProperty.cs @@ -0,0 +1,85 @@ +using System; +using System.Runtime.InteropServices; +using Rive.Utils; + +namespace Rive +{ + /// + /// A view model instance property for artboard properties. + /// + public sealed class ViewModelInstanceArtboardProperty : ViewModelInstancePrimitiveProperty + { + public ViewModelInstanceArtboardProperty(IntPtr instanceValuePtr, ViewModelInstance instance) : base(instanceValuePtr, instance) + { + } + + /// + /// Sets the artboard value for this property. + /// + public BindableArtboard Value + { + set + { + ThrowIfOwnerDisposed(); + SetArtboardInternal(value); + } + } + + /// + /// Raised when the artboard property is changed in the Rive graphic. + /// + public event Action OnValueChanged + { + add => AddPropertyCallback(value, ref m_onValueChanged); + remove => RemovePropertyCallback(value, ref m_onValueChanged); + } + private Action m_onValueChanged; + + /// + /// Sets the artboard for the property. + /// + private void SetArtboardInternal(BindableArtboard artboard) + { + if (artboard != null && artboard.NativeBindableArtboard == IntPtr.Zero) + { + DebugLogger.Instance.LogError("Trying to assign an invalid artboard."); + return; + } + + + bool wasSuccess = setViewModelInstanceArtboardValue( + InstancePropertyPtr, + artboard?.NativeBindableArtboard ?? IntPtr.Zero, + artboard?.ViewModelInstanceHandle ?? ViewModelInstanceSafeHandle.Null); + + + if (!wasSuccess) + { + DebugLogger.Instance.LogError("Failed to set artboard."); + } + } + + internal override void RaiseChangedEvent() + { + m_onValueChanged?.Invoke(); + } + + internal override void ClearAllCallbacks() + { + m_onValueChanged = null; + base.ClearAllCallbacks(); + } + + internal override void ClearDelegatesOnly() + { + m_onValueChanged = null; + } + + [DllImport(NativeLibrary.name)] + private static extern bool setViewModelInstanceArtboardValue( + IntPtr instanceProperty, + IntPtr artboard, + ViewModelInstanceSafeHandle viewModelInstance); + + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceArtboardProperty.cs.meta b/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceArtboardProperty.cs.meta new file mode 100644 index 00000000..5fe6308f --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceArtboardProperty.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: b64163b892710430ca18cb732dee8721 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceArtboardProperty.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceBooleanProperty.cs b/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceBooleanProperty.cs new file mode 100644 index 00000000..349d88e5 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceBooleanProperty.cs @@ -0,0 +1,39 @@ +using System; +using System.Runtime.InteropServices; + +namespace Rive +{ + /// + /// A view model instance property that holds a boolean. + /// + public sealed class ViewModelInstanceBooleanProperty : ViewModelInstancePrimitiveProperty + { + internal ViewModelInstanceBooleanProperty(IntPtr instanceValuePtr, ViewModelInstance rootInstance) : base(instanceValuePtr, rootInstance) + { + } + + /// + /// The value of the property. + /// + public override bool Value + { + get + { + ThrowIfOwnerDisposed(); + return getViewModelInstanceBooleanValue(InstancePropertyPtr); + } + set + { + ThrowIfOwnerDisposed(); + setViewModelInstanceBooleanValue(InstancePropertyPtr, value); + } + } + + + [DllImport(NativeLibrary.name)] + private static extern bool getViewModelInstanceBooleanValue(IntPtr instanceProperty); + + [DllImport(NativeLibrary.name)] + private static extern void setViewModelInstanceBooleanValue(IntPtr instanceProperty, bool value); + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceBooleanProperty.cs.meta b/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceBooleanProperty.cs.meta new file mode 100644 index 00000000..21fdb068 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceBooleanProperty.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: dcd5e9d7761f24131b540f069e42d80f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceBooleanProperty.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceColorProperty.cs b/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceColorProperty.cs new file mode 100644 index 00000000..cf76dd4d --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceColorProperty.cs @@ -0,0 +1,93 @@ +using System; +using System.Runtime.InteropServices; +using UnityEngine; + +namespace Rive +{ + /// + /// A view model instance property that holds a color. + /// + public sealed class ViewModelInstanceColorProperty : ViewModelInstancePrimitiveProperty + { + internal ViewModelInstanceColorProperty(IntPtr instanceValuePtr, ViewModelInstance rootInstance) : base(instanceValuePtr, rootInstance) + { + } + + private static int ColorToArgb(UnityEngine.Color color) + { + return (Mathf.RoundToInt(color.a * 255) << 24) | + (Mathf.RoundToInt(color.r * 255) << 16) | + (Mathf.RoundToInt(color.g * 255) << 8) | + Mathf.RoundToInt(color.b * 255); + } + + private static int Color32ToArgb(Color32 color) + { + return (color.a << 24) | + (color.r << 16) | + (color.g << 8) | + color.b; + } + + private static UnityEngine.Color ArgbToColor(int argb) + { + return new UnityEngine.Color( + ((argb >> 16) & 0xFF) / 255f, // R (from ARGB) + ((argb >> 8) & 0xFF) / 255f, // G (from ARGB) + (argb & 0xFF) / 255f, // B (from ARGB) + ((argb >> 24) & 0xFF) / 255f // A (from ARGB) + ); + } + + private static Color32 ArgbToColor32(int argb) + { + return new Color32( + (byte)((argb >> 16) & 0xFF), // R (from ARGB) + (byte)((argb >> 8) & 0xFF), // G (from ARGB) + (byte)(argb & 0xFF), // B (from ARGB) + (byte)((argb >> 24) & 0xFF) // A (from ARGB) + ); + } + + /// + /// Gets or sets the color value as a Unity Color. + /// + public override UnityEngine.Color Value + { + get + { + ThrowIfOwnerDisposed(); + return ArgbToColor(getViewModelInstanceColorValue(InstancePropertyPtr)); + } + set + { + ThrowIfOwnerDisposed(); + setViewModelInstanceColorValue(InstancePropertyPtr, ColorToArgb(value)); + } + } + + /// + /// Gets or sets the color value as a Color32 + /// + public Color32 Value32 + { + get + { + ThrowIfOwnerDisposed(); + return ArgbToColor32(getViewModelInstanceColorValue(InstancePropertyPtr)); + } + set + { + ThrowIfOwnerDisposed(); + setViewModelInstanceColorValue(InstancePropertyPtr, Color32ToArgb(value)); + } + } + + + [DllImport(NativeLibrary.name)] + private static extern int getViewModelInstanceColorValue(IntPtr instanceProperty); + + [DllImport(NativeLibrary.name)] + private static extern void setViewModelInstanceColorValue(IntPtr instanceProperty, int value); + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceColorProperty.cs.meta b/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceColorProperty.cs.meta new file mode 100644 index 00000000..610a230a --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceColorProperty.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 7bdf3f20b1174474299449e497069b00 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceColorProperty.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceEnumProperty.cs b/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceEnumProperty.cs new file mode 100644 index 00000000..ecedca7c --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceEnumProperty.cs @@ -0,0 +1,163 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using Rive.Utils; + +namespace Rive +{ + /// + /// A view model instance property that holds an enum. + /// + public sealed class ViewModelInstanceEnumProperty : ViewModelInstancePrimitiveProperty + { + private string[] m_enumValues; + + /// + /// Constructor for the enum property. This is used when the enum values are known ahead of time. + /// + /// The pointer to the instance property. + /// The root instance of the view model. + /// The list of enum values. + internal ViewModelInstanceEnumProperty(IntPtr instanceValuePtr, ViewModelInstance rootInstance, string[] enumValues) : base(instanceValuePtr, rootInstance) + { + m_enumValues = enumValues; + } + + /// + /// Constructor for the enum property. This is used when the enum values are not known ahead of time. + /// + /// The pointer to the instance property. + /// The root instance of the view model. + internal ViewModelInstanceEnumProperty(IntPtr instanceValuePtr, ViewModelInstance rootInstance) : base(instanceValuePtr, rootInstance) + { + PopulateEnumValuesIfNeeded(); + } + + /// + /// The current enum value of the property. + /// + public override string Value + { + get + { + ThrowIfOwnerDisposed(); + + if (InstancePropertyPtr == IntPtr.Zero) + { + DebugLogger.Instance.LogWarning("Trying to get a null enum property."); + return null; + } + + if (m_enumValues.Length == 0) + { + return null; + } + + + return m_enumValues[(int)getViewModelInstanceEnumIndex(InstancePropertyPtr)]; + } + set + { + ThrowIfOwnerDisposed(); + + int index = Array.IndexOf(m_enumValues, value); + + if (index == -1) + { + DebugLogger.Instance.LogWarning("Invalid enum value: " + value); + return; + } + + if (index < 0) + { + DebugLogger.Instance.LogWarning("Trying to set a negative enum value."); + return; + } + + setViewModelInstanceEnumIndex(InstancePropertyPtr, (uint)index); + } + } + + /// + /// The current enum value index of the property in the enum values list. + /// + internal int ValueIndex + { + get + { + ThrowIfOwnerDisposed(); + + if (InstancePropertyPtr == IntPtr.Zero) + { + DebugLogger.Instance.LogWarning("Trying to get a null enum property."); + return -1; + } + + return (int)getViewModelInstanceEnumIndex(InstancePropertyPtr); + } + set + { + ThrowIfOwnerDisposed(); + + if (value < 0 || value >= m_enumValues.Length) + { + DebugLogger.Instance.LogWarning("Invalid enum value index: " + value); + return; + } + + setViewModelInstanceEnumIndex(InstancePropertyPtr, (uint)value); + } + } + + private void PopulateEnumValuesIfNeeded() + { + if (m_enumValues == null) + { + IntPtr m_enumValuesPtr = getViewModelInstanceEnumValues(InstancePropertyPtr); + nuint valueCount = getViewModelInstanceEnumValueCount(m_enumValuesPtr); + m_enumValues = new string[(int)valueCount]; + for (nuint i = 0; i < valueCount; i++) + { + m_enumValues[i] = Marshal.PtrToStringAnsi(getViewModelInstanceEnumValueAtIndex(m_enumValuesPtr, i)); + } + + freeViewModelInstanceEnumValues(m_enumValuesPtr); + } + + } + + /// + /// The list of enum options for this property. + /// + public IReadOnlyList EnumValues + { + get + { + if (m_enumValues == null) + { + PopulateEnumValuesIfNeeded(); + } + + return m_enumValues; + } + } + + [DllImport(NativeLibrary.name)] + private static extern uint getViewModelInstanceEnumIndex(IntPtr instanceProperty); + + [DllImport(NativeLibrary.name)] + private static extern void setViewModelInstanceEnumIndex(IntPtr instanceProperty, uint value); + + [DllImport(NativeLibrary.name)] + private static extern IntPtr getViewModelInstanceEnumValues(IntPtr instanceProperty); + + [DllImport(NativeLibrary.name)] + private static extern nuint getViewModelInstanceEnumValueCount(IntPtr listPtr); + + [DllImport(NativeLibrary.name)] + private static extern IntPtr getViewModelInstanceEnumValueAtIndex(IntPtr listPtr, nuint index); + + [DllImport(NativeLibrary.name)] + private static extern void freeViewModelInstanceEnumValues(IntPtr listPtr); + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceEnumProperty.cs.meta b/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceEnumProperty.cs.meta new file mode 100644 index 00000000..cd86a99b --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceEnumProperty.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 8d4dd5b4ee8df436ebc24fa8c0b56d49 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceEnumProperty.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceImageProperty.cs b/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceImageProperty.cs new file mode 100644 index 00000000..2694654a --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceImageProperty.cs @@ -0,0 +1,83 @@ +using System; +using System.Runtime.InteropServices; +using Rive.Utils; + +namespace Rive +{ + /// + /// A view model instance property for image properties. + /// + public sealed class ViewModelInstanceImageProperty : ViewModelInstancePrimitiveProperty + { + + + public ViewModelInstanceImageProperty(IntPtr instanceValuePtr, ViewModelInstance instance) : base(instanceValuePtr, instance) + { + } + + /// + /// Sets the image asset for the property. + /// + /// The image asset to set. + public ImageOutOfBandAsset Value + { + set + { + ThrowIfOwnerDisposed(); + SetImage(value); + } + } + + /// + /// Raised when the image property is changed in the Rive graphic. + /// + public event Action OnValueChanged + { + add => AddPropertyCallback(value, ref m_onValueChanged); + remove => RemovePropertyCallback(value, ref m_onValueChanged); + } + private Action m_onValueChanged; + + /// + /// Sets the image asset for the property. + /// + /// The image asset to set. + private void SetImage(ImageOutOfBandAsset imageAsset) + { + + if (imageAsset != null && imageAsset.NativeAsset == IntPtr.Zero) + { + DebugLogger.Instance.LogWarning("Trying to assign an unloaded image asset."); + return; + } + + bool wasSuccess = setViewModelInstanceImageValue(InstancePropertyPtr, imageAsset == null ? IntPtr.Zero : imageAsset.NativeAsset); + + if (!wasSuccess) + { + DebugLogger.Instance.LogWarning("Failed to set image asset."); + } + + } + + internal override void RaiseChangedEvent() + { + m_onValueChanged?.Invoke(); + } + + internal override void ClearAllCallbacks() + { + m_onValueChanged = null; + base.ClearAllCallbacks(); + } + + internal override void ClearDelegatesOnly() + { + m_onValueChanged = null; + } + + [DllImport(NativeLibrary.name)] + private static extern bool setViewModelInstanceImageValue(IntPtr instanceProperty, + IntPtr imageAsset); + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceImageProperty.cs.meta b/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceImageProperty.cs.meta new file mode 100644 index 00000000..3e816043 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceImageProperty.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 23f3f5571d2ec47dfaefa91d59d07cde +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceImageProperty.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceListProperty.cs b/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceListProperty.cs new file mode 100644 index 00000000..5b17c90d --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceListProperty.cs @@ -0,0 +1,297 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using Rive.Utils; + +namespace Rive +{ + /// + /// A view model instance property that holds a list of view model instances. + /// + public sealed class ViewModelInstanceListProperty : ViewModelInstancePrimitiveProperty + { + + internal ViewModelInstanceListProperty(IntPtr instanceValuePtr, ViewModelInstance rootInstance) + : base(instanceValuePtr, rootInstance) + { + } + + /// + /// The number of items in the list. + /// + public int Count + { + get + { + ThrowIfOwnerDisposed(); + + if (InstancePropertyPtr == IntPtr.Zero) + { + DebugLogger.Instance.LogWarning("Trying to get length of a null list property."); + return 0; + } + return (int)getViewModelInstanceListSize(InstancePropertyPtr); + } + } + + /// + /// Gets the view model instance at the specified index. + /// + /// The index of the item to get. + /// The view model instance at the specified index, or null if the index is out of bounds. + public ViewModelInstance GetInstanceAt(int index) + { + ThrowIfOwnerDisposed(); + + if (InstancePropertyPtr == IntPtr.Zero) + { + DebugLogger.Instance.LogError("Trying to get item from a null list property."); + return null; + } + + if (index < 0 || index >= Count) + { + DebugLogger.Instance.LogError($"Index {index} is out of bounds for list of length {Count}."); + return null; + } + + IntPtr instancePtr = getViewModelInstanceListItemAt(InstancePropertyPtr, index); + if (instancePtr == IntPtr.Zero) + { + return null; + } + + ViewModelInstance vmi = GetOrCreateVMInstanceFromPtr(instancePtr); + + return vmi; + + } + + private ViewModelInstance GetOrCreateVMInstanceFromPtr(IntPtr instancePtr) + { + if (instancePtr == IntPtr.Zero) + { + return null; + } + + return ViewModelInstance.GetOrCreateFromPointer(instancePtr, this.RootInstance?.RiveFile, this.RootInstance); + } + + + + /// + /// Adds a view model instance to the end of the list. + /// + /// The view model instance to add. + public void Add(ViewModelInstance instance) + { + ThrowIfOwnerDisposed(); + + if (InstancePropertyPtr == IntPtr.Zero) + { + DebugLogger.Instance.LogError("Trying to add to a null list property."); + return; + } + + if (instance == null || instance.NativeSafeHandle.IsInvalid) + { + DebugLogger.Instance.LogError("Cannot add null or invalid view model instance to list."); + return; + } + + addViewModelInstanceToList(InstancePropertyPtr, instance.NativeSafeHandle.DangerousGetHandle()); + + instance.AddParent(this.RootInstance); + + } + + /// + /// Inserts a view model instance at the specified index. + /// + /// The view model instance to insert. + /// The index at which to insert the instance. + public void Insert(ViewModelInstance instance, int index) + { + ThrowIfOwnerDisposed(); + + if (instance == null) + { + DebugLogger.Instance.LogError("Cannot insert null or invalid view model instance into list."); + return; + } + + if (InstancePropertyPtr == IntPtr.Zero) + { + DebugLogger.Instance.LogError("Trying to insert into a null list property."); + return; + } + + if (index < 0) + { + DebugLogger.Instance.LogError($"Index {index} is out of bounds for list of length {Count}."); + return; + } + + if (!addViewModelInstanceToListAt(InstancePropertyPtr, instance.NativeSafeHandle.DangerousGetHandle(), index)) + { + DebugLogger.Instance.LogError($"Failed to insert view model instance at index {index}."); + return; + } + + instance.AddParent(this.RootInstance); + } + + /// + /// Removes a view model instance from the list. + /// + /// The view model instance to remove. + /// + /// This method will remove every occurrence of the instance from the list. + /// + public void Remove(ViewModelInstance instance) + { + ThrowIfOwnerDisposed(); + + if (InstancePropertyPtr == IntPtr.Zero) + { + DebugLogger.Instance.LogError("Trying to remove from a null list property."); + return; + } + + if (instance == null || instance.NativeSafeHandle.IsInvalid) + { + DebugLogger.Instance.LogError("Cannot remove null or invalid view model instance from list."); + return; + } + + removeViewModelInstanceFromList(InstancePropertyPtr, instance.NativeSafeHandle.DangerousGetHandle()); + + instance.RemoveParent(this.RootInstance); + + } + + /// + /// Removes the view model instance at the specified index. + /// + /// The index of the item to remove. + public void RemoveAt(int index) + { + ThrowIfOwnerDisposed(); + + if (InstancePropertyPtr == IntPtr.Zero) + { + DebugLogger.Instance.LogError("Trying to remove from a null list property."); + return; + } + + if (index < 0 || index >= Count) + { + DebugLogger.Instance.LogError($"Index {index} is out of bounds for list of length {Count}."); + return; + } + + ViewModelInstance instance = GetInstanceAt(index); + if (instance == null) + { + DebugLogger.Instance.LogError($"No instance found at index {index}."); + return; + } + + removeViewModelInstanceFromListAt(InstancePropertyPtr, index); + + } + + /// + /// Swaps the view model instances at the specified indices. + /// + /// The index of the first item to swap. + /// The index of the second item to swap. + public void Swap(int indexA, int indexB) + { + ThrowIfOwnerDisposed(); + + if (InstancePropertyPtr == IntPtr.Zero) + { + DebugLogger.Instance.LogError("Trying to swap instances in a null list property."); + return; + } + + if (indexA == indexB) + { + DebugLogger.Instance.LogError("Cannot swap instances at the same index."); + return; + } + + if (indexA < 0 || indexA >= Count) + { + DebugLogger.Instance.LogError($"Index {indexA} is out of bounds for list of length {Count}."); + return; + } + + if (indexB < 0 || indexB >= Count) + { + DebugLogger.Instance.LogError($"Index {indexB} is out of bounds for list of length {Count}."); + return; + } + + swapViewModelInstancesInList(InstancePropertyPtr, indexA, indexB); + } + + /// + /// Called when the list property value changes. + /// + internal override void RaiseChangedEvent() + { + // List changes don't have a specific value, just notify that the list changed + m_onTriggered?.Invoke(); + } + + + + /// + /// Event that is raised when the list changes. + /// + public event Action OnChanged + { + add => AddPropertyCallback(value, ref m_onTriggered); + remove => RemovePropertyCallback(value, ref m_onTriggered); + } + private Action m_onTriggered; + + + /// + /// Clears all callbacks registered with this property. + /// + internal override void ClearAllCallbacks() + { + m_onTriggered = null; + base.ClearAllCallbacks(); + } + + internal override void ClearDelegatesOnly() + { + m_onTriggered = null; + } + + [DllImport(NativeLibrary.name)] + private static extern nuint getViewModelInstanceListSize(IntPtr listProperty); + + [DllImport(NativeLibrary.name)] + private static extern IntPtr getViewModelInstanceListItemAt(IntPtr listProperty, int index); + + [DllImport(NativeLibrary.name)] + private static extern void addViewModelInstanceToList(IntPtr listProperty, IntPtr instance); + + [DllImport(NativeLibrary.name)] + private static extern bool addViewModelInstanceToListAt(IntPtr listProperty, IntPtr instance, int index); + + [DllImport(NativeLibrary.name)] + private static extern void removeViewModelInstanceFromList(IntPtr listProperty, IntPtr instance); + + [DllImport(NativeLibrary.name)] + private static extern void removeViewModelInstanceFromListAt(IntPtr listProperty, int index); + + [DllImport(NativeLibrary.name)] + private static extern void swapViewModelInstancesInList(IntPtr listProperty, int indexA, int indexB); + } +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceListProperty.cs.meta b/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceListProperty.cs.meta new file mode 100644 index 00000000..0d8dcb41 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceListProperty.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 09fb2d52775024f32a84dee326a45e35 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceListProperty.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceNumberProperty.cs b/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceNumberProperty.cs new file mode 100644 index 00000000..5a6caf3d --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceNumberProperty.cs @@ -0,0 +1,38 @@ +using System; +using System.Runtime.InteropServices; + +namespace Rive +{ + /// + /// A view model instance property that holds a number. + /// + public sealed class ViewModelInstanceNumberProperty : ViewModelInstancePrimitiveProperty + { + internal ViewModelInstanceNumberProperty(IntPtr instanceValuePtr, ViewModelInstance rootInstance) : base(instanceValuePtr, rootInstance) + { + } + + /// + /// The value of the property. + /// + public override float Value + { + get + { + ThrowIfOwnerDisposed(); + return getViewModelInstanceNumberValue(InstancePropertyPtr); + } + set + { + ThrowIfOwnerDisposed(); + setViewModelInstanceNumberValue(InstancePropertyPtr, value); + } + } + + [DllImport(NativeLibrary.name)] + private static extern float getViewModelInstanceNumberValue(IntPtr instanceProperty); + + [DllImport(NativeLibrary.name)] + private static extern void setViewModelInstanceNumberValue(IntPtr instanceProperty, float value); + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceNumberProperty.cs.meta b/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceNumberProperty.cs.meta new file mode 100644 index 00000000..7573184f --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceNumberProperty.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 2f10803c1a29a410ebcfb1731ef0cabc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceNumberProperty.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceStringProperty.cs b/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceStringProperty.cs new file mode 100644 index 00000000..2fe010a3 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceStringProperty.cs @@ -0,0 +1,64 @@ +using System; +using System.Runtime.InteropServices; + +namespace Rive +{ + /// + /// A view model instance property that holds a string. + /// + public sealed class ViewModelInstanceStringProperty : ViewModelInstancePrimitiveProperty + { + [StructLayout(LayoutKind.Sequential)] + private struct StringHashInfo + { + public IntPtr str; + public uint length; + public uint hash; + } + + private StringHashInfo m_lastInfo; + private string m_stringVal = null; + + internal ViewModelInstanceStringProperty(IntPtr instanceValuePtr, ViewModelInstance parentInstance) : base(instanceValuePtr, parentInstance) + { + } + + public override string Value + { + get + { + ThrowIfOwnerDisposed(); + StringHashInfo currentInfo = getViewModelInstanceStringInfo(InstancePropertyPtr); + + // We check if either length or hash changed before marshalling the string + // This is a performance optimization to avoid marshalling the string every frame if it hasn't changed as it allocates memory every time the value is read + // This allocation can be expensive and might cause GC spikes if done frequently + + // TODO: Since the VM Instance Runtime knows when the string changes, we should switch to using that instead instead of a hash at some point + bool stringHasChanged = currentInfo.length != m_lastInfo.length || currentInfo.hash != m_lastInfo.hash; + if (m_stringVal == null || stringHasChanged) + { + m_lastInfo = currentInfo; + + m_stringVal = Marshal.PtrToStringAnsi(currentInfo.str); + } + + return m_stringVal; + } + set + { + ThrowIfOwnerDisposed(); + setViewModelInstanceStringValue(InstancePropertyPtr, value); + } + } + + [DllImport(NativeLibrary.name)] + private static extern IntPtr getViewModelInstanceStringValue(IntPtr instanceValue); + + [DllImport(NativeLibrary.name)] + private static extern void setViewModelInstanceStringValue(IntPtr instanceValue, string value); + + [DllImport(NativeLibrary.name)] + private static extern StringHashInfo getViewModelInstanceStringInfo(IntPtr instanceValue); + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceStringProperty.cs.meta b/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceStringProperty.cs.meta new file mode 100644 index 00000000..bfbdf5a6 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceStringProperty.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: ca5f8fb25618247ff9b6588c9d075a95 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceStringProperty.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceTriggerProperty.cs b/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceTriggerProperty.cs new file mode 100644 index 00000000..18769ae5 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceTriggerProperty.cs @@ -0,0 +1,61 @@ +using System; +using System.Runtime.InteropServices; +using Rive.Utils; + +namespace Rive +{ + /// + /// A view model instance property for trigger properties. + /// + public sealed class ViewModelInstanceTriggerProperty : ViewModelInstancePrimitiveProperty + { + internal ViewModelInstanceTriggerProperty(IntPtr instanceValuePtr, ViewModelInstance rootInstance) : base(instanceValuePtr, rootInstance) + { + } + + /// + /// Raised when the trigger property is fired in the Rive graphic. + /// + public event Action OnTriggered + { + add => AddPropertyCallback(value, ref m_onTriggered); + remove => RemovePropertyCallback(value, ref m_onTriggered); + } + private Action m_onTriggered; + + /// + /// Fires the trigger + /// + public void Trigger() + { + ThrowIfOwnerDisposed(); + + if (InstancePropertyPtr == IntPtr.Zero) + { + DebugLogger.Instance.LogWarning("Trying to trigger a null trigger property."); + return; + } + + fireViewModelInstanceTrigger(InstancePropertyPtr); + } + + [DllImport(NativeLibrary.name)] + private static extern void fireViewModelInstanceTrigger(IntPtr instanceProperty); + + internal override void RaiseChangedEvent() + { + m_onTriggered?.Invoke(); + } + + internal override void ClearAllCallbacks() + { + m_onTriggered = null; + base.ClearAllCallbacks(); + } + + internal override void ClearDelegatesOnly() + { + m_onTriggered = null; + } + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceTriggerProperty.cs.meta b/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceTriggerProperty.cs.meta new file mode 100644 index 00000000..dc22d680 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceTriggerProperty.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 0243f34ec09e64cd5904a8e4c5c01bdc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/DataBinding/Values/ViewModelInstanceTriggerProperty.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/DataBinding/ViewModel.cs b/Packages/app.rive.rive-unity/Runtime/DataBinding/ViewModel.cs new file mode 100644 index 00000000..9218cc49 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/DataBinding/ViewModel.cs @@ -0,0 +1,304 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using Rive.Utils; + +namespace Rive +{ + /// + /// View models describe a set of properties, but cannot themselves be used to get or set values + /// + public sealed class ViewModel + { + private IntPtr m_modelPtr; + private string m_name; + + private ViewModelPropertyData[] m_propertyData; + + private WeakReference m_riveFile; + + private string[] m_instanceNames; + + /// + /// The names of the instances of this view model in the Rive file. + /// + public IReadOnlyList InstanceNames + { + get + { + if (m_instanceNames == null) + { + m_instanceNames = GetInstanceNames(); + } + + return m_instanceNames; + } + } + + /// + /// The number of instances of this view model in the Rive file. + /// + public int InstanceCount + { + get + { + if (m_modelPtr == IntPtr.Zero) + { + return 0; + } + + return (int)getViewModelInstanceCount(m_modelPtr); + } + } + + /// + /// The name of this view model. + /// + public string Name + { + get + { + if (m_name == null) + { + m_name = Marshal.PtrToStringAnsi(getViewModelName(m_modelPtr)); + } + + return m_name; + } + } + + /// + /// The properties of this view model. + /// + public IReadOnlyList Properties + { + get + { + if (m_propertyData == null) + { + m_propertyData = InitializeProperties(); + } + + return m_propertyData; + } + } + + internal ViewModel(IntPtr viewModelPtr, File riveFile) + + { + m_modelPtr = viewModelPtr; + m_riveFile = new WeakReference(riveFile); + } + + private ViewModelPropertyData[] InitializeProperties() + { + nuint propertyCount = getViewModelPropertyCount(m_modelPtr); + ViewModelPropertyData[] properties = new ViewModelPropertyData[propertyCount]; + + for (nuint i = 0; i < propertyCount; i++) + { + IntPtr namePtr = getViewModelPropertyNameAtIndex(m_modelPtr, i); + string name = namePtr == IntPtr.Zero ? null : Marshal.PtrToStringAnsi(namePtr); + uint type = getViewModelPropertyTypeAtIndex(m_modelPtr, i); + + properties[i] = new ViewModelPropertyData(name, (ViewModelDataType)type); + + // Free the string in memory + freeViewModelString(namePtr); + + } + + return properties; + } + + + private string[] GetInstanceNames() + { + var namesList = getViewModelInstanceNamesList(m_modelPtr); + if (namesList == IntPtr.Zero) + { + return new string[0]; + } + + int count = (int)getViewModelInstanceNamesCount(namesList); + string[] names = new string[count]; + + for (int i = 0; i < count; i++) + { + IntPtr namePtr = getViewModelInstanceNameAtIndex(namesList, (nuint)i); + names[i] = Marshal.PtrToStringAnsi(namePtr); + } + + freeViewModelInstanceNamesList(namesList); + return names; + } + + /// + /// Creates a new instance of this view model from the given pointer. This is also used to cache instances that are created from the native code to avoid creating multiple instances of the same view model that share the same pointer. + /// + /// + /// The view model instance. + private ViewModelInstance GetOrCreateInstanceFromPointer(IntPtr instanceValue) + { + if (instanceValue == IntPtr.Zero) + { + DebugLogger.Instance.LogError("Failed to create instance."); + return null; + } + + if (ViewModelInstance.TryGetCachedViewModelInstanceForPointer(instanceValue, out ViewModelInstance existingInstance)) + { + return existingInstance; + } + + ViewModelInstance newInstance = ViewModelInstance.GetOrCreateFromPointer(instanceValue, m_riveFile.TryGetTarget(out File file) ? file : null); + + return newInstance; + } + + /// + /// Instantiates a view model instance at the given index. + /// + /// The index of the instance to instantiate. + /// The view model instance at the given index. + public ViewModelInstance CreateInstanceAt(int index) + { + if (index < 0 || index >= InstanceCount) + { + DebugLogger.Instance.LogError("Invalid instance index: " + index); + return null; + } + + + IntPtr instanceValue = createViewModelInstanceAtIndex(m_modelPtr, (nuint)index); + + if (instanceValue == IntPtr.Zero) + { + DebugLogger.Instance.LogError("Failed to create instance at index: " + index); + return null; + } + + + return GetOrCreateInstanceFromPointer(instanceValue); + } + + /// + /// Instantiates an instance of this view model with the given name. + /// + /// The name of the model to instantiate. + /// + public ViewModelInstance CreateInstanceByName(string name) + { + if (name == null) + { + DebugLogger.Instance.LogError("Invalid instance name: " + name); + return null; + } + + IntPtr instanceValue = createViewModelInstanceByName(m_modelPtr, name); + + if (instanceValue == IntPtr.Zero) + { + DebugLogger.Instance.LogError("Failed to create instance with name: " + name); + return null; + } + + + return GetOrCreateInstanceFromPointer(instanceValue); + + } + + /// + /// Instantiates a default instance of this view model in the Rive file. + /// + /// The default instance of this view model. + public ViewModelInstance CreateDefaultInstance() + { + + IntPtr instanceValue = createDefaultViewModelInstance(m_modelPtr); + + if (instanceValue == IntPtr.Zero) + { + DebugLogger.Instance.LogError("Failed to create default instance."); + return null; + } + + + return GetOrCreateInstanceFromPointer(instanceValue); + + } + + + /// + /// Create a new instance of this view model. + /// + /// A new instance of this view model. + public ViewModelInstance CreateInstance() + { + + IntPtr instanceValue = createViewModelInstance(m_modelPtr); + + if (instanceValue == IntPtr.Zero) + { + DebugLogger.Instance.LogError("Failed to create instance."); + return null; + } + + return GetOrCreateInstanceFromPointer(instanceValue); + + } + + + + [DllImport(NativeLibrary.name)] + private static extern nuint getViewModelInstanceCount(IntPtr modelPtr); + + [DllImport(NativeLibrary.name)] + private static extern IntPtr getViewModelName(IntPtr modelPtr); + + [DllImport(NativeLibrary.name)] + private static extern nuint getViewModelPropertyCount(IntPtr modelPtr); + + [DllImport(NativeLibrary.name)] + private static extern IntPtr getViewModelPropertyNameAtIndex(IntPtr modelPtr, nuint index); + + [DllImport(NativeLibrary.name)] + private static extern uint getViewModelPropertyTypeAtIndex(IntPtr modelPtr, nuint index); + + #region Instance + [DllImport(NativeLibrary.name)] + private static extern IntPtr createViewModelInstanceAtIndex(IntPtr modelPtr, nuint index); + + [DllImport(NativeLibrary.name)] + private static extern IntPtr createViewModelInstanceByName(IntPtr modelPtr, string name); + + + [DllImport(NativeLibrary.name)] + private static extern IntPtr createDefaultViewModelInstance(IntPtr modelPtr); + + [DllImport(NativeLibrary.name)] + private static extern IntPtr createViewModelInstance(IntPtr modelPtr); + + + + [DllImport(NativeLibrary.name)] + private static extern IntPtr getViewModelInstanceNamesList(IntPtr modelPtr); + + [DllImport(NativeLibrary.name)] + private static extern void freeViewModelInstanceNamesList(IntPtr namesList); + + [DllImport(NativeLibrary.name)] + private static extern nuint getViewModelInstanceNamesCount(IntPtr namesList); + + [DllImport(NativeLibrary.name)] + private static extern IntPtr getViewModelInstanceNameAtIndex(IntPtr namesList, nuint index); + + + #endregion + + #region Cleanup + [DllImport(NativeLibrary.name)] + private static extern void freeViewModelString(IntPtr stringPtr); + #endregion + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/DataBinding/ViewModel.cs.meta b/Packages/app.rive.rive-unity/Runtime/DataBinding/ViewModel.cs.meta new file mode 100644 index 00000000..fff208e3 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/DataBinding/ViewModel.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 1ef6fdabbfabf4122ab7a4f432b4153d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/DataBinding/ViewModel.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/DataBinding/ViewModelDataType.cs b/Packages/app.rive.rive-unity/Runtime/DataBinding/ViewModelDataType.cs new file mode 100644 index 00000000..8177cf80 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/DataBinding/ViewModelDataType.cs @@ -0,0 +1,44 @@ +namespace Rive +{ + /// + /// The type of data that a view model property can hold. + /// + public enum ViewModelDataType : uint + { + /// None. + None = 0, + + /// String. + String = 1, + + /// Number. + Number = 2, + + /// Bool. + Boolean = 3, + + /// Color. + Color = 4, + + /// List. + List = 5, + + /// Enum. + Enum = 6, + + /// Trigger. + Trigger = 7, + + /// View Model. + ViewModel = 8, + + /// Symbol List Index. + ListIndex = 10, + + /// Image. + AssetImage = 11, + + /// Artboard. + Artboard = 12 + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/DataBinding/ViewModelDataType.cs.meta b/Packages/app.rive.rive-unity/Runtime/DataBinding/ViewModelDataType.cs.meta new file mode 100644 index 00000000..a1afc05a --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/DataBinding/ViewModelDataType.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 765b8c43d195448b09454ae146ab8c1d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/DataBinding/ViewModelDataType.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/DataBinding/ViewModelEnumData.cs b/Packages/app.rive.rive-unity/Runtime/DataBinding/ViewModelEnumData.cs new file mode 100644 index 00000000..af619210 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/DataBinding/ViewModelEnumData.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; + +namespace Rive +{ + /// + /// Represents an enum type defined in a Rive file. + /// + public sealed class ViewModelEnumData + { + + private string[] m_values; + /// + /// The name of the enum defined in the Rive file. + /// + public string Name { get; private set; } + + /// + /// The values of the enum defined in the Rive file. + /// + public IReadOnlyList Values { get { return m_values; } } + + internal string[] ValuesArray => m_values; + + /// + /// Creates a new instance of the class. + /// + /// The name of the enum. + /// The values of the enum. + internal ViewModelEnumData(string name, string[] values) + { + Name = name; + m_values = values; + } + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/DataBinding/ViewModelEnumData.cs.meta b/Packages/app.rive.rive-unity/Runtime/DataBinding/ViewModelEnumData.cs.meta new file mode 100644 index 00000000..6a67516f --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/DataBinding/ViewModelEnumData.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 0a77b1e51bc22429488c4e921bae1af0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/DataBinding/ViewModelEnumData.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/DataBinding/ViewModelInstance.cs b/Packages/app.rive.rive-unity/Runtime/DataBinding/ViewModelInstance.cs new file mode 100644 index 00000000..f0ca89ee --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/DataBinding/ViewModelInstance.cs @@ -0,0 +1,831 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using Microsoft.Win32.SafeHandles; +using Rive.Utils; + +namespace Rive +{ + /// + /// Represents a runtime instance of a view model with mutable property values. + /// A ViewModelInstance contains the same properties as its source view model but maintains its own state that can change during execution. + /// + public sealed class ViewModelInstance : ViewModelInstanceProperty, IDisposable + { + private ViewModelInstanceSafeHandle m_safeHandle; + + private WeakReference m_riveFile; + + // Strong references to subscribed properties keyed by native pointer. + // The VMI owns these so that properties survive even when the user drops their reference. + private readonly Dictionary m_subscribedProperties = new Dictionary(); + + private readonly List> m_parents = new List>(); private readonly List m_children = new List(); + + // caching nested view model instances by name + private readonly Dictionary m_viewModelInstances = new Dictionary(); + + private const char kPathSeparator = '/'; + + /// + /// Cache for split paths to avoid repeated string operations + /// + private static readonly ConcurrentDictionary s_pathSegmentsCache = new ConcurrentDictionary(); + + + private bool m_disposed = false; + + internal bool IsDisposed => m_disposed; + + private string m_viewModelName = null; + + + internal File RiveFile + { + get + { + if (m_riveFile != null && m_riveFile.TryGetTarget(out var file)) + { + return file; + } + return null; + } + } + + internal ViewModelInstanceSafeHandle NativeSafeHandle => m_safeHandle; + + internal string ViewModelName + { + get + { + if (m_viewModelName == null && !m_disposed) + { + m_viewModelName = Marshal.PtrToStringAnsi(getViewModelNameFromViewModelInstance(NativeSafeHandle)); + } + + return m_viewModelName; + } + } + + + + + private ViewModelInstance(IntPtr instanceValue, File riveFile) + { + m_safeHandle = new ViewModelInstanceSafeHandle(instanceValue); + + m_riveFile = new WeakReference(riveFile); + } + + ~ViewModelInstance() + { + Dispose(false); + } + + private static string[] GetPathSegments(string path) + { + // For very frequent calls, caching the split results can improve performance + // If the user tries to get all the properties of a view model instance, this can be called a lot + // We cache the split results to avoid repeated string operations + if (!s_pathSegmentsCache.TryGetValue(path, out var segments)) + { + segments = path.Split(kPathSeparator); + s_pathSegmentsCache[path] = segments; + } + + return segments; + } + + + private T GetPropertyFromPathSegments(string[] pathSegments, int index) where T : ViewModelInstanceProperty + { + if (index < pathSegments.Length - 1) + { + // We need to navigate to a nested view model instance so we can propagate callbacks + var nestedInstance = GetInternalViewModelInstance(pathSegments[index]); + if (nestedInstance != null) + { + return nestedInstance.GetPropertyFromPathSegments(pathSegments, index + 1); + } + else + { + return null; + } + } + + // We're at the final segment, get the property directly + return ViewModelInstancePropertyHandlersFactory.GetPrimitiveProperty(this, pathSegments[index]); + } + + private ViewModelInstance GetViewModelInstanceFromPathSegments(string[] pathSegments, int index) + { + if (index >= pathSegments.Length) + { + return this; + } + + var viewModelInstance = GetInternalViewModelInstance(pathSegments[index]); + if (viewModelInstance != null) + { + if (index == pathSegments.Length - 1) + { + return viewModelInstance; + } + else + { + return viewModelInstance.GetViewModelInstanceFromPathSegments(pathSegments, index + 1); + } + } + + return null; + } + + + private bool HasParent(ViewModelInstance parent) + { + for (int i = 0; i < m_parents.Count; i++) + { + if (m_parents[i].TryGetTarget(out var existingParent) && existingParent == parent) + { + return true; + } + } + return false; + } + + private ViewModelInstance GetInternalViewModelInstance(string name) + { + if (m_viewModelInstances.TryGetValue(name, out var instance)) + { + return instance; + } + + // Otherwise, create and cache it + var ptr = getViewModelInstanceViewModelProperty(NativeSafeHandle, name); + if (ptr != IntPtr.Zero) + { + if (TryGetCachedViewModelInstanceForPointer(ptr, out var cachedInstance)) + { + // If we have already created this instance for this pointer, use it + m_viewModelInstances[name] = cachedInstance; + + // Let's make sure the parent relationship is set + + if (!cachedInstance.HasParent(this)) + { + cachedInstance.AddParent(this); + } + + return cachedInstance; + } + + var newInstance = GetOrCreateFromPointer(ptr, RiveFile, this); + m_viewModelInstances[name] = newInstance; + + return newInstance; + } + + return null; + } + + /// + /// Gets a nested view model instance property. + /// + /// The path to the nested property. If the property is on the current instance, the path is the property name. + /// The nested view model instance property. + private ViewModelInstance GetNestedViewModelInstance(string path) + { + // Fast path for simple names (no path separator) + if (!path.Contains(kPathSeparator)) + { + return GetInternalViewModelInstance(path); + } + + string[] pathSegments = GetPathSegments(path); + return GetViewModelInstanceFromPathSegments(pathSegments, 0); + } + + + /// + /// Replaces a nested view model instance property with a new instance. + /// + /// The name of the property to replace. + /// The new view model instance to replace the property with. + /// True if the view model property was replaced, false otherwise. E.g. If the view model instance provided is for a different view model, the replacement will fail. + private bool InternalReplaceViewModel(string name, ViewModelInstance value) + { + if (value == null || value.NativeSafeHandle.IsInvalid) + { + return false; + } + + bool result = replaceViewModelInstanceViewModelProperty(NativeSafeHandle, name, value.NativeSafeHandle); + + if (result) + { + + // Clean up the old instance if it exists + if (m_viewModelInstances.TryGetValue(name, out var oldInstance)) + { + oldInstance.RemoveParent(this); + + // Remove from children list if present + if (m_children.Contains(oldInstance)) + { + m_children.Remove(oldInstance); + } + + } + + m_viewModelInstances[name] = value; + + value.AddParent(this); + } + + return result; + } + + private void ClearCallbacks() + { + foreach (var kvp in m_subscribedProperties) + { + kvp.Value.ClearDelegatesOnly(); + PropertyCallbacksHub.Instance.Unregister(kvp.Key); + } + + m_subscribedProperties.Clear(); + } + + internal void AddParent(ViewModelInstance parent) + { + // Check if parent already exists + if (HasParent(parent)) + { + return; + } + + m_parents.Add(new WeakReference(parent)); + + // If we have properties or children with callbacks, notify parent + if (m_subscribedProperties.Count > 0 || m_children.Count > 0) + { + parent.AddChildToCallbacks(this); + } + } + + internal void RemoveParent(ViewModelInstance parent) + { + for (int i = m_parents.Count - 1; i >= 0; i--) + { + if (m_parents[i].TryGetTarget(out var existingParent) && existingParent == parent) + { + parent.RemoveChildFromCallbacks(this); + m_parents.RemoveAt(i); + return; + } + } + } + + internal void AddChildToCallbacks(ViewModelInstance child) + { + if (!m_children.Contains(child)) + { + m_children.Add(child); + + // Propagate up to parents + for (int i = 0; i < m_parents.Count; i++) + { + var parent = m_parents[i]; + if (parent != null && parent.TryGetTarget(out var parentInstance) && parentInstance != null) + { + parentInstance.AddChildToCallbacks(this); + } + } + } + } + + internal void RemoveChildFromCallbacks(ViewModelInstance child) + { + m_children.Remove(child); + + // If no more children or properties need callbacks, notify parents + if (m_children.Count == 0 && m_subscribedProperties.Count == 0) + { + for (int i = 0; i < m_parents.Count; i++) + { + var parent = m_parents[i]; + if (parent != null && parent.TryGetTarget(out var parentInstance) && parentInstance != null) + { + parentInstance.RemoveChildFromCallbacks(this); + } + } + } + } + + /// + /// Called by a property when the user subscribes to it for callbacks. + /// This is used to notify parents that they need to subscribe to this property for callbacks as well. + /// + internal void RegisterPropertyForCallbacks(ViewModelInstancePrimitiveProperty property) + { + if (property == null) + { + return; + } + + IntPtr ptr = property.InstancePropertyPtr; + if (ptr == IntPtr.Zero) + { + return; + } + + bool wasFirst = m_subscribedProperties.Count == 0; + bool added = !m_subscribedProperties.ContainsKey(ptr); + + m_subscribedProperties[ptr] = property; + + PropertyCallbacksHub.Instance.Register(property); + + if (added && wasFirst) + { + for (int i = 0; i < m_parents.Count; i++) + { + var parent = m_parents[i]; + + if (parent != null && parent.TryGetTarget(out var parentInstance) && parentInstance != null) + { + parentInstance.AddChildToCallbacks(this); + } + } + } + } + + /// + /// Called by a property when it transitions from non-zero to zero subscribers. + /// + internal void UnregisterPropertyForCallbacks(ViewModelInstancePrimitiveProperty property) + { + if (property == null) + { + return; + } + + IntPtr ptr = property.InstancePropertyPtr; + if (ptr != IntPtr.Zero) + { + m_subscribedProperties.Remove(ptr); + PropertyCallbacksHub.Instance.Unregister(ptr); + } + + // If no more properties with callbacks and no children with callbacks, notify parents + if (m_subscribedProperties.Count == 0 && m_children.Count == 0) + { + for (int i = 0; i < m_parents.Count; i++) + { + var parent = m_parents[i]; + if (parent != null && parent.TryGetTarget(out var parentInstance) && parentInstance != null) + { + parentInstance.RemoveChildFromCallbacks(this); + } + } + } + } + + + /// + /// Gets a cached nested view model instance for a given pointer. This is used to avoid creating multiple C# instances of the same underlying native instance. + /// + internal static bool TryGetCachedViewModelInstanceForPointer(IntPtr ptr, out ViewModelInstance instance) + { + if (ViewModelInstanceProperty.TryGetGloballyCachedVMPropertyForPointer(ptr, out var property)) + { + instance = property as ViewModelInstance; + + if (instance != null) + { + return true; + } + return false; + } + + instance = null; + return false; + } + + /// + /// Removes a cached view model instance for a given pointer. + /// /// + internal static void RemoveGloballyCachedViewModelInstanceForPointer(IntPtr ptr) + { + ViewModelInstanceProperty.RemoveCachedPropertyForPointer(ptr); + } + + + /// + /// Adds a cached view model instance for a given pointer. This is used to avoid creating multiple C# instances of the same underlying native instance. + /// + /// + /// + internal static void AddCachedViewModelInstanceForPointer(IntPtr ptr, ViewModelInstance instance) + { + ViewModelInstanceProperty.AddGloballyCachedVMPropertyForPointer(ptr, instance); + } + + + /// + /// Gets a property of the view model instance. + /// + /// The type of the property to get. + /// The path to the property. If the property is on the current instance, the path is the property name. + /// The path can be a nested path, e.g. "nestedInstance/propertyName". + /// The property of the view model instance. + public T GetProperty(string path) where T : ViewModelInstanceProperty + { + if (string.IsNullOrEmpty(path)) + { + DebugLogger.Instance.LogError("Property path cannot be null or empty"); + return null; + } + + if (m_disposed) + { + throw new ObjectDisposedException(nameof(ViewModelInstance), "Cannot get property from a disposed ViewModelInstance."); + } + + // Handle ViewModelInstance type specially since we do a few things differently for non-primitive properties + if (typeof(T) == typeof(ViewModelInstance)) + { + return GetNestedViewModelInstance(path) as T; + } + + // Fast path for simple property names (no nested path separator) + if (!path.Contains(kPathSeparator)) + { + return ViewModelInstancePropertyHandlersFactory.GetPrimitiveProperty(this, path); + } + + string[] pathSegments = GetPathSegments(path); + return GetPropertyFromPathSegments(pathSegments, 0); + } + + /// + /// Detects property value changes + /// Call this after advancing wherever you handle your per-frame logic. + /// + public void HandleCallbacks() + { + if (m_disposed) + { + return; + } + + foreach (var kvp in m_subscribedProperties) + { + var prop = kvp.Value; + if (prop.HasChanged) + { + prop.RaiseChangedEvent(); + } + } + + foreach (var kvp in m_subscribedProperties) + { + var prop = kvp.Value; + if (prop.HasChanged) + { + prop.ClearChanges(); + } + } + + // Propagate to children + for (int i = 0; i < m_children.Count; i++) + { + m_children[i]?.HandleCallbacks(); + } + } + + /// + /// Replaces a nested view model instance property with a new instance. + /// + /// The path to the property to replace. + /// The new instance to replace the property with. + public void SetViewModelInstance(string path, ViewModelInstance newInstance) + { + if (m_disposed) + { + throw new ObjectDisposedException(nameof(ViewModelInstance), "Cannot set view model instance on a disposed ViewModelInstance."); + } + + if (string.IsNullOrEmpty(path)) + { + DebugLogger.Instance.LogError("Property path cannot be null or empty"); + return; + } + + bool wasReplaced = false; + // Fast path for simple names (no path separator) + if (!path.Contains(kPathSeparator)) + { + wasReplaced = InternalReplaceViewModel(path, newInstance); + + if (!wasReplaced) + { + DebugLogger.Instance.LogError($"Failed to replace nested view model instance property at path: {path}. The property may not exist or the new instance may be of a different view model type."); + } + return; + } + + string[] pathSegments = GetPathSegments(path); + + ViewModelInstance currentViewModel = this; + + // Navigate to the parent of the target instance (all segments except the last) + for (int i = 0; i < pathSegments.Length - 1; i++) + { + currentViewModel = currentViewModel.GetInternalViewModelInstance(pathSegments[i]); + if (currentViewModel == null) + { + DebugLogger.Instance.LogError($"View model not found at segment '{pathSegments[i]}' in path: {path}"); + return; + } + } + + // Now currentViewModel is the parent of our target, so lets replace the final segment + wasReplaced = currentViewModel.InternalReplaceViewModel( + pathSegments[pathSegments.Length - 1], + newInstance); + + if (!wasReplaced) + { + DebugLogger.Instance.LogError($"Failed to replace nested view model instance property at path: {path}. The property may not exist or the new instance may be of a different view model type."); + } + + + } + + + #region Convenience methods + /// + /// Gets a number property of the view model instance. + /// + /// The path to the property. + /// The number property, or null if the property doesn't exist or is not a number. + public ViewModelInstanceNumberProperty GetNumberProperty(string path) + { + return GetProperty(path); + } + + /// + /// Gets a boolean property of the view model instance. + /// + /// The path to the property. + /// The boolean property, or null if the property doesn't exist or is not a boolean. + public ViewModelInstanceBooleanProperty GetBooleanProperty(string path) + { + return GetProperty(path); + } + + /// + /// Gets a string property of the view model instance. + /// + /// The path to the property. + /// The string property, or null if the property doesn't exist or is not a string. + public ViewModelInstanceStringProperty GetStringProperty(string path) + { + return GetProperty(path); + } + + /// + /// Gets a color property of the view model instance. + /// + /// The path to the property. + /// The color property, or null if the property doesn't exist or is not a color. + public ViewModelInstanceColorProperty GetColorProperty(string path) + { + return GetProperty(path); + } + + /// + /// Gets an enum property of the view model instance. + /// + /// The path to the property. + /// The enum property, or null if the property doesn't exist or is not an enum. + public ViewModelInstanceEnumProperty GetEnumProperty(string path) + { + return GetProperty(path); + } + + /// + /// Gets a trigger property of the view model instance. + /// + /// The path to the property. + /// The trigger property, or null if the property doesn't exist or is not a trigger. + public ViewModelInstanceTriggerProperty GetTriggerProperty(string path) + { + return GetProperty(path); + } + + /// + /// Gets an image property of the view model instance. + /// + /// The path to the property. + /// The image property, or null if the property doesn't exist or is not an image. + public ViewModelInstanceImageProperty GetImageProperty(string path) + { + return GetProperty(path); + } + + /// + /// Gets a list property of the view model instance. + /// + /// The path to the property. + /// The list property, or null if the property doesn't exist or is not a list. + public ViewModelInstanceListProperty GetListProperty(string path) + { + return GetProperty(path); + } + + /// + /// Gets an artboard property of the view model instance. + /// + /// The path to the property. + /// The artboard property, or null if the property doesn't exist or is not an artboard. + public ViewModelInstanceArtboardProperty GetArtboardProperty(string path) + { + return GetProperty(path); + } + + /// + /// Gets a nested view model instance property. + /// + /// The path to the property. + /// The nested view model instance, or null if the property doesn't exist or is not a view model. + public ViewModelInstance GetViewModelInstanceProperty(string path) + { + return GetProperty(path); + } + #endregion + + private void Dispose(bool disposing) + { + if (m_disposed) + { + return; + } + + if (disposing) + { + // ClearCallbacks() is intentionally only called on the explicit Dispose() path. + // On the finalizer path, the managed objects in m_subscribedProperties may already be finalized, + // and taking the lock inside PropertyCallbacksHub.Unregister() from a finalizer thread risks deadlocks. + // The hub uses weak references, so the hub won't keep the properties alive. It will also clean up any dead properties during the next CaptureChanges() call. + ClearCallbacks(); + + foreach (var kvp in m_viewModelInstances) + { + var childViewModelInstance = kvp.Value; + childViewModelInstance.RemoveParent(this); + } + + m_viewModelInstances.Clear(); + + for (int i = m_parents.Count - 1; i >= 0; i--) + { + if (m_parents[i].TryGetTarget(out var parentInstance) && parentInstance != null) + { + RemoveParent(parentInstance); + } + } + + m_children.Clear(); + } + + if (m_safeHandle != null && !m_safeHandle.IsInvalid) + { + // Get the IntPtr for cache removal before disposing + IntPtr nativePtr = m_safeHandle.DangerousGetHandle(); + m_safeHandle.Dispose(); + + RemoveGloballyCachedViewModelInstanceForPointer(nativePtr); + } + + m_disposed = true; + + if (disposing) + { + GC.SuppressFinalize(this); + } + } + + public void Dispose() + { + Dispose(true); + } + + /// + /// Helper method to get or create a ViewModelInstance from a native pointer. + /// This method checks if the instance already exists in the cache. If it does, it returns the existing instance so that a single C# instance is always used for the same native instance no matter which method returns it. + /// If it doesn't exist, it creates a new ViewModelInstance and adds it to the cache. + /// + /// The native pointer to the ViewModelInstance. + /// The Rive file associated with the ViewModelInstance. This is used to resolve the file context for the instance. + /// The parent ViewModelInstance, if any. The parent is used to propagate callbacks to this instance. A vm instance can have multiple parents. + /// The ViewModelInstance associated with the native pointer. + internal static ViewModelInstance GetOrCreateFromPointer(IntPtr instancePtr, File riveFile, ViewModelInstance parent = null) + { + if (TryGetCachedViewModelInstanceForPointer(instancePtr, out ViewModelInstance existingInstance)) + { + // Unity already owns this - balance the extra ref from underlying native methods. + // If we don't do this, the native instance might stay in memory longer than intended. + ViewModelInstanceSafeHandle.unrefViewModelInstance(instancePtr); + if (parent != null) + { + existingInstance.AddParent(parent); + } + return existingInstance; + } + + var newInstance = new ViewModelInstance(instancePtr, riveFile); + if (parent != null) + { + newInstance.AddParent(parent); + } + AddCachedViewModelInstanceForPointer(instancePtr, newInstance); + return newInstance; + } + + + + #region Native Calls + + + [DllImport(NativeLibrary.name)] + private static extern nuint getViewModelInstancePropertyCount(ViewModelInstanceSafeHandle instanceValue); + + [DllImport(NativeLibrary.name)] + private static extern IntPtr getViewModelInstancePropertyAtPath(ViewModelInstanceSafeHandle instanceValue, string path); + + + + + [DllImport(NativeLibrary.name)] + private static extern IntPtr getViewModelInstanceViewModelProperty(ViewModelInstanceSafeHandle instanceValue, string path); + + + + + [DllImport(NativeLibrary.name)] + private static extern IntPtr getViewModelNameFromViewModelInstance(ViewModelInstanceSafeHandle instanceValue); + + + /// + /// Replaces a nested view model instance property with a new instance. + /// + /// The instance that contains the property to replace. + /// The path to the property to replace. + /// The new instance to replace the property with. + /// True if the view model property was replaced, false otherwise. E.g. If the view model instance provided is for a different view model, the + /// replacement will fail. + [DllImport(NativeLibrary.name)] + private static extern bool replaceViewModelInstanceViewModelProperty( + ViewModelInstanceSafeHandle baseInstanceValue, + string path, + ViewModelInstanceSafeHandle newInstance); + + + #endregion + } + + /// + /// SafeHandle implementation for ViewModelInstance native resources + /// + internal sealed class ViewModelInstanceSafeHandle : SafeHandleZeroOrMinusOneIsInvalid + { + // The P/Invoke marshaller throws ArgumentNullException if a SafeHandle argument is null. + // We use this reusable invalid handle to represent IntPtr.Zero for optional parameters. + internal static readonly ViewModelInstanceSafeHandle Null = new ViewModelInstanceSafeHandle(); + + public ViewModelInstanceSafeHandle() : base(true) + { + } + + public ViewModelInstanceSafeHandle(IntPtr handle) : base(true) + { + SetHandle(handle); + } + + protected override bool ReleaseHandle() + { + if (!IsInvalid) + { + unrefViewModelInstance(handle); + return true; + } + return false; + } + + [DllImport(NativeLibrary.name)] + internal static extern void unrefViewModelInstance(IntPtr instancePtr); + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/DataBinding/ViewModelInstance.cs.meta b/Packages/app.rive.rive-unity/Runtime/DataBinding/ViewModelInstance.cs.meta new file mode 100644 index 00000000..e0482fc3 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/DataBinding/ViewModelInstance.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: b65d74517d2274b9e8c55e3161e8725f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/DataBinding/ViewModelInstance.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/DataBinding/ViewModelInstancePrimitiveProperty.cs b/Packages/app.rive.rive-unity/Runtime/DataBinding/ViewModelInstancePrimitiveProperty.cs new file mode 100644 index 00000000..0d9ab3cb --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/DataBinding/ViewModelInstancePrimitiveProperty.cs @@ -0,0 +1,218 @@ +using System; +using System.Runtime.InteropServices; +using Rive.Utils; + +namespace Rive +{ + /// + /// Base class for all primitive properties of a ViewModelInstance. This is usually used for types like numbers, strings, etc. that have a value change event. + /// + public abstract class ViewModelInstancePrimitiveProperty : ViewModelInstanceProperty + { + private IntPtr m_instanceValuePropertyPtr; + private ViewModelInstance m_instance; // The instance this property belongs to + + internal IntPtr InstancePropertyPtr => m_instanceValuePropertyPtr; + + /// + /// The instance this property belongs to. + /// + internal ViewModelInstance RootInstance => m_instance; + + /// + /// Throws if the owning has been disposed. + /// + protected void ThrowIfOwnerDisposed() + { + if (m_instance != null && m_instance.IsDisposed) + { + throw new ObjectDisposedException( + nameof(ViewModelInstance), + $"Cannot access {GetType().Name}: the owning ViewModelInstance has been disposed."); + } + } + + /// + /// Whether the value has changed since the last time it was read. + /// + internal bool HasChanged => viewModelInstancePropertyValueHasChanged(m_instanceValuePropertyPtr); + + /// + /// Constructor for a ViewModelInstanceProperty. + /// + /// Pointer to the instance property value. + /// The instance this property belongs to. + internal ViewModelInstancePrimitiveProperty(IntPtr instanceValuePtr, ViewModelInstance instance) + { + m_instanceValuePropertyPtr = instanceValuePtr; + m_instance = instance; + } + + ~ViewModelInstancePrimitiveProperty() + { + if (m_instanceValuePropertyPtr != IntPtr.Zero) + { + ViewModelInstanceProperty.RemoveCachedPropertyForPointer(m_instanceValuePropertyPtr); + m_instanceValuePropertyPtr = IntPtr.Zero; + } + } + + /// + /// Reset the changed flag for this value. + /// + internal void ClearChanges() + { + clearViewModelInstancePropertyValueChanges(m_instanceValuePropertyPtr); + } + + /// + /// Called by ViewModelInstance when it detects this property has changed. + /// + internal virtual void RaiseChangedEvent() + { + // no-op in non-generic base; override in subclasses + } + + /// + /// Clears this property's callbacks and performs the normal cleanup path. + /// Use this when the property is unsubscribing itself, because it also tells + /// the owning to unregister the property. + /// + internal virtual void ClearAllCallbacks() + { + // If we've removed all subscribers, unregister + m_instance?.UnregisterPropertyForCallbacks(this); + } + + /// + /// Clears only this property's stored callback delegates. + /// Unlike , this does not unregister the property + /// from its owning . + /// This is used by because that + /// method is already walking the subscribed properties and handling hub cleanup + /// itself. Calling the full unregister path there would change the collection + /// while it is being looped over. + /// + internal virtual void ClearDelegatesOnly() + { + } + + internal void RegisterForCallbacks() + { + + // Since we don't clean the changed flag for properties that don't have listeners, + // we clean it the first time we add a listener to it + ClearChanges(); + m_instance.RegisterPropertyForCallbacks(this); + } + + internal void UnregisterForCallbacks() + { + m_instance.UnregisterPropertyForCallbacks(this); + } + + [DllImport(NativeLibrary.name)] + private static extern bool viewModelInstancePropertyValueHasChanged(IntPtr instanceValue); + + [DllImport(NativeLibrary.name)] + private static extern void clearViewModelInstancePropertyValueChanges(IntPtr instanceValue); + + // Helpers to add/remove managed callbacks and register/unregister native notifications + /// + /// Adds a callback handler and, if first subscriber, clears stale changes and registers native callbacks. + /// + /// The callback to invoke when this property changes. + /// Reference to the private delegate field storing subscribers. + protected void AddPropertyCallback(Action handler, ref Action backingField) + { + ThrowIfOwnerDisposed(); + bool wasEmpty = backingField == null; + backingField += handler; + if (wasEmpty) + { + ClearChanges(); + RegisterForCallbacks(); + } + } + + /// + /// Removes a callback handler and, if no subscribers remain, unregisters native callbacks. + /// + /// The callback to remove. + /// Reference to the private delegate field storing subscribers. + protected void RemovePropertyCallback(Action handler, ref Action backingField) + { + backingField -= handler; + if (backingField == null) + { + UnregisterForCallbacks(); + } + } + + /// + /// Adds a typed callback handler and, if first subscriber, clears changes and registers native callbacks. + /// + protected void AddPropertyCallback(Action handler, ref Action backingField) + { + ThrowIfOwnerDisposed(); + bool wasEmpty = backingField == null; + backingField += handler; + if (wasEmpty) + { + ClearChanges(); + RegisterForCallbacks(); + } + } + + /// + /// Removes a typed callback handler and unregisters native callbacks if no subscribers remain. + /// + protected void RemovePropertyCallback(Action handler, ref Action backingField) + { + backingField -= handler; + if (backingField == null) + { + UnregisterForCallbacks(); + } + } + } + + /// + /// Generic subclass of ViewModelInstancePrimitiveProperty for primitive types. This class allows you to register a callback for when the value changes and provides a typed Value property. + /// + /// The type of the value. + /// This class is used for primitive types like strings, numbers, etc. + public abstract class ViewModelInstancePrimitiveProperty : ViewModelInstancePrimitiveProperty + { + /// + /// Event raised when the value changes, passing the new value. + /// + public event Action OnValueChanged + { + add => AddPropertyCallback(value, ref m_onValueChanged); + remove => RemovePropertyCallback(value, ref m_onValueChanged); + } + private Action m_onValueChanged; + + internal ViewModelInstancePrimitiveProperty(IntPtr instanceValuePtr, ViewModelInstance instance) + : base(instanceValuePtr, instance) { } + + internal override void RaiseChangedEvent() + { + m_onValueChanged?.Invoke(Value); + } + + internal override void ClearAllCallbacks() + { + m_onValueChanged = null; + base.ClearAllCallbacks(); + } + + internal override void ClearDelegatesOnly() + { + m_onValueChanged = null; + } + + public abstract T Value { get; set; } + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/DataBinding/ViewModelInstancePrimitiveProperty.cs.meta b/Packages/app.rive.rive-unity/Runtime/DataBinding/ViewModelInstancePrimitiveProperty.cs.meta new file mode 100644 index 00000000..15cc9e26 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/DataBinding/ViewModelInstancePrimitiveProperty.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 4344b52c58a344bd7bc787a3e3763d68 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/DataBinding/ViewModelInstancePrimitiveProperty.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/DataBinding/ViewModelInstanceProperty.cs b/Packages/app.rive.rive-unity/Runtime/DataBinding/ViewModelInstanceProperty.cs new file mode 100644 index 00000000..5a177d79 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/DataBinding/ViewModelInstanceProperty.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Concurrent; + +namespace Rive +{ + /// + /// Base class representing any value that can be a property of a ViewModelInstance. + /// This includes both primitive property values and nested view model instances. + /// + public abstract class ViewModelInstanceProperty + { + /// + /// Cache of property instances to avoid creating multiple instances for the same native property + /// + private static readonly ConcurrentDictionary> s_propertiesCache = + new ConcurrentDictionary>(); + + /// + /// Adds a globally cached view model property for a given pointer. + /// + /// The pointer to the property. + /// The C# property to cache. + internal static void AddGloballyCachedVMPropertyForPointer(IntPtr ptr, ViewModelInstanceProperty property) + { + s_propertiesCache[ptr] = new WeakReference(property); + } + + /// + /// Tries to get a globally cached view model property for a given pointer. + /// + /// The pointer to the property. + /// The C# property to cache. + /// + internal static bool TryGetGloballyCachedVMPropertyForPointer(IntPtr ptr, out ViewModelInstanceProperty property) + { + if (s_propertiesCache.TryGetValue(ptr, out var weakReference) && + weakReference.TryGetTarget(out property)) + { + return true; + } + + property = null; + return false; + } + + /// + /// Removes a cached view model property for a given pointer. + /// /// + /// The pointer to the property. + internal static void RemoveCachedPropertyForPointer(IntPtr ptr) + { + s_propertiesCache.TryRemove(ptr, out _); + } + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/DataBinding/ViewModelInstanceProperty.cs.meta b/Packages/app.rive.rive-unity/Runtime/DataBinding/ViewModelInstanceProperty.cs.meta new file mode 100644 index 00000000..fc6bbfbd --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/DataBinding/ViewModelInstanceProperty.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 35d4e0b7873b44d9bb270a14412eed23 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/DataBinding/ViewModelInstanceProperty.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/DataBinding/ViewModelPropertyData.cs b/Packages/app.rive.rive-unity/Runtime/DataBinding/ViewModelPropertyData.cs new file mode 100644 index 00000000..14f836ca --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/DataBinding/ViewModelPropertyData.cs @@ -0,0 +1,32 @@ +namespace Rive +{ + /// + /// Holds data about a view model property. + /// + public readonly struct ViewModelPropertyData + { + + private readonly string m_name; + + + private readonly ViewModelDataType m_type; + + + /// + /// The name of the property. + /// + public string Name => m_name; + + + /// + /// The type of the property. + /// + public ViewModelDataType Type => m_type; + + internal ViewModelPropertyData(string name, ViewModelDataType type) + { + m_name = name; + m_type = type; + } + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/DataBinding/ViewModelPropertyData.cs.meta b/Packages/app.rive.rive-unity/Runtime/DataBinding/ViewModelPropertyData.cs.meta new file mode 100644 index 00000000..16857803 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/DataBinding/ViewModelPropertyData.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 53eb422cb1b654a808feb86c5766ef29 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/DataBinding/ViewModelPropertyData.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/EditorOnly.meta b/Packages/app.rive.rive-unity/Runtime/EditorOnly.meta new file mode 100644 index 00000000..41599f30 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/EditorOnly.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5ddc353d8e1a54441a9bbf3eccea486f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Runtime/EditorOnly/InspectorDocLinks.cs b/Packages/app.rive.rive-unity/Runtime/EditorOnly/InspectorDocLinks.cs new file mode 100644 index 00000000..d8ee684e --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/EditorOnly/InspectorDocLinks.cs @@ -0,0 +1,58 @@ +using System; + +namespace Rive.EditorTools +{ +#if UNITY_EDITOR + /// + /// Central place for inspector help/documentation links. + /// Keep these as const so they can be used in attributes. + /// + internal static class InspectorDocLinks + { + // Fundamentals + public const string AddingRiveAssets = "https://rive.app/docs/game-runtimes/unity/fundamentals?ref=unity-inspector#adding-rive-assets"; + + public const string Artboards = "https://rive.app/docs/game-runtimes/unity/fundamentals?ref=unity-inspector#artboards"; + + public const string StateMachines = "https://rive.app/docs/game-runtimes/unity/fundamentals?ref=unity-inspector#state-machines"; + + public const string FitAndAlignment = "https://rive.app/docs/game-runtimes/unity/layouts?ref=unity-inspector#fit-and-alignment"; + public const string HitTesting = "https://rive.app/docs/game-runtimes/unity/listeners?ref=unity-inspector#hit-testing"; + + public const string LayoutScalingModes = "https://rive.app/docs/game-runtimes/unity/layouts?ref=unity-inspector#layout-scaling-modes"; + + public const string LayoutScaleFactor = "https://rive.app/docs/game-runtimes/unity/layouts?ref=unity-inspector#layout-scale-factor"; + + // Data Binding + public const string UnityDataBindingOverview = "https://rive.app/docs/game-runtimes/unity/data-binding?ref=unity-inspector#data-binding-overview"; + + + // Components + public const string RiveWidget = "https://rive.app/docs/game-runtimes/unity/components?ref=unity-inspector#rive-widget"; + + public const string RivePanel = "https://rive.app/docs/game-runtimes/unity/components?ref=unity-inspector#rive-panel"; + + public const string RenderTargetStrategies = "https://rive.app/docs/game-runtimes/unity/components?ref=unity-inspector#render-target-strategies"; + + public const string RiveCanvasRenderer = "https://rive.app/docs/game-runtimes/unity/components?ref=unity-inspector#rive-canvas-renderer"; + + public const string RiveTextureRenderer = "https://rive.app/docs/game-runtimes/unity/components?ref=unity-inspector#rive-texture-renderer"; + + // Data Binding Playground / Docs + public const string UnityDataBinding = "https://rive.app/docs/game-runtimes/unity/data-binding?ref=unity-inspector"; + public const string UnityDataBindingProperties = "https://rive.app/docs/runtimes/data-binding?ref=unity-inspector#properties"; + public const string UnityDataBindingViewModel = "https://rive.app/docs/runtimes/data-binding?ref=unity-inspector#view-models"; + public const string UnityDataBindingImages = "https://rive.app/docs/runtimes/data-binding?ref=unity-inspector#images"; + public const string UnityDataBindingLists = "https://rive.app/docs/runtimes/data-binding?ref=unity-inspector#lists"; + public const string UnityDataBindingArtboards = "https://rive.app/docs/runtimes/data-binding?ref=unity-inspector#artboards"; + public const string UnityDataBindingEnums = "https://rive.app/docs/runtimes/data-binding?ref=unity-inspector#enums"; + public const string UnityDataBindingListViewModelIndex = "https://rive.app/docs/editor/data-binding/lists?ref=unity-inspector#view-model-list-item-index"; + + // Welcome window / onboarding + public const string UnityGettingStarted = "https://rive.app/docs/game-runtimes/unity/getting-started?ref=unity-inspector"; + public const string RiveWebsite = "https://rive.app/?ref=unity-inspector"; + public const string RiveUnitySupport = "https://github.com/rive-app/rive-unity/issues"; + } +#endif +} + diff --git a/Packages/app.rive.rive-unity/Runtime/EditorOnly/InspectorDocLinks.cs.meta b/Packages/app.rive.rive-unity/Runtime/EditorOnly/InspectorDocLinks.cs.meta new file mode 100644 index 00000000..187d1f97 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/EditorOnly/InspectorDocLinks.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 83bc76198e6fb49778c43f18dee7fd4b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/EditorOnly/InspectorDocLinks.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/EmbeddedAsset.cs b/Packages/app.rive.rive-unity/Runtime/EmbeddedAsset.cs new file mode 100644 index 00000000..02272fab --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/EmbeddedAsset.cs @@ -0,0 +1,88 @@ +using System; +using Rive.Utils; +using UnityEngine; + +namespace Rive +{ + /// + /// Represents the type of an embedded asset in a Rive asset. + /// + public enum EmbeddedAssetType : ushort + { + Unknown = 0, + Image = 105, + Font = 141, + Audio = 406, + Script = 529 + } + + /// + /// Represents information about inband/out of band asset (OOB) that is embedded/referenced in a Rive asset. + /// + [Serializable] + public class EmbeddedAssetData + { + [SerializeField] + private EmbeddedAssetType m_AssetType; + + [SerializeField] + private uint m_Id; + + [SerializeField] + private string m_Name; + + [SerializeField] + private uint m_AssetSizeInBytes; + + [SerializeField] + private OutOfBandAsset m_OutOfBandAsset; + + + /// + /// The type of the embedded asset. + /// + public EmbeddedAssetType AssetType { get { return m_AssetType; } } + + /// + /// The unique identifier of the embedded asset. + /// + public uint Id { get { return m_Id; } } + + /// + /// The name of the embedded asset. + /// + public string Name { get { return m_Name; } } + + /// + /// The size of the bytes embedded in the asset. If the asset is only referenced (not embedded), this will be 0. + /// + public uint InBandBytesSize { get { return m_AssetSizeInBytes; } } + + /// + /// The out of band asset that is referenced by this embedded asset. + /// + public OutOfBandAsset OutOfBandAsset { get { return m_OutOfBandAsset; } internal set { m_OutOfBandAsset = value; } } + + + /// + /// Creates a new EmbeddedAssetData instance. + /// + /// The type of the embedded asset. + /// The unique identifier of the embedded asset. + /// The name of the embedded asset. + /// The number of bytes in the embedded asset. + public EmbeddedAssetData(EmbeddedAssetType assetType, uint id, string name, uint assetSizeInBytes) + { + m_AssetType = assetType; + m_Id = id; + m_Name = name; + m_AssetSizeInBytes = assetSizeInBytes; + } + + + } + + + + +} diff --git a/Packages/app.rive.rive-unity/Runtime/EmbeddedAsset.cs.meta b/Packages/app.rive.rive-unity/Runtime/EmbeddedAsset.cs.meta new file mode 100644 index 00000000..6aa69bad --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/EmbeddedAsset.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: f3079c28a17fd4bbe9c66b990c8c6416 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/EmbeddedAsset.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/EmbeddedAssetDataLoader.cs b/Packages/app.rive.rive-unity/Runtime/EmbeddedAssetDataLoader.cs new file mode 100644 index 00000000..6b4f7fbb --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/EmbeddedAssetDataLoader.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using Rive.Utils; + + +namespace Rive +{ + /// + /// Utility class for loading embedded asset data from a Rive file's byte data. + /// + internal class EmbeddedAssetDataLoader + { + public const string ERROR_CODE_RIVE_FILE_BYTES_NULL_OR_EMPTY = "RIVE_FILE_BYTES_NULL_OR_EMPTY"; + + + public EmbeddedAssetDataLoader() + { + } + + + /// + /// Load the embedded assets from a Rive file's byte data. + /// + /// The bytes of the Rive file. + /// An enumerable of embedded assets. + public IEnumerable LoadEmbeddedAssetDataFromRiveFileBytes(byte[] riveFileBytes) + { + + if (riveFileBytes == null || riveFileBytes.Length == 0) + { + DebugLogger.Instance.LogError(ERROR_CODE_RIVE_FILE_BYTES_NULL_OR_EMPTY + " - The Rive file bytes are null or empty."); + yield break; + } + + + IntPtr listPtr = IntPtr.Zero; + try + { + listPtr = loadEmbeddedAssetList(riveFileBytes, (nuint)riveFileBytes.Length); + nuint assetCount = getEmbeddedAssetCount(listPtr); + + for (nuint i = 0; i < assetCount; i++) + { + string name = Marshal.PtrToStringAnsi(getEmbeddedAssetName(listPtr, i)); + ushort type = getEmbeddedAssetType(listPtr, i); + var assetType = Enum.IsDefined(typeof(EmbeddedAssetType), type) + ? (EmbeddedAssetType)type + : EmbeddedAssetType.Unknown; + uint id = getEmbeddedAssetId(listPtr, i); + uint embeddedBytes = (uint)getEmbeddedAssetSize(listPtr, i); + var embeddedAsset = new EmbeddedAssetData(assetType, id, name, embeddedBytes); + + yield return embeddedAsset; + } + } + finally + { + if (listPtr != IntPtr.Zero) + { + deleteEmbeddedAssetList(listPtr); + } + } + } + + + #region Native Methods + [DllImport(NativeLibrary.name)] + internal static extern IntPtr loadEmbeddedAssetList(byte[] bytes, nuint byteCount); + + [DllImport(NativeLibrary.name)] + internal static extern void deleteEmbeddedAssetList(IntPtr list); + + [DllImport(NativeLibrary.name)] + internal static extern nuint getEmbeddedAssetCount(IntPtr list); + + [DllImport(NativeLibrary.name)] + internal static extern IntPtr getEmbeddedAssetName(IntPtr riveFile, nuint index); + + [DllImport(NativeLibrary.name)] + internal static extern ushort getEmbeddedAssetType(IntPtr riveFile, nuint index); + + [DllImport(NativeLibrary.name)] + internal static extern uint getEmbeddedAssetId(IntPtr riveFile, nuint index); + + [DllImport(NativeLibrary.name)] + internal static extern nuint getEmbeddedAssetSize(IntPtr riveFile, nuint index); + #endregion + } +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Runtime/EmbeddedAssetDataLoader.cs.meta b/Packages/app.rive.rive-unity/Runtime/EmbeddedAssetDataLoader.cs.meta new file mode 100644 index 00000000..83d60677 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/EmbeddedAssetDataLoader.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 576f219f9975d4cd7826ed88e7c555e5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/EmbeddedAssetDataLoader.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/EmbeddedAssetReference.cs b/Packages/app.rive.rive-unity/Runtime/EmbeddedAssetReference.cs new file mode 100644 index 00000000..f8c6b83d --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/EmbeddedAssetReference.cs @@ -0,0 +1,223 @@ +using System; +using Rive.Utils; + +namespace Rive +{ + + + /// + /// Represents a file asset within a specific Rive file. + /// + public abstract class EmbeddedAssetReference + { + + internal struct InitializationData + { + public EmbeddedAssetType AssetType { get; } + public uint Id { get; } + public string Name { get; } + public uint InBandBytesSize { get; } + public OutOfBandAsset OutOfBandAsset { get; } + public uint IndexInRiveFile { get; } + + public InitializationData(EmbeddedAssetType assetType, uint id, string name, uint inBandBytesSize, uint indexInRiveFile, OutOfBandAsset outOfBandAsset) + { + AssetType = assetType; + Id = id; + Name = name; + InBandBytesSize = inBandBytesSize; + OutOfBandAsset = outOfBandAsset; + IndexInRiveFile = indexInRiveFile; + } + + public static InitializationData FromEmbeddedAssetData(EmbeddedAssetData embeddedAssetData, uint index) + { + return new InitializationData(embeddedAssetData.AssetType, embeddedAssetData.Id, embeddedAssetData.Name, embeddedAssetData.InBandBytesSize, index, embeddedAssetData.OutOfBandAsset); + } + } + + public class WarningCodes + { + public const string FILE_NOT_LOADED = "RIVE_FILE_NOT_YET_LOADED"; + + public const string FILE_RELEASED = "RIVE_FILE_RELEASED"; + + public const string NULL_OOB_ASSET = "NULL_OOB_ASSET"; + } + + + private EmbeddedAssetType m_assetType = EmbeddedAssetType.Unknown; + + private uint m_Id; + + private string m_Name; + + private uint m_EmbeddededBytesSize; + + + /// + /// The index of the embedded asset in the Rive file. + /// + private uint m_Index; + + private WeakReference loadedFileReference; + + private OutOfBandAsset m_OutOfBandAssetToLoad; + + + /// + /// The type of the embedded asset. + /// + public EmbeddedAssetType AssetType { get { return m_assetType; } } + + /// + /// The unique identifier of the embedded asset. + /// + public uint Id { get { return m_Id; } } + + /// + /// The name of the embedded asset. + /// + public string Name { get { return m_Name; } } + + /// + /// The size of the bytes embedded in the asset. If the asset is only referenced (not embedded), this will be 0. + /// + public uint EmbeddededBytesSize { get { return m_EmbeddededBytesSize; } } + + /// + /// The out of band asset that will be loaded when the asset is needed. + /// + [Obsolete("Use OutOfBandAsset instead.")] + public OutOfBandAsset OutOfBandAssetToLoad { get { return m_OutOfBandAssetToLoad; } } + + /// + /// The index of the embedded/referenced asset in the Rive file. + /// + [Obsolete] + public uint IndexInRiveFile { get { return m_Index; } } + + /// + /// The index of the embedded/referenced asset in the Rive file. + /// + internal uint Index { get { return m_Index; } } + + public OutOfBandAsset OutOfBandAsset { get { return m_OutOfBandAssetToLoad; } } + + + [Obsolete] + public EmbeddedAssetReference(EmbeddedAssetData embeddedAssetData, uint index) + { + m_assetType = embeddedAssetData.AssetType; + m_Id = embeddedAssetData.Id; + m_Name = embeddedAssetData.Name; + m_EmbeddededBytesSize = embeddedAssetData.InBandBytesSize; + m_Index = index; + m_OutOfBandAssetToLoad = embeddedAssetData.OutOfBandAsset; + } + + [Obsolete] + public EmbeddedAssetReference(EmbeddedAssetType assetType, uint id, string name, uint embeddededBytesSize, uint indexInRiveFile, OutOfBandAsset outOfBandAsset) + { + m_assetType = assetType; + m_Id = id; + m_Name = name; + m_EmbeddededBytesSize = embeddededBytesSize; + m_Index = indexInRiveFile; + m_OutOfBandAssetToLoad = outOfBandAsset; + } + + + + + + internal EmbeddedAssetReference(InitializationData initializationData) + { + m_assetType = initializationData.AssetType; + m_Id = initializationData.Id; + m_Name = initializationData.Name; + m_EmbeddededBytesSize = initializationData.InBandBytesSize; + m_Index = initializationData.IndexInRiveFile; + m_OutOfBandAssetToLoad = initializationData.OutOfBandAsset; + } + + + + + /// + /// Sets the loaded file reference for this embedded asset, so we can update the asset reference later. + /// + /// + internal void SetRiveFileReference(File file) + { + loadedFileReference = new WeakReference(file); + } + + protected void UpdateEmbeddedAssetReferenceInFile(OutOfBandAsset outOfBandAsset) + { + if (outOfBandAsset == null) + { + DebugLogger.Instance.LogWarning($"{WarningCodes.NULL_OOB_ASSET}: Tried to update embedded asset reference in file, but the out of band asset is null."); + return; + } + + if (loadedFileReference == null) + { + DebugLogger.Instance.LogWarning($"{WarningCodes.FILE_NOT_LOADED}: Tried to update embedded asset reference in file, but the file has not been loaded yet."); + return; + } + + if (loadedFileReference.TryGetTarget(out Rive.File file)) + { + file.UpdateEmbeddedAssetReference(m_Index, outOfBandAsset); + m_OutOfBandAssetToLoad = outOfBandAsset; + + } + else + { + loadedFileReference = null; + DebugLogger.Instance.LogWarning($"{WarningCodes.FILE_RELEASED}: Tried to update embedded asset reference in file, but the file has already been released."); + } + + + } + + /// + /// Checks if the embedded asset reference has a file reference set. + /// + /// + internal bool HasFileReference() + { + return loadedFileReference != null && loadedFileReference.TryGetTarget(out Rive.File file); + } + + + /// + /// Empties the embedded asset reference value in the Rive file. This is used if the asset at this index had embedded bytes. + /// + internal void ClearEmbeddedAssetReference() + { + if (loadedFileReference == null) + { + DebugLogger.Instance.LogWarning($"{WarningCodes.FILE_NOT_LOADED}: Tried to clear embedded asset reference in file, but the file has not been loaded yet."); + return; + } + + if (loadedFileReference.TryGetTarget(out Rive.File file)) + { + NativeFileInterface.clearAssignedAssetReferenceValue(file.NativeFile, m_Index); + + } + else + { + loadedFileReference = null; + DebugLogger.Instance.LogWarning($"{WarningCodes.FILE_RELEASED}: Tried to clear embedded asset reference in file, but the file has already been released."); + } + + } + + + } + + +} diff --git a/Packages/app.rive.rive-unity/Runtime/EmbeddedAssetReference.cs.meta b/Packages/app.rive.rive-unity/Runtime/EmbeddedAssetReference.cs.meta new file mode 100644 index 00000000..681e7c1e --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/EmbeddedAssetReference.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 66d76c21bad09452fa629d31fc5b38ca +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/EmbeddedAssetReference.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/FallbackFileAssetLoader.cs b/Packages/app.rive.rive-unity/Runtime/FallbackFileAssetLoader.cs new file mode 100644 index 00000000..0379875f --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/FallbackFileAssetLoader.cs @@ -0,0 +1,421 @@ +using System; +using System.Collections.Generic; +using Rive.Utils; + + +namespace Rive +{ + + internal interface IFallbackFileAssetLoader + { + void AddLoader(IFileAssetLoader loader); + IntPtr NativeUnityAssetLoaderCallback(uint assetId, ushort assetType, string assetName, uint inBandByteSize); + void LoadOutOfBandAssets(File riveFile); + void UnloadInternallyLoadedAssets(); + } + + + + /// + /// The FallbackFileAssetLoader is the brain of the asset loading system. It is responsible for loading embedded assets from a Rive file and keeping track of which assets it loaded. It also accepts a list of IFileAssetLoader instances to load the assets. If an asset is not loaded by any of the loaders, then it will handle the loading itself. + /// + internal class FallbackFileAssetLoader : IFileAssetLoader, IFallbackFileAssetLoader + { + public static class LogCodes + { + public const string ERROR_UNSUPPORTED_ASSET_TYPE = "UNSUPPORTED_ASSET_TYPE"; + public const string ERROR_ASSET_DATA_SET_FAILED = "FAILED_TO_SET_ASSET_DATA"; + + public const string ERROR_ASSET_TYPE_MISMATCH = "ASSET_TYPE_MISMATCH"; + + public const string ERROR_ASSET_LOADING_FAILED = "ASSET_LOADING_ERROR"; + + public const string ERROR_NULL_LOADER = "NULL_LOADER_PROVIDED"; + + } + private List loaders = new List(); + + public List Loaders => loaders; + + /// + /// A map of the out of band assets that this loader was responsible for loading/decoding. The key is the ID of the embedded asset. This is used to unload the assets when the Rive file is unloaded. + /// + Dictionary m_loadedOobAssets = new(); + + + /// + /// A map of referenced out of band assets to load if the the user doesn't handle the loading themselves with the callback approach. We mostly need to use this for situations where the user is loading from a Rive Asset which has referenced images assigned in the Unity inspector. + /// In this case, some users might want the assigned values to be used if they don't handle the loading themselves, so this lets us handle that. + /// + Dictionary m_fallbackReferenceAssetMap; + + + public void AddLoader(IFileAssetLoader loader) + { + if (loader == null) + { + DebugLogger.Instance.LogError($"{LogCodes.ERROR_NULL_LOADER}: Can't add null to the list of loaders."); + return; + } + loaders.Add(loader); + } + + + /// + /// Stores a mapping of asset id to asset reference. This is used to load the asset data when the Rive file is loaded. + /// + private Dictionary assetReferenceMap = new Dictionary(); + + + public FallbackFileAssetLoader() + { + } + + + public FallbackFileAssetLoader(IEnumerable fallbackReferenceAssetData) + { + + if (fallbackReferenceAssetData == null) + { + return; + } + + m_fallbackReferenceAssetMap = new Dictionary(); + + foreach (var assetData in fallbackReferenceAssetData) + { + if (assetData.OutOfBandAsset != null) + { + m_fallbackReferenceAssetMap[assetData.Id] = assetData.OutOfBandAsset; + } + } + } + + + + /// + /// Generate the asset map bytes from the preloaded cache. This is used to load the assets when the Rive file is loaded with the asset data known ahead of time or without a callback. + /// + /// The asset map bytes. + public byte[] GenerateAssetMapBytesFromEmbeddedAssets(IEnumerable embeddedAssetData) + { + List assetMap = new List(); + + if (embeddedAssetData == null) + { + return assetMap.ToArray(); + } + + foreach (var assetData in embeddedAssetData) + { + if (assetData.OutOfBandAsset != null) + { + // Load the asset if it isn't in the cache + if (!m_loadedOobAssets.ContainsKey(assetData.Id)) + { + assetData.OutOfBandAsset.Load(); + // Add the asset to the cache so we can unload it when the Rive file is unloaded + this.AddToOobAssetCache(assetData.Id, assetData.OutOfBandAsset); + } + + assetData.OutOfBandAsset.LoadIntoByteAssetMap(assetData.Id, assetData.AssetType, assetMap); + } + } + + return assetMap.ToArray(); + } + + + private EmbeddedAssetReference GenerateAssetReference(uint assetId, ushort assetType, string assetName, uint inBandByteSize, OutOfBandAsset outOfBandAsset, uint indexInRiveFile) + { + + EmbeddedAssetType type = (EmbeddedAssetType)assetType; + + EmbeddedAssetReference.InitializationData initializationData = new EmbeddedAssetReference.InitializationData( + assetType: type, + id: assetId, + name: assetName, + inBandBytesSize: inBandByteSize, + indexInRiveFile: indexInRiveFile, + outOfBandAsset: outOfBandAsset + ); + + switch (type) + { + case EmbeddedAssetType.Font: + return new FontEmbeddedAssetReference(initializationData); + case EmbeddedAssetType.Image: + return new ImageEmbeddedAssetReference(initializationData); + case EmbeddedAssetType.Audio: + return new AudioEmbeddedAssetReference(initializationData); + default: + DebugLogger.Instance.LogError($"{LogCodes.ERROR_UNSUPPORTED_ASSET_TYPE}: Can't generate asset reference due to unsupported asset type: {type}"); + return null; + } + } + + /// + /// The native callback that is called when the Rive runtime needs to load an embedded asset. This is used to get information about the embedded assets. + /// + /// + /// + /// + /// + /// A pointer to the native asset to use, otherwise a null pointer. + public IntPtr NativeUnityAssetLoaderCallback(uint assetId, ushort assetType, string assetName, uint inBandByteSize) + { + // We use the native callback to get information about the embedded/referenced assets. + // Even though we have this information when an asset is imported into the Unity Editor, this is needed because we don't have the details about embedded assets when they're loaded remotely + // This gives us that information so we can load and set the assets at runtime right after the Rive file is loaded. + + // Don't call any native code from the plugin that uses a lock in this callback, because it will cause a deadlock + // For example, we can't call decodeFont here because it uses a lock. This is why we use the assetMapArray approach for assets that are known ahead of time, as those don't require a callback and are loaded before the Rive file is loaded. + + var assetIndexInRiveFile = assetReferenceMap.Count; + + var preloadedOutofBandAsset = this.GetLoadedOobAsset(assetId); + + + var assetReference = GenerateAssetReference(assetId, assetType, assetName, inBandByteSize, preloadedOutofBandAsset, (uint)assetIndexInRiveFile); + + + if (assetReference == null) + { + return System.IntPtr.Zero; + + } + + // Add the asset reference to the map so we can load the asset data when the Rive file is loaded if needed. + assetReferenceMap[assetId] = assetReference; + + + + // If no asset was preloaded, then return a null native asset. This tells the native runtime to handle the asset loading. + if (preloadedOutofBandAsset == null || assetReference == null) + { + return System.IntPtr.Zero; + + } + + + + // If the asset was preloaded, then return the native asset to the runtime. + return assetReference.OutOfBandAsset == null ? System.IntPtr.Zero : assetReference.OutOfBandAsset.NativeAsset; + + + + + } + + + + + /// + /// Load the contents of the asset reference. If the asset is not loaded by any of the loaders, then it will handle the loading itself. + /// + /// + /// Returns true if the asset was loaded by this loader. Otherwise, returns false. + public bool LoadContents(EmbeddedAssetReference assetReference) + { + // Try to load using other loaders first + if (TryLoadWithOtherLoaders(assetReference)) + { + // If the user chose to handle it, but no oob asset was loaded/assigned, then we clear the asset reference in the rive file + // If we don't do this, for example, the embedded image will be visible in the rive file, but it shouldn't be because the user technically chose to handle it + if (assetReference.OutOfBandAsset == null && assetReference.EmbeddededBytesSize > 0) + { + assetReference.ClearEmbeddedAssetReference(); + } + return true; + } + + // We check if the asset was already preloaded during the assetLoad callback + if (GetLoadedOobAsset(assetReference.Id) != null) + { + return false; // Asset already loaded, so we don't bother loading it again + } + + + + // Load the out of band asset if available + return LoadOutOfBandAsset(assetReference); + } + + private bool TryLoadWithOtherLoaders(EmbeddedAssetReference assetReference) + { + for (int i = 0; i < loaders.Count; i++) + { + var loader = loaders[i]; + if (loader is IFileAssetLoader fileLoader && fileLoader.LoadContents(assetReference)) + { + return true; + } + } + return false; + } + + /// + /// Load the out of band asset for the asset reference. + /// + /// + /// Returns true if the asset was loaded successfully. Otherwise, returns false. + public bool LoadOutOfBandAsset(EmbeddedAssetReference assetReference) + { + + OutOfBandAsset outOfBandAssetToLoad = assetReference.OutOfBandAsset; + + // If the user didn't handle the loading, and a default asset is available, then we assign it to the asset reference + if (outOfBandAssetToLoad == null && m_fallbackReferenceAssetMap != null && m_fallbackReferenceAssetMap.TryGetValue(assetReference.Id, out OutOfBandAsset fallbackAsset)) + { + outOfBandAssetToLoad = fallbackAsset; + } + + + + if (outOfBandAssetToLoad == null) + { + return false; + } + + bool success = false; + + outOfBandAssetToLoad.Load(); + + try + { + + if (SetAssetReferenceData(assetReference, outOfBandAssetToLoad)) + { + AddToOobAssetCache(assetReference.Id, outOfBandAssetToLoad); + success = true; + } + else + { + DebugLogger.Instance.LogError($"{LogCodes.ERROR_ASSET_DATA_SET_FAILED}: Failed to set asset reference for asset {assetReference.Id} of type {assetReference.AssetType}."); + } + } + catch (Exception ex) + { + DebugLogger.Instance.LogError($"{LogCodes.ERROR_ASSET_LOADING_FAILED}: Failed to load asset {assetReference.Id} of type {assetReference.AssetType}. Error: {ex.Message}"); + + } + finally + { + if (!success) + { + // Unload the asset if anything went wrong + outOfBandAssetToLoad.Unload(); + + } + } + + return success; + } + + private bool SetAssetReferenceData(EmbeddedAssetReference assetReference, OutOfBandAsset outOfBandAsset) + { + switch (assetReference.AssetType) + { + case EmbeddedAssetType.Font: + if (assetReference is FontEmbeddedAssetReference fontRef && outOfBandAsset is FontOutOfBandAsset fontAsset) + { + fontRef.SetFont(fontAsset); + return true; + } + break; + case EmbeddedAssetType.Image: + if (assetReference is ImageEmbeddedAssetReference imageRef && outOfBandAsset is ImageOutOfBandAsset imageAsset) + { + imageRef.SetImage(imageAsset); + return true; + } + break; + case EmbeddedAssetType.Audio: + if (assetReference is AudioEmbeddedAssetReference audioRef && outOfBandAsset is AudioOutOfBandAsset audioAsset) + { + audioRef.SetAudio(audioAsset); + return true; + } + break; + default: + DebugLogger.Instance.LogError($"{LogCodes.ERROR_UNSUPPORTED_ASSET_TYPE}: Unable to set asset reference due to unsupported asset type: {assetReference.AssetType}"); + return false; + } + + DebugLogger.Instance.LogError($"{LogCodes.ERROR_ASSET_TYPE_MISMATCH}: Failed to set asset reference for type {assetReference.AssetType}. Asset reference or out-of-band asset is of incorrect type."); + return false; + } + + + + /// + /// Get the loaded out of band asset by it's owning asset ID. + /// + /// + /// The loaded out of band asset, otherwise null. + public OutOfBandAsset GetLoadedOobAsset(uint assetId) + { + if (m_loadedOobAssets.TryGetValue(assetId, out OutOfBandAsset asset)) + { + return asset; + } + return null; + } + + /// + /// Load the out of band assets into the Rive file. If a custom loader is provided, then it will be used to load the assets. If not, then the loader will handle the loading itself. + /// + /// + public void LoadOutOfBandAssets(File riveFile) + { + foreach (var assetReferencePair in assetReferenceMap) + { + var assetReference = assetReferencePair.Value; + assetReference.SetRiveFileReference(riveFile); + this.LoadContents(assetReference); + + } + } + + /// + /// Unload all the out of band assets that were loaded by this loader. + /// + public void UnloadInternallyLoadedAssets() + { + foreach (var assetValuePair in m_loadedOobAssets) + { + OutOfBandAsset asset = assetValuePair.Value; + asset.Unload(); + } + m_loadedOobAssets.Clear(); + } + + + /// + /// Adds a loaded out of band asset to the cache along with the asset ID. + /// + /// + /// + private void AddToOobAssetCache(uint assetId, OutOfBandAsset outOfBandAsset) + { + m_loadedOobAssets[assetId] = outOfBandAsset; + } + + /// + /// Get the asset reference by it's owning asset ID. + /// + /// + /// The asset reference, otherwise null. + public EmbeddedAssetReference GetAssetReference(uint assetId) + { + if (assetReferenceMap.TryGetValue(assetId, out EmbeddedAssetReference assetReference)) + { + return assetReference; + } + return null; + } + + + + } +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Runtime/FallbackFileAssetLoader.cs.meta b/Packages/app.rive.rive-unity/Runtime/FallbackFileAssetLoader.cs.meta new file mode 100644 index 00000000..c6110317 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/FallbackFileAssetLoader.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: c605d1e1af7a44a13988f5c49b188639 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/FallbackFileAssetLoader.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/FileLoader.cs b/Packages/app.rive.rive-unity/Runtime/FileLoader.cs new file mode 100644 index 00000000..29f021df --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/FileLoader.cs @@ -0,0 +1,284 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using Rive.Utils; + +namespace Rive +{ + /// + /// A utility class for loading Rive files with referenced or embedded assets. + /// + internal class FileLoader + { + + public static class LogCodes + { + public const string ERROR_EMPTY_RIVE_FILE_BYTES = "RIVE_FILE_BYTES_NULL_OR_EMPTY"; + public const string ERROR_RIVE_FILE_LOAD_FAILED = "RIVE_FILE_LOAD_FAILED"; + + } + private readonly ConcurrentDictionary FileRef, int RefCount)> m_activeFiles = new(); + + + + + public FileLoader() + { + } + + + /// + /// Load a Rive file with embedded asset info available in the Unity project. + /// + /// + /// + /// + /// + /// + internal File LoadWithKnownAssets( + byte[] riveFileByteContents, + int? cacheId, + IEnumerable embeddedAssets) + { + if (!ValidateInput(riveFileByteContents)) + { + return null; + } + + if (cacheId.HasValue) + { + var cacheResult = GetFileFromCache(cacheId.Value); + if (cacheResult != null) + { + IncrementRefCount(cacheId.Value); + return cacheResult; + } + } + + var fallbackAssetLoader = new FallbackFileAssetLoader(); + var assetMap = fallbackAssetLoader.GenerateAssetMapBytesFromEmbeddedAssets(embeddedAssets); + + var file = LoadFileAndAssets(() => + { + return LoadNativeFileWithAssetMap(riveFileByteContents, assetMap, fallbackAssetLoader, cacheId); + }, fallbackAssetLoader); + + if (file != null && cacheId.HasValue) + { + m_activeFiles[cacheId.Value] = (new WeakReference(file), 1); + } + + return file; + } + + /// + /// Load a Rive file with a custom asset loader callback. Use this method if you want to load a file that isn't available within the Unity project. + /// + /// + /// + /// + /// + internal File LoadFileWithCallback( + byte[] riveFileByteContents, + File.CustomAssetLoaderCallback customAssetLoaderCallback, + IEnumerable fallbackAssets = null) + + { + + if (!ValidateInput(riveFileByteContents)) + { + return null; + } + + + var fallbackAssetLoader = new FallbackFileAssetLoader(fallbackAssets); + if (customAssetLoaderCallback != null) + { + fallbackAssetLoader.AddLoader(new CustomFileAssetLoader(customAssetLoaderCallback)); + } + + return LoadFileAndAssets(() => + { + return LoadNativeFileWithCallback(riveFileByteContents, fallbackAssetLoader); + }, fallbackAssetLoader); + } + + private bool ValidateInput(byte[] riveFileByteContents) + { + if (riveFileByteContents == null || riveFileByteContents.Length == 0) + { + DebugLogger.Instance.LogError($"{LogCodes.ERROR_EMPTY_RIVE_FILE_BYTES}: The provided Rive file bytes are null or empty. If you're loading from a remote file, make sure you're using the correct path and that the file exists."); + return false; + } + return true; + } + + /// + /// Get a file from the cache if it's already loaded. + /// + /// + /// + private File GetFileFromCache(int id) + { + if (m_activeFiles.TryGetValue(id, out var fileInfo) && fileInfo.FileRef.TryGetTarget(out File activeFile)) + { + return activeFile; + } + m_activeFiles.TryRemove(id, out _); + return null; + } + + + private File LoadFileAndAssets(Func loadFile, FallbackFileAssetLoader fallbackAssetLoader) + { + try + { + var file = loadFile(); + + if (file == null) + { + DebugLogger.Instance.LogError($"{LogCodes.ERROR_RIVE_FILE_LOAD_FAILED}: Failed to load Rive file. Make sure the file is valid and not corrupted."); + // We unload the out-of-band assets we loaded here because we don't want to keep them in memory if the file failed to load. + fallbackAssetLoader.UnloadInternallyLoadedAssets(); + return null; + } + + return file; + } + catch (Exception ex) + { + DebugLogger.Instance.LogException(ex); + fallbackAssetLoader.UnloadInternallyLoadedAssets(); + return null; + } + } + + private File LoadNativeFileWithCallback(byte[] riveFileByteContents, FallbackFileAssetLoader fallbackAssetLoader) + { + NativeFileInterface.s_NativeFileAssetLoader = fallbackAssetLoader; + IntPtr filePtr = NativeFileInterface.loadRiveFileWithUnityCallback(riveFileByteContents, (uint)riveFileByteContents.Length, NativeFileInterface.AssetLoaderCallback); + + if (filePtr == IntPtr.Zero) + { + return null; + } + + // We don't pass the cacheId here because we expect that if the user is using a custom asset loader callback, they will want the callback to be called every time. In that case, the user is responsible for reusing the file if they want to. + var file = new File(filePtr, null, fallbackAssetLoader); + + // Then we load the out-of-band assets after. We can't do this during the actual asset loader callback because of potential deadlocks when calling native rive code within the callback (which already has a lock). + // This will call the asset loader callback for each asset and allow the user to load the asset in their own way. It's safe to load the assets here because we're not in the callback anymore. + fallbackAssetLoader.LoadOutOfBandAssets(file); + + + + return file; + } + + private File LoadNativeFileWithAssetMap(byte[] riveFileByteContents, byte[] assetMap, FallbackFileAssetLoader fallbackAssetLoader, int? cacheId) + { + // We call the native load function with the asset map. This will provide the native file with the necessary information to load the assets. + IntPtr filePtr = NativeFileInterface.loadRiveFile( + riveFileByteContents, + (uint)riveFileByteContents.Length, + assetMap, + (uint)assetMap.Length + ); + + if (filePtr == IntPtr.Zero) + { + return null; + } + + var file = new File(filePtr, cacheId, fallbackAssetLoader); + + if (cacheId.HasValue) + { + m_activeFiles[cacheId.Value] = (new WeakReference(file), 1); + } + + return file; + + + } + + /// + /// Increment the reference count for a file. + /// + /// + internal void IncrementRefCount(int assetKey) + { + if (m_activeFiles.TryGetValue(assetKey, out var fileInfo)) + { + m_activeFiles[assetKey] = (fileInfo.FileRef, fileInfo.RefCount + 1); + } + } + + /// + /// Decrement the reference count for a file. If the reference count reaches 0, the file is unloaded. + /// + /// + /// Returns true if the file is still being referenced after decrementing. Otherwise, returns false. + internal bool DecrementRefCount(int assetKey) + { + if (m_activeFiles.TryGetValue(assetKey, out var fileInfo)) + { + int newRefCount = fileInfo.RefCount - 1; + if (newRefCount > 0) + { + m_activeFiles[assetKey] = (fileInfo.FileRef, newRefCount); + return true; + } + else + { + if (fileInfo.FileRef.TryGetTarget(out var file)) + { + + ReleaseFile(file); + m_activeFiles.TryRemove(assetKey, out _); + return false; + } + } + } + return false; + } + + + + /// + /// Release a file + /// + /// The file to release. + internal void ReleaseFile(File file) + { + if (file != null) + { + + + if (file.AssetKey.HasValue) + { + m_activeFiles.TryRemove(file.AssetKey.Value, out _); + } + + if (file.NativeFile == IntPtr.Zero) + { + return; + } + + NativeFileInterface.unrefRiveFile(file.NativeFile); + if (file.FallbackFileAssetLoader != null) + { + // Unload any out-of-band assets that the fallback loader was responsible for loading. + // This doesn't unload the assets the user loaded themselves because they might still be in use elsewhere. + file.FallbackFileAssetLoader.UnloadInternallyLoadedAssets(); + } + + } + } + + + + } + + +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Runtime/FileLoader.cs.meta b/Packages/app.rive.rive-unity/Runtime/FileLoader.cs.meta new file mode 100644 index 00000000..68a4bbfd --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/FileLoader.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 799ef80e1ed07495899f3bc178ba2c7c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/FileLoader.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Fit.cs b/Packages/app.rive.rive-unity/Runtime/Fit.cs new file mode 100644 index 00000000..8d90c28b --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Fit.cs @@ -0,0 +1,69 @@ +namespace Rive +{ + /// + /// Fit determines how the Rive content will be fitted to the view. + /// + public enum Fit : byte + { + /// + /// Rive content will fill the available bounds. + /// + /// If the aspect ratios differ, then the Rive + /// content will be stretched. + /// + Fill = 0, + + /// + /// (Default) Rive content will be contained within the bounds, + /// preserving the aspect ratio. + /// + /// If the ratios differ, then a portion of the bounds will + /// be unused. + /// + Contain = 1, + + /// + /// Rive will cover the bounds, preserving the aspect ratio. + /// + /// If the Rive content has a different ratio to the bounds, + /// then the Rive content will be clipped. + /// + Cover = 2, + + /// + /// Rive content will fill to the width of the bounds. + /// + /// This may result in clipping or unfilled bound space. + /// + FitWidth = 3, + + /// + /// Rive content will fill to the height of the bounds. + /// + /// This may result in clipping or unfilled bound space. + /// + FitHeight = 4, + + /// + /// Rive content will render to the size of its artboard, + /// which may result in clipping or unfilled bound space. + /// + None = 5, + + /// + /// Rive content is scaled down to the size of the bounds, + /// preserving the aspect ratio. + /// + /// This is equivalent to Contain when the content is larger + /// than the bounds. If the bounds is larger, then ScaleDown + /// will not scale up. + /// + ScaleDown = 6, + + /// + /// Rive content will be resized automatically based on layout constraints of the artboard. + /// + Layout = 7 + + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/Fit.cs.meta b/Packages/app.rive.rive-unity/Runtime/Fit.cs.meta new file mode 100644 index 00000000..3f4f9686 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Fit.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 980e7c13bee464c159ad67ceee8ca16f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Fit.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/FontEmbeddedAssetReference.cs b/Packages/app.rive.rive-unity/Runtime/FontEmbeddedAssetReference.cs new file mode 100644 index 00000000..7e1b15cc --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/FontEmbeddedAssetReference.cs @@ -0,0 +1,37 @@ +namespace Rive +{ + + + /// + /// Represents a Font file asset reference within a specific Rive file. + /// + public class FontEmbeddedAssetReference : EmbeddedAssetReference + { + [System.Obsolete] + public FontEmbeddedAssetReference(EmbeddedAssetData embeddedAssetData, uint index) + : base(embeddedAssetData, index) + { + } + + [System.Obsolete] + public FontEmbeddedAssetReference(EmbeddedAssetType assetType, uint id, string name, uint embeddededBytesSize, uint index, OutOfBandAsset outOfBandAsset) : base(assetType, id, name, embeddededBytesSize, index, outOfBandAsset) + { + } + + internal FontEmbeddedAssetReference(InitializationData initializationData) : base(initializationData) + { + } + + /// + /// Updates the font asset reference in the Rive file. + /// + /// + public void SetFont(FontOutOfBandAsset fontAsset) + { + this.UpdateEmbeddedAssetReferenceInFile(fontAsset); + + } + } + + +} diff --git a/Packages/app.rive.rive-unity/Runtime/FontEmbeddedAssetReference.cs.meta b/Packages/app.rive.rive-unity/Runtime/FontEmbeddedAssetReference.cs.meta new file mode 100644 index 00000000..93ac0d37 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/FontEmbeddedAssetReference.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 7f4edcf04f27d474f9cbc544a4133b4b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/FontEmbeddedAssetReference.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/FontOutOfBandAsset.cs b/Packages/app.rive.rive-unity/Runtime/FontOutOfBandAsset.cs new file mode 100644 index 00000000..91cc3d05 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/FontOutOfBandAsset.cs @@ -0,0 +1,29 @@ +using System; +using System.Runtime.InteropServices; + +namespace Rive +{ + /// + /// Represents an out-of-band Rive font asset. + /// + public class FontOutOfBandAsset : OutOfBandAsset + { + protected override IntPtr LoadNative(byte[] data) + { + return loadRiveFont(data, (nuint)data.Length); + } + + protected override void UnloadNative(IntPtr nativePtr) + { + unrefRiveFont(nativePtr); + } + + #region Native Methods + [DllImport(NativeLibrary.name)] + private static extern IntPtr loadRiveFont(byte[] bytes, nuint byteCount); + + [DllImport(NativeLibrary.name)] + private static extern void unrefRiveFont(IntPtr font); + #endregion + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/FontOutOfBandAsset.cs.meta b/Packages/app.rive.rive-unity/Runtime/FontOutOfBandAsset.cs.meta new file mode 100644 index 00000000..4e88b358 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/FontOutOfBandAsset.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 3aa3afe05b0e24df2875fc3582125ee6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: df0df084c4eaa4149a9c988c71b85313, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/FontOutOfBandAsset.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/HitResult.cs b/Packages/app.rive.rive-unity/Runtime/HitResult.cs new file mode 100644 index 00000000..6af1eaf2 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/HitResult.cs @@ -0,0 +1,12 @@ +namespace Rive +{ + /// + /// Represents the result of a hit test. + /// + public enum HitResult + { + None = 0, + Hit = 1, + HitOpaque = 2 + } +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Runtime/HitResult.cs.meta b/Packages/app.rive.rive-unity/Runtime/HitResult.cs.meta new file mode 100644 index 00000000..af61a873 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/HitResult.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 73be9c7fc58194421b77868e9a25a21e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/HitResult.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/ImageEmbeddedAssetReference.cs b/Packages/app.rive.rive-unity/Runtime/ImageEmbeddedAssetReference.cs new file mode 100644 index 00000000..4caf7977 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/ImageEmbeddedAssetReference.cs @@ -0,0 +1,37 @@ +namespace Rive +{ + + + /// + /// Represents an Image file asset reference within a specific Rive file. + /// + public class ImageEmbeddedAssetReference : EmbeddedAssetReference + { + [System.Obsolete] + public ImageEmbeddedAssetReference(EmbeddedAssetData embeddedAssetData, uint index) + : base(embeddedAssetData, index) + { + } + + [System.Obsolete] + public ImageEmbeddedAssetReference(EmbeddedAssetType assetType, uint id, string name, uint embeddededBytesSize, uint index, OutOfBandAsset outOfBandAsset) : base(assetType, id, name, embeddededBytesSize, index, outOfBandAsset) + { + } + + internal ImageEmbeddedAssetReference(InitializationData initializationData) : base(initializationData) + { + } + + + /// + /// Updates the image asset reference in the Rive file. + /// + /// + public void SetImage(ImageOutOfBandAsset imageAsset) + { + this.UpdateEmbeddedAssetReferenceInFile(imageAsset); + } + } + + +} diff --git a/Packages/app.rive.rive-unity/Runtime/ImageEmbeddedAssetReference.cs.meta b/Packages/app.rive.rive-unity/Runtime/ImageEmbeddedAssetReference.cs.meta new file mode 100644 index 00000000..36b0e0be --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/ImageEmbeddedAssetReference.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 5c8c55c195cee4b1e8df11092ca46e98 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/ImageEmbeddedAssetReference.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/ImageOutOfBandAsset.cs b/Packages/app.rive.rive-unity/Runtime/ImageOutOfBandAsset.cs new file mode 100644 index 00000000..4a728e0b --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/ImageOutOfBandAsset.cs @@ -0,0 +1,30 @@ +using System; +using System.Runtime.InteropServices; + +namespace Rive +{ + /// + /// Represents an out-of-band Rive image asset. + /// + public class ImageOutOfBandAsset : OutOfBandAsset + { + protected override IntPtr LoadNative(byte[] data) + { + var inp = loadRiveImage(data, (nuint)data.Length); + return inp; + } + + protected override void UnloadNative(IntPtr nativePtr) + { + unrefRiveImage(nativePtr); + } + + #region Native Methods + [DllImport(NativeLibrary.name)] + private static extern IntPtr loadRiveImage(byte[] bytes, nuint byteCount); + + [DllImport(NativeLibrary.name)] + private static extern void unrefRiveImage(IntPtr image); + #endregion + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/ImageOutOfBandAsset.cs.meta b/Packages/app.rive.rive-unity/Runtime/ImageOutOfBandAsset.cs.meta new file mode 100644 index 00000000..ef879d3e --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/ImageOutOfBandAsset.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 622ac2b7aea4c4202895a366fa55f3f9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: df0df084c4eaa4149a9c988c71b85313, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/ImageOutOfBandAsset.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Interfaces.meta b/Packages/app.rive.rive-unity/Runtime/Interfaces.meta new file mode 100644 index 00000000..5e448b27 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Interfaces.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ddeb393eb4a284afda9ac9f69e6b34de +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Runtime/Interfaces/IDebugLogger.cs b/Packages/app.rive.rive-unity/Runtime/Interfaces/IDebugLogger.cs new file mode 100644 index 00000000..6565962d --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Interfaces/IDebugLogger.cs @@ -0,0 +1,16 @@ + +namespace Rive +{ + /// + /// Interface for logging debug messages. + /// + public interface IDebugLogger + { + void Log(string message); + void LogWarning(string message); + void LogError(string message); + + void LogException(System.Exception exception); + + } +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Runtime/Interfaces/IDebugLogger.cs.meta b/Packages/app.rive.rive-unity/Runtime/Interfaces/IDebugLogger.cs.meta new file mode 100644 index 00000000..b4761215 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Interfaces/IDebugLogger.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: ab144a42fd94c4224b0670daa57549c7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Interfaces/IDebugLogger.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Interfaces/IFileAssetLoader.cs b/Packages/app.rive.rive-unity/Runtime/Interfaces/IFileAssetLoader.cs new file mode 100644 index 00000000..33ddc437 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Interfaces/IFileAssetLoader.cs @@ -0,0 +1,9 @@ +namespace Rive +{ + public interface IFileAssetLoader + { + bool LoadContents(EmbeddedAssetReference assetReference); + } + + +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Runtime/Interfaces/IFileAssetLoader.cs.meta b/Packages/app.rive.rive-unity/Runtime/Interfaces/IFileAssetLoader.cs.meta new file mode 100644 index 00000000..19e9c8df --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Interfaces/IFileAssetLoader.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 45bbc017863f948cf8da7418f520968a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Interfaces/IFileAssetLoader.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Interfaces/IRenderer.cs b/Packages/app.rive.rive-unity/Runtime/Interfaces/IRenderer.cs new file mode 100644 index 00000000..9be4a6fe --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Interfaces/IRenderer.cs @@ -0,0 +1,93 @@ +using UnityEngine.Rendering; + +namespace Rive +{ + /// + /// Interface for rendering Rive content to a render queue + /// + public interface IRenderer + { + + /// + /// Clear the commands in the render queue + /// + void Clear(); + + /// + /// Draw the given artboard to the render queue + /// + /// The artboard to draw + void Draw(Artboard artboard); + + /// + /// Draw the given path and paint to the render queue + /// + /// The path to draw + /// The paint to apply to the path + void Draw(Path path, Paint paint); + + /// + /// Clip the render queue to the given path + /// + /// The path to use as a clip mask + void Clip(Path path); + + /// + /// Save the current render queue state + /// + void Save(); + + /// + /// Restore the last saved render queue state + /// + void Restore(); + + /// + /// Transform the render queue by the given translation + /// + /// The translation vector to apply + void Translate(System.Numerics.Vector2 translation); + + /// + /// Transform the render queue by the given translation + /// + /// The x translation + /// The y translation + void Translate(float x, float y); + + /// + /// Transform the render queue by the given matrix + /// + /// The transformation matrix to apply + void Transform(System.Numerics.Matrix3x2 matrix); + + /// + /// Align the artboard to the given fit and alignment + /// + /// The fit mode to use + /// The alignment to apply + /// The artboard to align + /// Optional scale factor to apply (defaults to 1.0) + void Align(Fit fit, Alignment alignment, Artboard artboard, float scaleFactor = 1.0f); + + /// + /// Align the artboard to the given fit and alignment, with the given frame + /// + /// The fit mode to use + /// The alignment to apply + /// The artboard to align + /// The frame to align within + /// Optional scale factor to apply (defaults to 1.0) + void Align(Fit fit, Alignment alignment, Artboard artboard, AABB frame, float scaleFactor = 1.0f); + + + /// + /// Add the render queue commands to an existing command buffer + /// + /// The command buffer to add commands to + /// Whether to release resources after execution (defaults to false) + void AddToCommandBuffer(UnityEngine.Rendering.CommandBuffer commandBuffer, bool release = false); + + + } +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Runtime/Interfaces/IRenderer.cs.meta b/Packages/app.rive.rive-unity/Runtime/Interfaces/IRenderer.cs.meta new file mode 100644 index 00000000..b02a3b13 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Interfaces/IRenderer.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 40ed18ea8606644d08690cc74afe9f32 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Interfaces/IRenderer.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries.meta b/Packages/app.rive.rive-unity/Runtime/Libraries.meta new file mode 100644 index 00000000..b6dd5bc9 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 04ec908b159444e47895d2e00b648f77 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/Android.meta b/Packages/app.rive.rive-unity/Runtime/Libraries/Android.meta new file mode 100644 index 00000000..f4d73672 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/Android.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 97afff3cbdb8b4f8c814a38fde2aec13 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/Android/arm.meta b/Packages/app.rive.rive-unity/Runtime/Libraries/Android/arm.meta new file mode 100644 index 00000000..4e8137c1 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/Android/arm.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d05e8711c70074c62a2af43fba41b36f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/Android/arm/librive.so b/Packages/app.rive.rive-unity/Runtime/Libraries/Android/arm/librive.so new file mode 100644 index 00000000..4a1dc583 Binary files /dev/null and b/Packages/app.rive.rive-unity/Runtime/Libraries/Android/arm/librive.so differ diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/Android/arm/librive.so.meta b/Packages/app.rive.rive-unity/Runtime/Libraries/Android/arm/librive.so.meta new file mode 100644 index 00000000..7ad6b54a --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/Android/arm/librive.so.meta @@ -0,0 +1,88 @@ +fileFormatVersion: 2 +guid: d7db26e77af8249ec8a19b7baf6ed01f +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : Any + second: + enabled: 0 + settings: + Exclude Android: 0 + Exclude Editor: 1 + Exclude Linux64: 1 + Exclude OSXUniversal: 1 + Exclude Win: 1 + Exclude Win64: 1 + Exclude iOS: 1 + - first: + Android: Android + second: + enabled: 1 + settings: + AndroidSharedLibraryType: Executable + CPU: ARMv7 + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + CPU: AnyCPU + DefaultValueInitialized: true + OS: AnyOS + - first: + Standalone: Linux64 + second: + enabled: 0 + settings: + CPU: None + - first: + Standalone: OSXUniversal + second: + enabled: 0 + settings: + CPU: None + - first: + Standalone: Win + second: + enabled: 0 + settings: + CPU: None + - first: + Standalone: Win64 + second: + enabled: 0 + settings: + CPU: None + - first: + iPhone: iOS + second: + enabled: 0 + settings: + AddToEmbeddedBinaries: false + CPU: AnyCPU + CompileFlags: + FrameworkDependencies: + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Libraries/Android/arm/librive.so + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/Android/arm64.meta b/Packages/app.rive.rive-unity/Runtime/Libraries/Android/arm64.meta new file mode 100644 index 00000000..ce15968f --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/Android/arm64.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cd12a20fe640941838c8427e3a5eefa1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/Android/arm64/librive.so b/Packages/app.rive.rive-unity/Runtime/Libraries/Android/arm64/librive.so new file mode 100644 index 00000000..96b0aded Binary files /dev/null and b/Packages/app.rive.rive-unity/Runtime/Libraries/Android/arm64/librive.so differ diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/Android/arm64/librive.so.meta b/Packages/app.rive.rive-unity/Runtime/Libraries/Android/arm64/librive.so.meta new file mode 100644 index 00000000..61fa5f52 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/Android/arm64/librive.so.meta @@ -0,0 +1,88 @@ +fileFormatVersion: 2 +guid: a30161fb6f50444fe8998d929b10c157 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : Any + second: + enabled: 0 + settings: + Exclude Android: 0 + Exclude Editor: 1 + Exclude Linux64: 1 + Exclude OSXUniversal: 1 + Exclude Win: 1 + Exclude Win64: 1 + Exclude iOS: 1 + - first: + Android: Android + second: + enabled: 1 + settings: + AndroidSharedLibraryType: Executable + CPU: ARM64 + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + CPU: AnyCPU + DefaultValueInitialized: true + OS: AnyOS + - first: + Standalone: Linux64 + second: + enabled: 0 + settings: + CPU: None + - first: + Standalone: OSXUniversal + second: + enabled: 0 + settings: + CPU: None + - first: + Standalone: Win + second: + enabled: 0 + settings: + CPU: None + - first: + Standalone: Win64 + second: + enabled: 0 + settings: + CPU: None + - first: + iPhone: iOS + second: + enabled: 0 + settings: + AddToEmbeddedBinaries: false + CPU: AnyCPU + CompileFlags: + FrameworkDependencies: + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Libraries/Android/arm64/librive.so + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/Linux.meta b/Packages/app.rive.rive-unity/Runtime/Libraries/Linux.meta new file mode 100644 index 00000000..2ef65a02 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/Linux.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b931cf581494f9b49a0ecee3f0a20694 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/Linux/x86_64.meta b/Packages/app.rive.rive-unity/Runtime/Libraries/Linux/x86_64.meta new file mode 100644 index 00000000..64546059 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/Linux/x86_64.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 607a92edebebd47abb7efcd264d3a37c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/Linux/x86_64/librive.so b/Packages/app.rive.rive-unity/Runtime/Libraries/Linux/x86_64/librive.so new file mode 100644 index 00000000..f8e0a281 Binary files /dev/null and b/Packages/app.rive.rive-unity/Runtime/Libraries/Linux/x86_64/librive.so differ diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/Linux/x86_64/librive.so.meta b/Packages/app.rive.rive-unity/Runtime/Libraries/Linux/x86_64/librive.so.meta new file mode 100644 index 00000000..78675fa8 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/Linux/x86_64/librive.so.meta @@ -0,0 +1,69 @@ +fileFormatVersion: 2 +guid: e61fccaeadc1949f8ab5a19e6ba75fbe +PluginImporter: + externalObjects: {} + serializedVersion: 3 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + Android: + enabled: 0 + settings: + AndroidLibraryDependee: UnityLibrary + AndroidSharedLibraryType: Executable + CPU: ARMv7 + Any: + enabled: 0 + settings: + Exclude Android: 1 + Exclude Editor: 0 + Exclude Linux64: 0 + Exclude OSXUniversal: 1 + Exclude WebGL: 1 + Exclude Win: 0 + Exclude Win64: 0 + Exclude iOS: 1 + Editor: + enabled: 1 + settings: + CPU: x86_64 + DefaultValueInitialized: true + OS: Linux + Linux64: + enabled: 1 + settings: + CPU: x86_64 + OSXUniversal: + enabled: 0 + settings: + CPU: None + Win: + enabled: 1 + settings: + CPU: None + Win64: + enabled: 1 + settings: + CPU: None + iOS: + enabled: 0 + settings: + AddToEmbeddedBinaries: false + CPU: AnyCPU + CompileFlags: + FrameworkDependencies: + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Libraries/Linux/x86_64/librive.so + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/MacOS.meta b/Packages/app.rive.rive-unity/Runtime/Libraries/MacOS.meta new file mode 100644 index 00000000..f3cbba3e --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/MacOS.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 711bedd7d564a4c8f9007a1885570a5a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/MacOS/rive.dylib b/Packages/app.rive.rive-unity/Runtime/Libraries/MacOS/rive.dylib new file mode 100644 index 00000000..2acf0f22 Binary files /dev/null and b/Packages/app.rive.rive-unity/Runtime/Libraries/MacOS/rive.dylib differ diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/MacOS/rive.dylib.meta b/Packages/app.rive.rive-unity/Runtime/Libraries/MacOS/rive.dylib.meta new file mode 100644 index 00000000..176342de --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/MacOS/rive.dylib.meta @@ -0,0 +1,40 @@ +fileFormatVersion: 2 +guid: bd741b3f980c042ceaab63ddd351777c +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 1 + settings: + DefaultValueInitialized: true + - first: + Standalone: OSXUniversal + second: + enabled: 1 + settings: + CPU: AnyCPU + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Libraries/MacOS/rive.dylib + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL.meta b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL.meta new file mode 100644 index 00000000..43ec14e5 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 553426d9e7ee24519b6e627698840ac8 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38.meta b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38.meta new file mode 100644 index 00000000..13481f91 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 055a80be2a9cb4a7f948cc5598738677 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/liblibjpeg_wasm.a b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/liblibjpeg_wasm.a new file mode 100644 index 00000000..a3f56ad4 Binary files /dev/null and b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/liblibjpeg_wasm.a differ diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/liblibjpeg_wasm.a.meta b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/liblibjpeg_wasm.a.meta new file mode 100644 index 00000000..2af709bc --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/liblibjpeg_wasm.a.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 6901a44be85da42c38e3642f268ed5e9 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : + second: + enabled: 0 + settings: {} + - first: + : Any + second: + enabled: 0 + settings: + Exclude Android: 1 + Exclude Editor: 1 + Exclude Linux64: 1 + Exclude OSXUniversal: 1 + Exclude WebGL: 1 + Exclude Win: 1 + Exclude Win64: 1 + Exclude iOS: 1 + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/liblibjpeg_wasm.a + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/liblibpng_wasm.a b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/liblibpng_wasm.a new file mode 100644 index 00000000..100a4a1b Binary files /dev/null and b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/liblibpng_wasm.a differ diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/liblibpng_wasm.a.meta b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/liblibpng_wasm.a.meta new file mode 100644 index 00000000..d7a199a0 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/liblibpng_wasm.a.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 8cd66083087604310b662826db613fb1 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : + second: + enabled: 0 + settings: {} + - first: + : Any + second: + enabled: 0 + settings: + Exclude Android: 1 + Exclude Editor: 1 + Exclude Linux64: 1 + Exclude OSXUniversal: 1 + Exclude WebGL: 1 + Exclude Win: 1 + Exclude Win64: 1 + Exclude iOS: 1 + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/liblibpng_wasm.a + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/liblibwebp_wasm.a b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/liblibwebp_wasm.a new file mode 100644 index 00000000..b014e397 Binary files /dev/null and b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/liblibwebp_wasm.a differ diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/liblibwebp_wasm.a.meta b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/liblibwebp_wasm.a.meta new file mode 100644 index 00000000..10cb00a8 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/liblibwebp_wasm.a.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 3696e2e514b0f4006bcee4bf1ded40b0 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : + second: + enabled: 0 + settings: {} + - first: + : Any + second: + enabled: 0 + settings: + Exclude Android: 1 + Exclude Editor: 1 + Exclude Linux64: 1 + Exclude OSXUniversal: 1 + Exclude WebGL: 1 + Exclude Win: 1 + Exclude Win64: 1 + Exclude iOS: 1 + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/liblibwebp_wasm.a + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/libluau_vm_wasm.a b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/libluau_vm_wasm.a new file mode 100644 index 00000000..68e53cae Binary files /dev/null and b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/libluau_vm_wasm.a differ diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/libluau_vm_wasm.a.meta b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/libluau_vm_wasm.a.meta new file mode 100644 index 00000000..a14686e8 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/libluau_vm_wasm.a.meta @@ -0,0 +1,67 @@ +fileFormatVersion: 2 +guid: e6b18b7f9ee7a4bd78229c875a5512d0 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : Any + second: + enabled: 0 + settings: + Exclude Android: 1 + Exclude Editor: 1 + Exclude Linux64: 1 + Exclude OSXUniversal: 1 + Exclude VisionOS: 1 + Exclude WebGL: 1 + Exclude Win: 1 + Exclude Win64: 1 + Exclude iOS: 1 + Exclude tvOS: 1 + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + Standalone: Linux64 + second: + enabled: 0 + settings: + CPU: None + - first: + Standalone: Win + second: + enabled: 0 + settings: + CPU: None + - first: + Standalone: Win64 + second: + enabled: 0 + settings: + CPU: None + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/libluau_vm_wasm.a + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/libminiaudio_wasm.a b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/libminiaudio_wasm.a new file mode 100644 index 00000000..28148377 Binary files /dev/null and b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/libminiaudio_wasm.a differ diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/libminiaudio_wasm.a.meta b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/libminiaudio_wasm.a.meta new file mode 100644 index 00000000..96f6ffff --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/libminiaudio_wasm.a.meta @@ -0,0 +1,89 @@ +fileFormatVersion: 2 +guid: 4011a423dc13e40a487d789bb9282f22 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : Any + second: + enabled: 0 + settings: + Exclude Android: 1 + Exclude Editor: 1 + Exclude Linux64: 1 + Exclude OSXUniversal: 1 + Exclude WebGL: 1 + Exclude Win: 1 + Exclude Win64: 1 + Exclude iOS: 1 + - first: + Android: Android + second: + enabled: 0 + settings: + AndroidSharedLibraryType: Executable + CPU: ARMv7 + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + CPU: AnyCPU + DefaultValueInitialized: true + OS: AnyOS + - first: + Standalone: Linux64 + second: + enabled: 0 + settings: + CPU: None + - first: + Standalone: OSXUniversal + second: + enabled: 0 + settings: + CPU: None + - first: + Standalone: Win + second: + enabled: 0 + settings: + CPU: None + - first: + Standalone: Win64 + second: + enabled: 0 + settings: + CPU: None + - first: + iPhone: iOS + second: + enabled: 0 + settings: + AddToEmbeddedBinaries: false + CPU: AnyCPU + CompileFlags: + FrameworkDependencies: + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/libminiaudio_wasm.a + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/librive_decoders_wasm.a b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/librive_decoders_wasm.a new file mode 100644 index 00000000..8316c16f Binary files /dev/null and b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/librive_decoders_wasm.a differ diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/librive_decoders_wasm.a.meta b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/librive_decoders_wasm.a.meta new file mode 100644 index 00000000..dbc69165 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/librive_decoders_wasm.a.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: c257c258e8c25445696c11d37e5d8895 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : + second: + enabled: 0 + settings: {} + - first: + : Any + second: + enabled: 0 + settings: + Exclude Android: 1 + Exclude Editor: 1 + Exclude Linux64: 1 + Exclude OSXUniversal: 1 + Exclude WebGL: 1 + Exclude Win: 1 + Exclude Win64: 1 + Exclude iOS: 1 + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/librive_decoders_wasm.a + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/librive_harfbuzz_wasm.a b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/librive_harfbuzz_wasm.a new file mode 100644 index 00000000..9cfe6b4a Binary files /dev/null and b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/librive_harfbuzz_wasm.a differ diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/librive_harfbuzz_wasm.a.meta b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/librive_harfbuzz_wasm.a.meta new file mode 100644 index 00000000..c9083bd8 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/librive_harfbuzz_wasm.a.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 2849656d6ed2e4b4e8e108eb4ce0ad5b +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : + second: + enabled: 0 + settings: {} + - first: + : Any + second: + enabled: 0 + settings: + Exclude Android: 1 + Exclude Editor: 1 + Exclude Linux64: 1 + Exclude OSXUniversal: 1 + Exclude WebGL: 1 + Exclude Win: 1 + Exclude Win64: 1 + Exclude iOS: 1 + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/librive_harfbuzz_wasm.a + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/librive_pls_renderer_wasm.a b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/librive_pls_renderer_wasm.a new file mode 100644 index 00000000..d9aa1bde Binary files /dev/null and b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/librive_pls_renderer_wasm.a differ diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/librive_pls_renderer_wasm.a.meta b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/librive_pls_renderer_wasm.a.meta new file mode 100644 index 00000000..73ede79b --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/librive_pls_renderer_wasm.a.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: fbef64a78028b40e5b3084ae47fda6cd +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : + second: + enabled: 0 + settings: {} + - first: + : Any + second: + enabled: 0 + settings: + Exclude Android: 1 + Exclude Editor: 1 + Exclude Linux64: 1 + Exclude OSXUniversal: 1 + Exclude WebGL: 1 + Exclude Win: 1 + Exclude Win64: 1 + Exclude iOS: 1 + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/librive_pls_renderer_wasm.a + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/librive_sheenbidi_wasm.a b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/librive_sheenbidi_wasm.a new file mode 100644 index 00000000..feb79d64 Binary files /dev/null and b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/librive_sheenbidi_wasm.a differ diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/librive_sheenbidi_wasm.a.meta b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/librive_sheenbidi_wasm.a.meta new file mode 100644 index 00000000..ef06951f --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/librive_sheenbidi_wasm.a.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 03145630af92449ce8ba6b5d514ed372 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : + second: + enabled: 0 + settings: {} + - first: + : Any + second: + enabled: 0 + settings: + Exclude Android: 1 + Exclude Editor: 1 + Exclude Linux64: 1 + Exclude OSXUniversal: 1 + Exclude WebGL: 1 + Exclude Win: 1 + Exclude Win64: 1 + Exclude iOS: 1 + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/librive_sheenbidi_wasm.a + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/librive_unity_wasm.a b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/librive_unity_wasm.a new file mode 100644 index 00000000..fabd19db Binary files /dev/null and b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/librive_unity_wasm.a differ diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/librive_unity_wasm.a.meta b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/librive_unity_wasm.a.meta new file mode 100644 index 00000000..844c8b13 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/librive_unity_wasm.a.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: c5ae103db0322456e8f32fdf1bdb15be +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : + second: + enabled: 0 + settings: {} + - first: + : Any + second: + enabled: 0 + settings: + Exclude Android: 1 + Exclude Editor: 1 + Exclude Linux64: 1 + Exclude OSXUniversal: 1 + Exclude WebGL: 1 + Exclude Win: 1 + Exclude Win64: 1 + Exclude iOS: 1 + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/librive_unity_wasm.a + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/librive_wasm.a b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/librive_wasm.a new file mode 100644 index 00000000..1407cef7 Binary files /dev/null and b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/librive_wasm.a differ diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/librive_wasm.a.meta b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/librive_wasm.a.meta new file mode 100644 index 00000000..14be993e --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/librive_wasm.a.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: bf6739ac9b5924682a27d5c13458cbe5 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : + second: + enabled: 0 + settings: {} + - first: + : Any + second: + enabled: 0 + settings: + Exclude Android: 1 + Exclude Editor: 1 + Exclude Linux64: 1 + Exclude OSXUniversal: 1 + Exclude WebGL: 1 + Exclude Win: 1 + Exclude Win64: 1 + Exclude iOS: 1 + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/librive_wasm.a + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/librive_yoga_wasm.a b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/librive_yoga_wasm.a new file mode 100644 index 00000000..d8c42a78 Binary files /dev/null and b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/librive_yoga_wasm.a differ diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/librive_yoga_wasm.a.meta b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/librive_yoga_wasm.a.meta new file mode 100644 index 00000000..4907af02 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/librive_yoga_wasm.a.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 3d9af2b78d5d44f92a39788112dc4faf +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : + second: + enabled: 0 + settings: {} + - first: + : Any + second: + enabled: 0 + settings: + Exclude Android: 1 + Exclude Editor: 1 + Exclude Linux64: 1 + Exclude OSXUniversal: 1 + Exclude WebGL: 1 + Exclude Win: 1 + Exclude Win64: 1 + Exclude iOS: 1 + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/librive_yoga_wasm.a + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/libzlib_wasm.a b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/libzlib_wasm.a new file mode 100644 index 00000000..8a4f04d7 Binary files /dev/null and b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/libzlib_wasm.a differ diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/libzlib_wasm.a.meta b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/libzlib_wasm.a.meta new file mode 100644 index 00000000..55f20d23 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/libzlib_wasm.a.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 1c92bea23c5dc4087918435716fddd92 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : + second: + enabled: 0 + settings: {} + - first: + : Any + second: + enabled: 0 + settings: + Exclude Android: 1 + Exclude Editor: 1 + Exclude Linux64: 1 + Exclude OSXUniversal: 1 + Exclude WebGL: 1 + Exclude Win: 1 + Exclude Win64: 1 + Exclude iOS: 1 + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.38/libzlib_wasm.a + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8.meta b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8.meta new file mode 100644 index 00000000..6da64e3e --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 765e27d1ac78d404a910ee7e6386c347 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/liblibjpeg_wasm.a b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/liblibjpeg_wasm.a new file mode 100644 index 00000000..a5809644 Binary files /dev/null and b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/liblibjpeg_wasm.a differ diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/liblibjpeg_wasm.a.meta b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/liblibjpeg_wasm.a.meta new file mode 100644 index 00000000..65866333 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/liblibjpeg_wasm.a.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: ce6c55d5bde0c4299946a9f88d356f1f +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : + second: + enabled: 0 + settings: {} + - first: + : Any + second: + enabled: 0 + settings: + Exclude Android: 1 + Exclude Editor: 1 + Exclude Linux64: 1 + Exclude OSXUniversal: 1 + Exclude WebGL: 1 + Exclude Win: 1 + Exclude Win64: 1 + Exclude iOS: 1 + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/liblibjpeg_wasm.a + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/liblibpng_wasm.a b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/liblibpng_wasm.a new file mode 100644 index 00000000..f1224f78 Binary files /dev/null and b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/liblibpng_wasm.a differ diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/liblibpng_wasm.a.meta b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/liblibpng_wasm.a.meta new file mode 100644 index 00000000..57255f1b --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/liblibpng_wasm.a.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: ce71a875e524740799659a53f428b480 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : + second: + enabled: 0 + settings: {} + - first: + : Any + second: + enabled: 0 + settings: + Exclude Android: 1 + Exclude Editor: 1 + Exclude Linux64: 1 + Exclude OSXUniversal: 1 + Exclude WebGL: 1 + Exclude Win: 1 + Exclude Win64: 1 + Exclude iOS: 1 + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/liblibpng_wasm.a + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/liblibwebp_wasm.a b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/liblibwebp_wasm.a new file mode 100644 index 00000000..2b695a6f Binary files /dev/null and b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/liblibwebp_wasm.a differ diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/liblibwebp_wasm.a.meta b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/liblibwebp_wasm.a.meta new file mode 100644 index 00000000..b39f6cac --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/liblibwebp_wasm.a.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: f20a5c60599834f319c0a379117b2445 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : + second: + enabled: 0 + settings: {} + - first: + : Any + second: + enabled: 0 + settings: + Exclude Android: 1 + Exclude Editor: 1 + Exclude Linux64: 1 + Exclude OSXUniversal: 1 + Exclude WebGL: 1 + Exclude Win: 1 + Exclude Win64: 1 + Exclude iOS: 1 + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/liblibwebp_wasm.a + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/libluau_vm_wasm.a b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/libluau_vm_wasm.a new file mode 100644 index 00000000..4f785675 Binary files /dev/null and b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/libluau_vm_wasm.a differ diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/libluau_vm_wasm.a.meta b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/libluau_vm_wasm.a.meta new file mode 100644 index 00000000..c2196cfc --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/libluau_vm_wasm.a.meta @@ -0,0 +1,49 @@ +fileFormatVersion: 2 +guid: 3a939cccb5ce34c838518d0a3f86e071 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : Any + second: + enabled: 0 + settings: + Exclude Android: 1 + Exclude Editor: 1 + Exclude Linux64: 1 + Exclude OSXUniversal: 1 + Exclude VisionOS: 1 + Exclude WebGL: 1 + Exclude Win: 1 + Exclude Win64: 1 + Exclude iOS: 1 + Exclude tvOS: 1 + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/libluau_vm_wasm.a + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/libminiaudio_wasm.a b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/libminiaudio_wasm.a new file mode 100644 index 00000000..a7aae7b0 Binary files /dev/null and b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/libminiaudio_wasm.a differ diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/libminiaudio_wasm.a.meta b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/libminiaudio_wasm.a.meta new file mode 100644 index 00000000..e635695e --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/libminiaudio_wasm.a.meta @@ -0,0 +1,89 @@ +fileFormatVersion: 2 +guid: 505c48decfb904504be8e2a14f542118 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : Any + second: + enabled: 0 + settings: + Exclude Android: 1 + Exclude Editor: 1 + Exclude Linux64: 1 + Exclude OSXUniversal: 1 + Exclude WebGL: 1 + Exclude Win: 1 + Exclude Win64: 1 + Exclude iOS: 1 + - first: + Android: Android + second: + enabled: 0 + settings: + AndroidSharedLibraryType: Executable + CPU: ARMv7 + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + CPU: AnyCPU + DefaultValueInitialized: true + OS: AnyOS + - first: + Standalone: Linux64 + second: + enabled: 0 + settings: + CPU: None + - first: + Standalone: OSXUniversal + second: + enabled: 0 + settings: + CPU: None + - first: + Standalone: Win + second: + enabled: 0 + settings: + CPU: None + - first: + Standalone: Win64 + second: + enabled: 0 + settings: + CPU: None + - first: + iPhone: iOS + second: + enabled: 0 + settings: + AddToEmbeddedBinaries: false + CPU: AnyCPU + CompileFlags: + FrameworkDependencies: + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/libminiaudio_wasm.a + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/librive_decoders_wasm.a b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/librive_decoders_wasm.a new file mode 100644 index 00000000..f30e8b5a Binary files /dev/null and b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/librive_decoders_wasm.a differ diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/librive_decoders_wasm.a.meta b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/librive_decoders_wasm.a.meta new file mode 100644 index 00000000..64936dee --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/librive_decoders_wasm.a.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 6fb2173f19c3b42eb849a2de6f5276b0 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : + second: + enabled: 0 + settings: {} + - first: + : Any + second: + enabled: 0 + settings: + Exclude Android: 1 + Exclude Editor: 1 + Exclude Linux64: 1 + Exclude OSXUniversal: 1 + Exclude WebGL: 1 + Exclude Win: 1 + Exclude Win64: 1 + Exclude iOS: 1 + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/librive_decoders_wasm.a + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/librive_harfbuzz_wasm.a b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/librive_harfbuzz_wasm.a new file mode 100644 index 00000000..eeb8372a Binary files /dev/null and b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/librive_harfbuzz_wasm.a differ diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/librive_harfbuzz_wasm.a.meta b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/librive_harfbuzz_wasm.a.meta new file mode 100644 index 00000000..9b8882b2 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/librive_harfbuzz_wasm.a.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 2ff32efd637c94ee2b1b2da20ae2c058 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : + second: + enabled: 0 + settings: {} + - first: + : Any + second: + enabled: 0 + settings: + Exclude Android: 1 + Exclude Editor: 1 + Exclude Linux64: 1 + Exclude OSXUniversal: 1 + Exclude WebGL: 1 + Exclude Win: 1 + Exclude Win64: 1 + Exclude iOS: 1 + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/librive_harfbuzz_wasm.a + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/librive_pls_renderer_wasm.a b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/librive_pls_renderer_wasm.a new file mode 100644 index 00000000..9b2b7837 Binary files /dev/null and b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/librive_pls_renderer_wasm.a differ diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/librive_pls_renderer_wasm.a.meta b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/librive_pls_renderer_wasm.a.meta new file mode 100644 index 00000000..156a29e7 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/librive_pls_renderer_wasm.a.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 76bb7591ba17a4410812e91bfca64536 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : + second: + enabled: 0 + settings: {} + - first: + : Any + second: + enabled: 0 + settings: + Exclude Android: 1 + Exclude Editor: 1 + Exclude Linux64: 1 + Exclude OSXUniversal: 1 + Exclude WebGL: 1 + Exclude Win: 1 + Exclude Win64: 1 + Exclude iOS: 1 + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/librive_pls_renderer_wasm.a + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/librive_sheenbidi_wasm.a b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/librive_sheenbidi_wasm.a new file mode 100644 index 00000000..107d1aea Binary files /dev/null and b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/librive_sheenbidi_wasm.a differ diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/librive_sheenbidi_wasm.a.meta b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/librive_sheenbidi_wasm.a.meta new file mode 100644 index 00000000..cd65b361 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/librive_sheenbidi_wasm.a.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: f64f895237b174eaf8cdd45bc83aa258 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : + second: + enabled: 0 + settings: {} + - first: + : Any + second: + enabled: 0 + settings: + Exclude Android: 1 + Exclude Editor: 1 + Exclude Linux64: 1 + Exclude OSXUniversal: 1 + Exclude WebGL: 1 + Exclude Win: 1 + Exclude Win64: 1 + Exclude iOS: 1 + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/librive_sheenbidi_wasm.a + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/librive_unity_wasm.a b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/librive_unity_wasm.a new file mode 100644 index 00000000..f7a55dff Binary files /dev/null and b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/librive_unity_wasm.a differ diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/librive_unity_wasm.a.meta b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/librive_unity_wasm.a.meta new file mode 100644 index 00000000..18c42b0a --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/librive_unity_wasm.a.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 8fe17c0390569425a9dcff73528582f4 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : + second: + enabled: 0 + settings: {} + - first: + : Any + second: + enabled: 0 + settings: + Exclude Android: 1 + Exclude Editor: 1 + Exclude Linux64: 1 + Exclude OSXUniversal: 1 + Exclude WebGL: 1 + Exclude Win: 1 + Exclude Win64: 1 + Exclude iOS: 1 + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/librive_unity_wasm.a + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/librive_wasm.a b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/librive_wasm.a new file mode 100644 index 00000000..004b2b69 Binary files /dev/null and b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/librive_wasm.a differ diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/librive_wasm.a.meta b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/librive_wasm.a.meta new file mode 100644 index 00000000..5ba57a69 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/librive_wasm.a.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: a43738bdaf669432080c35510bfc7d26 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : + second: + enabled: 0 + settings: {} + - first: + : Any + second: + enabled: 0 + settings: + Exclude Android: 1 + Exclude Editor: 1 + Exclude Linux64: 1 + Exclude OSXUniversal: 1 + Exclude WebGL: 1 + Exclude Win: 1 + Exclude Win64: 1 + Exclude iOS: 1 + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/librive_wasm.a + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/librive_yoga_wasm.a b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/librive_yoga_wasm.a new file mode 100644 index 00000000..094ae4f1 Binary files /dev/null and b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/librive_yoga_wasm.a differ diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/librive_yoga_wasm.a.meta b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/librive_yoga_wasm.a.meta new file mode 100644 index 00000000..cc51fd6a --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/librive_yoga_wasm.a.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 41e52fdabbfe64b45a35e3561b5b807d +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : + second: + enabled: 0 + settings: {} + - first: + : Any + second: + enabled: 0 + settings: + Exclude Android: 1 + Exclude Editor: 1 + Exclude Linux64: 1 + Exclude OSXUniversal: 1 + Exclude WebGL: 1 + Exclude Win: 1 + Exclude Win64: 1 + Exclude iOS: 1 + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/librive_yoga_wasm.a + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/libzlib_wasm.a b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/libzlib_wasm.a new file mode 100644 index 00000000..f8ce5782 Binary files /dev/null and b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/libzlib_wasm.a differ diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/libzlib_wasm.a.meta b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/libzlib_wasm.a.meta new file mode 100644 index 00000000..f715d75c --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/libzlib_wasm.a.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: e52dbe6327a464f88aab9a4812d9b04e +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : + second: + enabled: 0 + settings: {} + - first: + : Any + second: + enabled: 0 + settings: + Exclude Android: 1 + Exclude Editor: 1 + Exclude Linux64: 1 + Exclude OSXUniversal: 1 + Exclude WebGL: 1 + Exclude Win: 1 + Exclude Win64: 1 + Exclude iOS: 1 + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Libraries/WebGL/emscripten_3.1.8/libzlib_wasm.a + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/Windows.meta b/Packages/app.rive.rive-unity/Runtime/Libraries/Windows.meta new file mode 100644 index 00000000..71ba79b3 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/Windows.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f0e5c8dca1ffd4dfb80f03226cc36e94 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/Windows/rive.dll b/Packages/app.rive.rive-unity/Runtime/Libraries/Windows/rive.dll new file mode 100644 index 00000000..c5b941a0 Binary files /dev/null and b/Packages/app.rive.rive-unity/Runtime/Libraries/Windows/rive.dll differ diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/Windows/rive.dll.meta b/Packages/app.rive.rive-unity/Runtime/Libraries/Windows/rive.dll.meta new file mode 100644 index 00000000..a3989b26 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/Windows/rive.dll.meta @@ -0,0 +1,34 @@ +fileFormatVersion: 2 +guid: 91a239b3e5d8d62468158ddb66f8b4e4 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 1 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Libraries/Windows/rive.dll + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/iOS.meta b/Packages/app.rive.rive-unity/Runtime/Libraries/iOS.meta new file mode 100644 index 00000000..5c0ed8fa --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/iOS.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2208a1008d2c2439daef0989d69cb5e5 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/iOS/rive.xcframework.meta b/Packages/app.rive.rive-unity/Runtime/Libraries/iOS/rive.xcframework.meta new file mode 100644 index 00000000..9698d544 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/iOS/rive.xcframework.meta @@ -0,0 +1,83 @@ +fileFormatVersion: 2 +guid: 7f0f3b9e3c9440d1bd9b0c7a3a2a5c31 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : Any + second: + enabled: 0 + settings: + Exclude Android: 1 + Exclude Editor: 1 + Exclude Linux64: 1 + Exclude OSXUniversal: 1 + Exclude WebGL: 1 + Exclude Win: 1 + Exclude Win64: 1 + Exclude iOS: 0 + - first: + Android: Android + second: + enabled: 0 + settings: + AndroidSharedLibraryType: Executable + CPU: ARMv7 + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + CPU: AnyCPU + DefaultValueInitialized: true + OS: AnyOS + - first: + Standalone: Linux64 + second: + enabled: 0 + settings: + CPU: AnyCPU + - first: + Standalone: OSXUniversal + second: + enabled: 0 + settings: + CPU: AnyCPU + - first: + Standalone: Win + second: + enabled: 0 + settings: + CPU: AnyCPU + - first: + Standalone: Win64 + second: + enabled: 0 + settings: + CPU: AnyCPU + - first: + iPhone: iOS + second: + enabled: 1 + settings: + AddToEmbeddedBinaries: false + CPU: AnyCPU + CompileFlags: + FrameworkDependencies: ImageIO; + userData: + assetBundleName: + assetBundleVariant: + diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/iOS/rive.xcframework/Info.plist b/Packages/app.rive.rive-unity/Runtime/Libraries/iOS/rive.xcframework/Info.plist new file mode 100644 index 00000000..8c0dce2d --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/iOS/rive.xcframework/Info.plist @@ -0,0 +1,48 @@ + + + + + AvailableLibraries + + + BinaryPath + rive.device.a + HeadersPath + Headers + LibraryIdentifier + ios-arm64 + LibraryPath + rive.device.a + SupportedArchitectures + + arm64 + + SupportedPlatform + ios + + + BinaryPath + rive.simulator.a + HeadersPath + Headers + LibraryIdentifier + ios-arm64_x86_64-simulator + LibraryPath + rive.simulator.a + SupportedArchitectures + + arm64 + x86_64 + + SupportedPlatform + ios + SupportedPlatformVariant + simulator + + + CFBundlePackageType + XFWK + XCFrameworkFormatVersion + 1.0 + + diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/iOS/rive.xcframework/ios-arm64/Headers/rive_unity.h b/Packages/app.rive.rive-unity/Runtime/Libraries/iOS/rive.xcframework/ios-arm64/Headers/rive_unity.h new file mode 100644 index 00000000..c59c2e8a --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/iOS/rive.xcframework/ios-arm64/Headers/rive_unity.h @@ -0,0 +1 @@ +/* Rive Unity XCFramework */ diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/iOS/rive.xcframework/ios-arm64/rive.device.a b/Packages/app.rive.rive-unity/Runtime/Libraries/iOS/rive.xcframework/ios-arm64/rive.device.a new file mode 100644 index 00000000..b2039661 Binary files /dev/null and b/Packages/app.rive.rive-unity/Runtime/Libraries/iOS/rive.xcframework/ios-arm64/rive.device.a differ diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/iOS/rive.xcframework/ios-arm64_x86_64-simulator/Headers/rive_unity.h b/Packages/app.rive.rive-unity/Runtime/Libraries/iOS/rive.xcframework/ios-arm64_x86_64-simulator/Headers/rive_unity.h new file mode 100644 index 00000000..c59c2e8a --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/iOS/rive.xcframework/ios-arm64_x86_64-simulator/Headers/rive_unity.h @@ -0,0 +1 @@ +/* Rive Unity XCFramework */ diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/iOS/rive.xcframework/ios-arm64_x86_64-simulator/rive.simulator.a b/Packages/app.rive.rive-unity/Runtime/Libraries/iOS/rive.xcframework/ios-arm64_x86_64-simulator/rive.simulator.a new file mode 100644 index 00000000..00423142 Binary files /dev/null and b/Packages/app.rive.rive-unity/Runtime/Libraries/iOS/rive.xcframework/ios-arm64_x86_64-simulator/rive.simulator.a differ diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/tvOS.meta b/Packages/app.rive.rive-unity/Runtime/Libraries/tvOS.meta new file mode 100644 index 00000000..51c7bade --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/tvOS.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ef273ab06036747b4bcc739786b86861 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/tvOS/rive.xcframework.meta b/Packages/app.rive.rive-unity/Runtime/Libraries/tvOS/rive.xcframework.meta new file mode 100644 index 00000000..e35da2cd --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/tvOS/rive.xcframework.meta @@ -0,0 +1,92 @@ +fileFormatVersion: 2 +guid: f21a39cf44e604916884e85fd0772465 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : Any + second: + enabled: 0 + settings: + Exclude Android: 1 + Exclude Editor: 1 + Exclude Linux64: 1 + Exclude OSXUniversal: 1 + Exclude WebGL: 1 + Exclude Win: 1 + Exclude Win64: 1 + Exclude iOS: 1 + Exclude tvOS: 0 + - first: + Android: Android + second: + enabled: 0 + settings: + AndroidSharedLibraryType: Executable + CPU: ARMv7 + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + CPU: AnyCPU + DefaultValueInitialized: true + OS: AnyOS + - first: + Standalone: Linux64 + second: + enabled: 0 + settings: + CPU: None + - first: + Standalone: OSXUniversal + second: + enabled: 0 + settings: + CPU: None + - first: + Standalone: Win + second: + enabled: 0 + settings: + CPU: None + - first: + Standalone: Win64 + second: + enabled: 0 + settings: + CPU: None + - first: + iPhone: iOS + second: + enabled: 0 + settings: + AddToEmbeddedBinaries: false + CPU: AnyCPU + CompileFlags: + FrameworkDependencies: + - first: + tvOS: tvOS + second: + enabled: 1 + settings: + AddToEmbeddedBinaries: false + CPU: AnyCPU + CompileFlags: + FrameworkDependencies: ImageIO; + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/tvOS/rive.xcframework/Info.plist b/Packages/app.rive.rive-unity/Runtime/Libraries/tvOS/rive.xcframework/Info.plist new file mode 100644 index 00000000..d166f33d --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/tvOS/rive.xcframework/Info.plist @@ -0,0 +1,48 @@ + + + + + AvailableLibraries + + + BinaryPath + rive.simulator.a + HeadersPath + Headers + LibraryIdentifier + tvos-arm64_x86_64-simulator + LibraryPath + rive.simulator.a + SupportedArchitectures + + arm64 + x86_64 + + SupportedPlatform + tvos + SupportedPlatformVariant + simulator + + + BinaryPath + rive.device.a + HeadersPath + Headers + LibraryIdentifier + tvos-arm64 + LibraryPath + rive.device.a + SupportedArchitectures + + arm64 + + SupportedPlatform + tvos + + + CFBundlePackageType + XFWK + XCFrameworkFormatVersion + 1.0 + + diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/tvOS/rive.xcframework/tvos-arm64/Headers/rive_unity.h b/Packages/app.rive.rive-unity/Runtime/Libraries/tvOS/rive.xcframework/tvos-arm64/Headers/rive_unity.h new file mode 100644 index 00000000..c59c2e8a --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/tvOS/rive.xcframework/tvos-arm64/Headers/rive_unity.h @@ -0,0 +1 @@ +/* Rive Unity XCFramework */ diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/tvOS/rive.xcframework/tvos-arm64/rive.device.a b/Packages/app.rive.rive-unity/Runtime/Libraries/tvOS/rive.xcframework/tvos-arm64/rive.device.a new file mode 100644 index 00000000..15d3b868 Binary files /dev/null and b/Packages/app.rive.rive-unity/Runtime/Libraries/tvOS/rive.xcframework/tvos-arm64/rive.device.a differ diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/tvOS/rive.xcframework/tvos-arm64_x86_64-simulator/Headers/rive_unity.h b/Packages/app.rive.rive-unity/Runtime/Libraries/tvOS/rive.xcframework/tvos-arm64_x86_64-simulator/Headers/rive_unity.h new file mode 100644 index 00000000..c59c2e8a --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/tvOS/rive.xcframework/tvos-arm64_x86_64-simulator/Headers/rive_unity.h @@ -0,0 +1 @@ +/* Rive Unity XCFramework */ diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/tvOS/rive.xcframework/tvos-arm64_x86_64-simulator/rive.simulator.a b/Packages/app.rive.rive-unity/Runtime/Libraries/tvOS/rive.xcframework/tvos-arm64_x86_64-simulator/rive.simulator.a new file mode 100644 index 00000000..62b46df2 Binary files /dev/null and b/Packages/app.rive.rive-unity/Runtime/Libraries/tvOS/rive.xcframework/tvos-arm64_x86_64-simulator/rive.simulator.a differ diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/visionOS.meta b/Packages/app.rive.rive-unity/Runtime/Libraries/visionOS.meta new file mode 100644 index 00000000..aa4c74e7 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/visionOS.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 30d3332567f954b67b0f8da7c275ec59 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/visionOS/rive.xcframework.meta b/Packages/app.rive.rive-unity/Runtime/Libraries/visionOS/rive.xcframework.meta new file mode 100644 index 00000000..03e46520 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/visionOS/rive.xcframework.meta @@ -0,0 +1,101 @@ +fileFormatVersion: 2 +guid: c7554fca848c0497ba3f219fe523167b +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : Any + second: + enabled: 0 + settings: + Exclude Android: 1 + Exclude Editor: 1 + Exclude Linux64: 1 + Exclude OSXUniversal: 1 + Exclude VisionOS: 0 + Exclude WebGL: 1 + Exclude Win: 1 + Exclude Win64: 1 + Exclude iOS: 1 + Exclude tvOS: 1 + - first: + Android: Android + second: + enabled: 0 + settings: + AndroidSharedLibraryType: Executable + CPU: ARMv7 + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + CPU: AnyCPU + DefaultValueInitialized: true + OS: AnyOS + - first: + Standalone: Linux64 + second: + enabled: 0 + settings: + CPU: None + - first: + Standalone: OSXUniversal + second: + enabled: 0 + settings: + CPU: None + - first: + Standalone: Win + second: + enabled: 0 + settings: + CPU: None + - first: + Standalone: Win64 + second: + enabled: 0 + settings: + CPU: None + - first: + VisionOS: VisionOS + second: + enabled: 1 + settings: + AddToEmbeddedBinaries: false + CPU: AnyCPU + CompileFlags: + FrameworkDependencies: ImageIO; + - first: + iPhone: iOS + second: + enabled: 0 + settings: + AddToEmbeddedBinaries: false + CPU: AnyCPU + CompileFlags: + FrameworkDependencies: + - first: + tvOS: tvOS + second: + enabled: 0 + settings: + CPU: AnyCPU + CompileFlags: + FrameworkDependencies: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/visionOS/rive.xcframework/Info.plist b/Packages/app.rive.rive-unity/Runtime/Libraries/visionOS/rive.xcframework/Info.plist new file mode 100644 index 00000000..0b846aa6 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/visionOS/rive.xcframework/Info.plist @@ -0,0 +1,48 @@ + + + + + AvailableLibraries + + + BinaryPath + rive.simulator.a + HeadersPath + Headers + LibraryIdentifier + xros-arm64_x86_64-simulator + LibraryPath + rive.simulator.a + SupportedArchitectures + + arm64 + x86_64 + + SupportedPlatform + xros + SupportedPlatformVariant + simulator + + + BinaryPath + rive.device.a + HeadersPath + Headers + LibraryIdentifier + xros-arm64 + LibraryPath + rive.device.a + SupportedArchitectures + + arm64 + + SupportedPlatform + xros + + + CFBundlePackageType + XFWK + XCFrameworkFormatVersion + 1.0 + + diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/visionOS/rive.xcframework/xros-arm64/Headers/rive_unity.h b/Packages/app.rive.rive-unity/Runtime/Libraries/visionOS/rive.xcframework/xros-arm64/Headers/rive_unity.h new file mode 100644 index 00000000..c59c2e8a --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/visionOS/rive.xcframework/xros-arm64/Headers/rive_unity.h @@ -0,0 +1 @@ +/* Rive Unity XCFramework */ diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/visionOS/rive.xcframework/xros-arm64/rive.device.a b/Packages/app.rive.rive-unity/Runtime/Libraries/visionOS/rive.xcframework/xros-arm64/rive.device.a new file mode 100644 index 00000000..516b9b68 Binary files /dev/null and b/Packages/app.rive.rive-unity/Runtime/Libraries/visionOS/rive.xcframework/xros-arm64/rive.device.a differ diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/visionOS/rive.xcframework/xros-arm64_x86_64-simulator/Headers/rive_unity.h b/Packages/app.rive.rive-unity/Runtime/Libraries/visionOS/rive.xcframework/xros-arm64_x86_64-simulator/Headers/rive_unity.h new file mode 100644 index 00000000..c59c2e8a --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Libraries/visionOS/rive.xcframework/xros-arm64_x86_64-simulator/Headers/rive_unity.h @@ -0,0 +1 @@ +/* Rive Unity XCFramework */ diff --git a/Packages/app.rive.rive-unity/Runtime/Libraries/visionOS/rive.xcframework/xros-arm64_x86_64-simulator/rive.simulator.a b/Packages/app.rive.rive-unity/Runtime/Libraries/visionOS/rive.xcframework/xros-arm64_x86_64-simulator/rive.simulator.a new file mode 100644 index 00000000..19f0cab7 Binary files /dev/null and b/Packages/app.rive.rive-unity/Runtime/Libraries/visionOS/rive.xcframework/xros-arm64_x86_64-simulator/rive.simulator.a differ diff --git a/Packages/app.rive.rive-unity/Runtime/OutOfBandAsset.cs b/Packages/app.rive.rive-unity/Runtime/OutOfBandAsset.cs new file mode 100644 index 00000000..50a61b29 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/OutOfBandAsset.cs @@ -0,0 +1,128 @@ +using UnityEngine; +using System; +using System.Collections.Generic; + +namespace Rive +{ + /// + /// Interface for out-of-band assets. + /// + public interface IOutOfBandAsset + { + void Load(); + void Unload(); + } + + /// + /// Represents an out-of-band Rive asset. + /// + /// Out-of-band assets are assets that are referenced in a Rive asset, but are not + /// part of the Rive asset itself. For example, images and fonts can be marked as + /// referenced and linked separately. + /// + public abstract class OutOfBandAsset : ScriptableObject, IOutOfBandAsset + { + [HideInInspector] + [SerializeField] + private byte[] bytes; + + [NonSerialized] + private int m_refCount; + + [NonSerialized] + private IntPtr m_nativeAsset = IntPtr.Zero; + + protected abstract IntPtr LoadNative(byte[] bytes); + protected abstract void UnloadNative(IntPtr nativePtr); + + internal IntPtr NativeAsset { get { return m_nativeAsset; } } + + /// + /// The raw bytes of the out-of-band asset. + /// + public byte[] Bytes { get { return bytes; } } + + /// + /// Create an out-of-band asset instance from the given bytes. + /// + /// + /// + /// The created out-of-band asset instance. + public static T Create(byte[] bytes) where T : OutOfBandAsset + { + var asset = ScriptableObject.CreateInstance(); + asset.Init(bytes); + return asset; + } + + private void Init(byte[] bytes) + { + this.bytes = bytes; + } + + internal void LoadIntoByteAssetMap(uint embeddedAssetId, EmbeddedAssetType embeddedAssetType, List assetMap) + { + // Write it into the asset map if the native asset was succesfully loaded. + if (NativeAsset != IntPtr.Zero) + { + var bytes = BitConverter.GetBytes(embeddedAssetId); + for (int j = 0; j < bytes.Length; j++) + { + assetMap.Add(bytes[j]); + } + bytes = BitConverter.GetBytes((ushort)embeddedAssetType); + for (int j = 0; j < bytes.Length; j++) + { + assetMap.Add(bytes[j]); + } +#if UNITY_WEBGL && !UNITY_EDITOR + // nint is incorrectly reported as 64 bit on wasm which would + // break Rive's native code. + bytes = BitConverter.GetBytes((int)NativeAsset); +#else + bytes = BitConverter.GetBytes((nint)NativeAsset); +#endif + for (int j = 0; j < bytes.Length; j++) + { + assetMap.Add(bytes[j]); + } + } + } + + + /// + /// Load the out-of-band asset. Call this before using the asset. + /// + public void Load() + { + if (m_refCount == 0) + { + m_nativeAsset = LoadNative(bytes); + } + m_refCount++; + } + + /// + /// Unload the out-of-band asset. This allows the engine to clean it up when it is not used by any more animations. + /// + public void Unload() + { + m_refCount--; + if (m_refCount == 0) + { + IntPtr nativeAsset = m_nativeAsset; + m_nativeAsset = IntPtr.Zero; + UnloadNative(nativeAsset); + } + } + + /// + /// Check the reference count of the out-of-band asset. + /// + /// + internal int RefCount() + { + return m_refCount; + } + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/OutOfBandAsset.cs.meta b/Packages/app.rive.rive-unity/Runtime/OutOfBandAsset.cs.meta new file mode 100644 index 00000000..33a85330 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/OutOfBandAsset.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 54fc4eefc90d440ba9d07e739397d003 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/OutOfBandAsset.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/PackageInfo.cs b/Packages/app.rive.rive-unity/Runtime/PackageInfo.cs new file mode 100644 index 00000000..3e4e3ecb --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/PackageInfo.cs @@ -0,0 +1,8 @@ +namespace Rive.EditorTools +{ + public class PackageInfo + { + public const string PACKAGE_NAME = "app.rive.rive-unity"; + + } +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Runtime/PackageInfo.cs.meta b/Packages/app.rive.rive-unity/Runtime/PackageInfo.cs.meta new file mode 100644 index 00000000..f04b43b8 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/PackageInfo.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 83ed0c391b8ca4f1692427468383c947 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/PackageInfo.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/RenderQueue.cs b/Packages/app.rive.rive-unity/Runtime/RenderQueue.cs new file mode 100644 index 00000000..aa611a12 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/RenderQueue.cs @@ -0,0 +1,624 @@ +using System; +using System.Collections; +using System.Runtime.InteropServices; +using UnityEngine; +using UnityEngine.Rendering; +using System.Numerics; + +namespace Rive +{ + public class RiveCommandBuffer : CommandBuffer + { + private readonly Renderer m_renderer; + + public RiveCommandBuffer(Renderer renderer) + { + m_renderer = renderer; + } + } + + internal class CoroutineRunner : MonoBehaviour {} + + public class Renderer : IRenderer + { + protected RenderQueue m_renderQueue; + private IntPtr m_nativeRenderQueue = IntPtr.Zero; + private uint m_index; + + internal Renderer(RenderQueue queue) + { + m_renderQueue = queue; + m_nativeRenderQueue = queue.m_nativeRenderQueue; + m_index = getNextCommandBufferIndex(m_nativeRenderQueue); + } + + internal RenderQueue RenderQueue => m_renderQueue; + + void Release() + { + releaseCommandBuffer(m_nativeRenderQueue, m_index); + } + /// + /// Clear the commands in the render queue. + /// + public void Clear() + { + clearCommandBuffer(m_nativeRenderQueue, m_index); + } + + /// + /// Enables/disables checking whether any artboards referenced by this render queue have dirt (didChange) + /// to decide if a render should occur. + /// This is a render-queue level setting: if any artboard in the queue has dirt, the entire queue can redraw. + /// + internal void SetArtboardDirtCheckEnabled(bool enabled) + { + setRenderQueueArtboardDirtCheckEnabled(m_nativeRenderQueue, enabled); + } + + + /// + /// Draw the given artboard to the render queue. + /// + public void Draw(Artboard artboard) + { + if (artboard == null) + { + throw new ArgumentException("A non null artboard must be provided."); + } + renderQueueDrawArtboard(m_nativeRenderQueue, m_index, artboard.NativeArtboard); + } + + /// + /// Draw the given path and paint to the render queue. + /// + public void Draw(Path path, Paint paint) + { + renderQueueDrawPath(m_nativeRenderQueue, m_index, path.NativePath, paint.NativePaint); + } + + /// + /// Clip the render queue to the given path. + /// + public void Clip(Path path) + { + renderQueueClipPath(m_nativeRenderQueue, m_index, path.NativePath); + } + + /// + /// Save the current render queue state. + /// + public void Save() + { + renderQueueSave(m_nativeRenderQueue, m_index); + } + + /// + /// Restore the last saved render queue state. + /// + public void Restore() + { + renderQueueRestore(m_nativeRenderQueue, m_index); + } + + /// + /// Transform the render queue by the given translation. + /// + public void Translate(System.Numerics.Vector2 translation) + { + renderQueueTransform( + m_nativeRenderQueue, + m_index, + 1.0f, + 0.0f, + 0.0f, + 1.0f, + translation.X, + translation.Y + ); + } + + /// + /// Transform the render queue by the given translation. + /// + public void Translate(float x, float y) + { + renderQueueTransform(m_nativeRenderQueue, m_index, 1.0f, 0.0f, 0.0f, 1.0f, x, y); + } + + /// + /// Transform the render queue by the given matrix. + /// + public void Transform(Matrix3x2 matrix) + { + renderQueueTransform( + m_nativeRenderQueue, + m_index, + matrix.M11, + matrix.M12, + matrix.M21, + matrix.M22, + matrix.M31, + matrix.M32 + ); + } + + /// + /// Align the artboard to the given fit and alignment. + /// + public void Align(Fit fit, Alignment alignment, Artboard artboard, float scaleFactor = 1.0f) + { + if (artboard == null) + { + throw new ArgumentException("A non null artboard must be provided."); + } + renderQueueAlign( + m_nativeRenderQueue, + m_index, + (byte)fit, + alignment.X, + alignment.Y, + artboard.NativeArtboard, + scaleFactor + ); + } + + /// + /// Align the artboard to the given fit and alignment, with the given frame. + /// + public void Align(Fit fit, Alignment alignment, Artboard artboard, AABB frame, float scaleFactor = 1.0f) + { + renderQueueAlignWithFrame( + m_nativeRenderQueue, + m_index, + (byte)fit, + alignment.X, + alignment.Y, + artboard.NativeArtboard, + frame.minX, + frame.minY, + frame.maxX, + frame.maxY, + scaleFactor + ); + } + + public void Submit() + { + var commandBuffer = new RiveCommandBuffer(this); + if (m_renderQueue.Texture != null) + { + commandBuffer.SetRenderTarget(m_renderQueue.Texture); + } + + m_renderQueue.UpdateDelayedRenderTexture(); + + commandBuffer.IssuePluginEventAndData( + getRenderCommandBufferCallback(), + (int)m_index, + m_nativeRenderQueue + ); + Graphics.ExecuteCommandBuffer(commandBuffer); + } + + public void SubmitAndRelease() + { + var commandBuffer = new RiveCommandBuffer(this); + if (m_renderQueue.Texture != null) + { + commandBuffer.SetRenderTarget(m_renderQueue.Texture); + } + + m_renderQueue.UpdateDelayedRenderTexture(); + + commandBuffer.IssuePluginEventAndData( + getRenderAndReleaseCommandBufferCallback(), + (int)m_index, + m_nativeRenderQueue + ); + Graphics.ExecuteCommandBuffer(commandBuffer); + } + + public CommandBuffer ToCommandBuffer() + { + var commandBuffer = new RiveCommandBuffer(this); + AddToCommandBuffer(commandBuffer); + return commandBuffer; + } + + public void AddToCommandBuffer(CommandBuffer commandBuffer, bool release = false) + { + + if ( + UnityEngine.SystemInfo.graphicsDeviceType + == UnityEngine.Rendering.GraphicsDeviceType.Metal + ) + { + // Unity seems to have the wrong texture bound when querying the + // exposed CurrentRenderPassDescriptor's colorAttachment. This + // forces the Metal backend to catch up. + commandBuffer.DrawMesh( + GetResetMesh(), + new UnityEngine.Matrix4x4(), + GetResetMaterial() + ); + } + + m_renderQueue.UpdateDelayedRenderTexture(); + + commandBuffer.IssuePluginEventAndData( + release + ? getRenderAndReleaseCommandBufferCallback() + : getRenderCommandBufferCallback(), + (int)m_index, + m_nativeRenderQueue + ); + commandBuffer.IssuePluginEvent(getInvalidateState(), 0); + } + +#if UNITY_2023_1_OR_NEWER && RIVE_USING_URP + + public void AddToCommandBuffer(UnsafeCommandBuffer commandBuffer, bool release = false) + { + + if ( + UnityEngine.SystemInfo.graphicsDeviceType + == UnityEngine.Rendering.GraphicsDeviceType.Metal + ) + { + // Unity seems to have the wrong texture bound when querying the + // exposed CurrentRenderPassDescriptor's colorAttachment. This + // forces the Metal backend to catch up. + commandBuffer.DrawMesh( + GetResetMesh(), + new UnityEngine.Matrix4x4(), + GetResetMaterial() + ); + } + + m_renderQueue.UpdateDelayedRenderTexture(); + + commandBuffer.IssuePluginEventAndData( + release + ? getRenderAndReleaseCommandBufferCallback() + : getRenderCommandBufferCallback(), + (int)m_index, + m_nativeRenderQueue + ); + commandBuffer.IssuePluginEvent(getInvalidateState(), 0); + } + +#endif + + private static Material m_resetMaterial; + private static Mesh m_resetMesh; + + private static Material GetResetMaterial() + { + if (m_resetMaterial == null) + { + m_resetMaterial = new Material(UnityEngine.Shader.Find("UI/Default")); + } + return m_resetMaterial; + } + + private static Mesh GetResetMesh() + { + if (m_resetMesh == null) + { + m_resetMesh = new Mesh(); + } + return m_resetMesh; + } + + #region Native Methods + [DllImport(NativeLibrary.name)] + protected static extern uint getNextCommandBufferIndex(IntPtr renderQueue); + + [DllImport(NativeLibrary.name)] + internal static extern IntPtr getRenderCommandBufferCallback(); + + [DllImport(NativeLibrary.name)] + internal static extern void releaseCommandBuffer( + IntPtr renderQueue, + uint commandBufferIndex + ); + + [DllImport(NativeLibrary.name)] + internal static extern void clearCommandBuffer( + IntPtr renderQueue, + uint commandBufferIndex + ); + + [DllImport(NativeLibrary.name)] + internal static extern void setRenderQueueArtboardDirtCheckEnabled( + IntPtr renderQueue, + bool enabled + ); + + + + [DllImport(NativeLibrary.name)] + internal static extern void renderQueueDrawArtboard( + IntPtr renderQueue, + uint commandBufferIndex, + IntPtr artboard + ); + + [DllImport(NativeLibrary.name)] + internal static extern void renderQueueDrawPath( + IntPtr renderQueue, + uint commandBufferIndex, + IntPtr path, + IntPtr Paint + ); + + [DllImport(NativeLibrary.name)] + internal static extern void renderQueueClipPath( + IntPtr renderQueue, + uint commandBufferIndex, + IntPtr path + ); + + [DllImport(NativeLibrary.name)] + internal static extern void renderQueueSave(IntPtr renderQueue, uint commandBufferIndex); + + [DllImport(NativeLibrary.name)] + internal static extern void renderQueueRestore(IntPtr renderQueue, uint commandBufferIndex); + + [DllImport(NativeLibrary.name)] + internal static extern void renderQueueTransform( + IntPtr renderQueue, + uint commandBufferIndex, + float xx, + float xy, + float yx, + float yy, + float tx, + float ty + ); + + [DllImport(NativeLibrary.name)] + internal static extern void renderQueueAlign( + IntPtr renderQueue, + uint commandBufferIndex, + byte fit, + float alignX, + float alignY, + IntPtr artboard, + float scaleFactor + ); + + [DllImport(NativeLibrary.name)] + internal static extern void renderQueueAlignWithFrame( + IntPtr renderQueue, + uint commandBufferIndex, + byte fit, + float alignX, + float alignY, + IntPtr artboard, + float minX, + float minY, + float maxX, + float maxY, + float scaleFactor + ); + + + + [DllImport(NativeLibrary.name)] + internal static extern IntPtr getRenderAndReleaseCommandBufferCallback(); + + [DllImport(NativeLibrary.name)] + internal static extern IntPtr getInvalidateState(); + #endregion + } + + public class RenderQueue : IDisposable + { + private bool m_disposed = false; + + // When using Vulkan we need to pass the RenderTexture.colorBuffer's + // native pointer. This colorBuffer's native pointer sometimes returns 0 + // (null) even after calling RenderTexture.Create. In these rare cases + // we hold onto it to try to re-acquire it prior to the next submission. + private bool m_delayed = false; + + public RenderTexture Texture { get; private set; } + + + private void Initialize(RenderTexture texture, bool clear) + { + m_updateDelayedCallback = UpdateDelayedRenderTexture; + + Texture = texture; + ValidateRenderTexture(texture, true); + if (texture != null) + { + texture.Create(); + } + m_nativeRenderQueue = makeRenderQueue( + texture == null ? IntPtr.Zero : + GetNativeTexturePointer(texture), + (uint)(texture?.width ?? 0), + (uint)(texture?.height ?? 0), + clear + ); + } + + public RenderQueue(RenderTexture texture = null, bool clear = true) + { + Initialize(texture, clear); + } + + internal RenderQueue(RenderTexture texture, bool clear, MonoBehaviour coroutineHelper) + { + CoroutineHelper = coroutineHelper; + Initialize(texture, clear); + } + + public Renderer Renderer() + { + return new Renderer(this); + } + + ~RenderQueue() + { + Dispose(false); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (!m_disposed) + { + if (m_nativeRenderQueue != IntPtr.Zero) + { + unrefRenderQueue(m_nativeRenderQueue); + m_nativeRenderQueue = IntPtr.Zero; + } + + Texture = null; + m_disposed = true; + } + } + + static void ValidateRenderTexture(RenderTexture texture, bool allowNull = false) + { + if (allowNull && texture == null) + { + return; + } + if (texture == null) + { + throw new ArgumentException("A non null RenderTexture must be provided."); + } + if ( + UnityEngine.SystemInfo.graphicsDeviceType + == UnityEngine.Rendering.GraphicsDeviceType.Direct3D11 + && !texture.enableRandomWrite + ) + { + throw new ArgumentException( + "RenderTexture must have enableRandomWrite set to true for D3D11." + ); + } + } + + + static WaitForEndOfFrame s_waitForEndOfFrame = new WaitForEndOfFrame(); + private CallbackEventHandler m_updateDelayedCallback; + + private static MonoBehaviour s_coroutineHelper; + + /// + /// Used to run coroutines for the render queue. Needs to be a dontdestroyonload object so that it can be used across scenes. + /// + internal MonoBehaviour CoroutineHelper { get { return s_coroutineHelper; } set { s_coroutineHelper = value; } } + + private delegate void CallbackEventHandler(); + private static IEnumerator CallCallback(CallbackEventHandler callback) + { + yield return s_waitForEndOfFrame; + callback(); + } + + private static void EndOfFrame(CallbackEventHandler callback) + { + if (Application.isPlaying) + { + if (s_coroutineHelper == null) { + s_coroutineHelper = new GameObject("[Rive] RenderQueue Coroutine Helper").AddComponent();; + UnityEngine.Object.DontDestroyOnLoad(s_coroutineHelper.gameObject); + } + s_coroutineHelper.StartCoroutine(CallCallback(callback)); + } + } + + private IntPtr GetNativeTexturePointer(RenderTexture texture) + { + if(UnityEngine.SystemInfo.graphicsDeviceType + == UnityEngine.Rendering.GraphicsDeviceType.Vulkan) + { + IntPtr pointer = texture.colorBuffer.GetNativeRenderBufferPtr(); + if(pointer == IntPtr.Zero) + { + texture.Create(); + pointer = texture.colorBuffer.GetNativeRenderBufferPtr(); + if(pointer == IntPtr.Zero) + { + m_delayed = true; + EndOfFrame(m_updateDelayedCallback); + } + } + return pointer; + } + return texture.GetNativeTexturePtr(); + } + + internal void UpdateDelayedRenderTexture() + { + if(!m_delayed || Texture == null) + { + return; + } + IntPtr pointer = GetNativeTexturePointer(Texture); + // Make sure null pointers are set too or the native side could be + // left with an invalid/discarded texture. + renderQueueUpdateRenderTexture( + m_nativeRenderQueue, + pointer, + (uint)Texture.width, + (uint)Texture.height + ); + m_delayed = false; + } + + /// + /// Update the render queue's target texture. + /// + public void UpdateTexture(RenderTexture texture) + { + ValidateRenderTexture(texture); + IntPtr pointer = GetNativeTexturePointer(texture); + renderQueueUpdateRenderTexture( + m_nativeRenderQueue, + pointer, + (uint)texture.width, + (uint)texture.height + ); + Texture = texture; + } + + internal IntPtr m_nativeRenderQueue = IntPtr.Zero; + + #region Native Methods + [DllImport(NativeLibrary.name)] + protected static extern IntPtr makeRenderQueue( + IntPtr renderTexture, + uint width, + uint height, + bool clear + ); + + [DllImport(NativeLibrary.name)] + internal static extern void unrefRenderQueue(IntPtr renderQueue); + + [DllImport(NativeLibrary.name)] + internal static extern void renderQueueUpdateRenderTexture( + IntPtr renderQueue, + IntPtr texture, + uint width, + uint heigh + ); + + [DllImport(NativeLibrary.name)] + public static extern bool supportsDrawingToScreen(); + #endregion + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/RenderQueue.cs.meta b/Packages/app.rive.rive-unity/Runtime/RenderQueue.cs.meta new file mode 100644 index 00000000..f9296cd2 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/RenderQueue.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: a1fab2ef69b014d80a91001c19f12d2b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/RenderQueue.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Renderer.cs b/Packages/app.rive.rive-unity/Runtime/Renderer.cs new file mode 100644 index 00000000..7ebeccaf --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Renderer.cs @@ -0,0 +1,793 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Numerics; +using System.Diagnostics; + +namespace Rive +{ + public abstract class Gradient + { + private Vector2 m_start; + private readonly List m_colors; + private readonly List m_stops; + + /// + /// The start point of the gradient. + /// + public Vector2 Start => m_start; + + /// + /// The list of colors in the gradient. + /// + public List Colors => m_colors; + + /// + /// The list of stops in the gradient. + /// + public List Stops => m_stops; + + public Gradient(Vector2 start, List colors, List stops) + { + m_start = start; + m_colors = colors; + m_stops = stops; + } + } + + /// + /// A radial gradient. The gradient will be a circle with the given radius + /// centered at the start point. + /// + /// Provide a list of colors and stops to define the gradient. + /// + public class RadialGradient : Gradient + { + private readonly float m_radius; + + public RadialGradient(Vector2 start, float radius, List colors, List stops) + : base(start, colors, stops) + { + m_radius = radius; + } + + public float Radius + { + get { return m_radius; } + } + } + + /// + /// A linear gradient. The gradient will be a line from the start point to the + /// end point. + /// + /// Provide a list of colors and stops to define the gradient. + /// + public class LinearGradient : Gradient + { + private Vector2 m_end; + + public LinearGradient(Vector2 start, Vector2 end, List colors, List stops) + : base(start, colors, stops) + { + m_end = end; + } + + public Vector2 End => m_end; + } + + enum PathVerb : byte + { + Move = 0, + Line = 1, + Quad = 2, + Cubic = 4, + Close = 5 + } + + /// + /// A path is a series of drawing commands. The path is used to define the + /// outline of a shape or to define a clipping mask. + /// + /// Paths are built by calling moveTo, lineTo, quadTo, cubicTo, close, etc. + /// + public class Path + { + IntPtr m_nativePath = IntPtr.Zero; + private readonly List m_verbs = new(); + private readonly List m_points = new(); + + internal const int scratchSize = 1024; + internal static byte[] scratchBuffer = new byte[scratchSize]; + + ~Path() + { + unrefRenderPath(m_nativePath); + } + + internal IntPtr NativePath + { + get + { + Flush(); + return m_nativePath; + } + } + + private int VerbPointCount(PathVerb verb) + { + switch (verb) + { + case PathVerb.Close: + return 0; + case PathVerb.Line: + case PathVerb.Move: + return 1; + case PathVerb.Quad: + return 2; + case PathVerb.Cubic: + return 3; + default: + return 0; + } + } + + /// + /// Resets the path to an empty state. + /// + /// This is called automatically when the path is flushed (see flush). + /// + public void Reset() + { + m_verbs.Clear(); + m_points.Clear(); + } + + /// + /// Closes the path. This will draw a line from the current point to the + /// first point in the path. + /// + public void Close() + { + m_verbs.Add((byte)PathVerb.Close); + } + + /// + /// Adds a cubic bezier curve to the path. + /// + /// The curve starts at the current point and ends at the given point (x, y). + /// The control points (ox, oy) and (ix, iy) are used to define the curve. + /// + public void CubicTo(float ox, float oy, float ix, float iy, float x, float y) + { + m_points.Add(ox); + m_points.Add(oy); + m_points.Add(ix); + m_points.Add(iy); + m_points.Add(x); + m_points.Add(y); + m_verbs.Add((byte)PathVerb.Cubic); + } + + /// + /// Adds a circle to the path. + /// + /// The circle is centered at (centerX, centerY) and has the given radius. + /// + public void Circle(float centerX, float centerY, float radius) + { + const float circleConstant = 0.552284749831f; + + float ox = centerX; + float oy = centerY; + float radiusY = radius; + float radiusX = radius; + MoveTo(ox, oy - radiusY); + + CubicTo( + ox + radiusX * circleConstant, + oy - radiusY, + ox + radiusX, + oy + circleConstant * -radiusY, + ox + radiusX, + oy + ); + + CubicTo( + ox + radiusX, + oy + circleConstant * radiusY, + ox + radiusX * circleConstant, + oy + radiusY, + ox, + oy + radiusY + ); + + CubicTo( + ox - radiusX * circleConstant, + oy + radiusY, + ox - radiusX, + oy + radiusY * circleConstant, + ox - radiusX, + oy + ); + + CubicTo( + ox - radiusX, + oy - radiusY * circleConstant, + ox - radiusX * circleConstant, + oy - radiusY, + ox, + oy - radiusY + ); + } + + /// + /// Adds a quadratic bezier segment that curves from the current point + /// to the given point (x,y), using the control point (cx,cy). + /// + public void QuadTo(float cx, float cy, float x, float y) + { + m_points.Add(cx); + m_points.Add(cy); + m_points.Add(x); + m_points.Add(y); + m_verbs.Add((byte)PathVerb.Quad); + } + + /// + /// Adds a straight line from the current point to the given point (x,y). + /// + public void LineTo(float x, float y) + { + m_points.Add(x); + m_points.Add(y); + m_verbs.Add((byte)PathVerb.Line); + } + + /// + /// Moves the current point to the given point (x,y). + /// + public void MoveTo(float x, float y) + { + m_points.Add(x); + m_points.Add(y); + m_verbs.Add((byte)PathVerb.Move); + } + + /// + /// Adds the sub-paths of path to this path, transformed by the provided matrix (Mat2D). + /// + public void AddPath(Path path, Matrix3x2 transform) + { + if (m_nativePath == null) + { + m_nativePath = makeEmptyRenderPath(); + } + addPathToPath( + m_nativePath, + path.m_nativePath, + transform.M11, + transform.M12, + transform.M21, + transform.M22, + transform.M31, + transform.M32 + ); + } + + /// + /// Flushes the path to native memory. + /// + public void Flush() + { + if (m_verbs.Count == 0) + { + if (m_nativePath == IntPtr.Zero) + { + m_nativePath = makeEmptyRenderPath(); + } + return; + } + + uint offset = 0; + int pointIndex = 0; + uint commandCount = 0; + + foreach (var verb in m_verbs) + { + int elementCount = VerbPointCount((PathVerb)verb) * 2; + int requiredSize = elementCount * 4 + 1; + if (requiredSize + offset >= scratchSize) + { + // Flush + appendCommands(scratchBuffer, commandCount); + offset = 0; + commandCount = 0; + } + scratchBuffer[offset++] = verb; + for (int i = 0; i < elementCount; i++) + { + var bytes = BitConverter.GetBytes(m_points[pointIndex++]); + for (int j = 0; j < 4; j++) + { + scratchBuffer[offset++] = bytes[j]; + } + } + commandCount++; + } + if (commandCount > 0) + { + appendCommands(scratchBuffer, commandCount); + } + if (m_nativePath != IntPtr.Zero) + { + unrefRenderPath(m_nativePath); + } + m_nativePath = makeRenderPath(); + + Reset(); + } + + #region Native Methods + [DllImport(NativeLibrary.name)] + private static extern void appendCommands(byte[] bytes, uint commandCount); + + [DllImport(NativeLibrary.name)] + private static extern IntPtr makeRenderPath(); + + [DllImport(NativeLibrary.name)] + private static extern IntPtr makeEmptyRenderPath(); + + [DllImport(NativeLibrary.name)] + private static extern void unrefRenderPath(IntPtr nativePath); + + [DllImport(NativeLibrary.name)] + private static extern void addPathToPath( + IntPtr to, + IntPtr from, + float x1, + float y1, + float x2, + float y2, + float tx, + float ty + ); + #endregion + } + + /// + /// Algorithms to use when painting on the canvas. + /// + /// When painting the algorithm is used to blend the source + /// pixels with the destination pixels. + /// + public enum BlendMode : byte + { + SrcOver = 3, + Screen = 14, + Overlay = 15, + Darken = 16, + Lighten = 17, + ColorDodge = 18, + ColorBurn = 19, + HardLight = 20, + SoftLight = 21, + Difference = 22, + Exclusion = 23, + Multiply = 24, + Hue = 25, + Saturation = 26, + Color = 27, + Luminosity = 28 + } + + /// + /// The style to use when painting on the canvas. + /// + /// When painting the style is used to determine if the + /// shape is filled or stroked. + /// + public enum PaintingStyle : byte + { + /// + /// Fill the shape. + /// + Fill = 0, + + /// + /// Stroke the shape. + /// + Stroke = 1 + } + + /// + /// The cap to use when stroking a path. + /// + /// When stroking a path the cap is used to determine how the + /// end points of the path are drawn. + /// + public enum StrokeCap : byte + { + /// + /// The end of the path is squared off. + /// + Butt = 0, + + /// + /// The end of the path is rounded. + /// + Round = 1, + + /// + /// The end of the path is squared off and extends past the end of the path. + /// + Square = 2 + } + + /// + /// The join to use when stroking a path. + /// + /// The kind of finish to place on the joins between segments. + /// + public enum StrokeJoin : byte + { + /// + /// Joins between segments are sharp. + /// + Miter = 0, + + /// + /// Joins between segments are rounded. + /// + Round = 1, + + /// + /// Joins between segments are beveled. + /// + Bevel = 2 + } + + [Flags] + internal enum PaintDirt : ushort + { + None = 0, + Style = 1 << 0, + Color = 1 << 1, + Thickness = 1 << 2, + Join = 1 << 3, + Cap = 1 << 4, + BlendMode = 1 << 5, + Radial = 1 << 6, // 0 == linear, 1 == radial only valid if stops != 0 + Done = 1 << 7, // 1 when no more gradien stops will follow, + + // Anything higher than 8 bits will not be written to native, but can be used + // as flags. + Gradient = 1 << 8, + } + + /// + /// A paint is used to describe how to draw a shape. + /// + /// The paint describes the color, gradient, style, thickness, etc. + /// + public class Paint + { + readonly IntPtr m_nativePaint; + BlendMode m_blendMode; + PaintDirt m_dirty = PaintDirt.None; + Color m_color = new(0x000000FF); + PaintingStyle m_style = PaintingStyle.Fill; + float m_thickness = 1.0f; + StrokeCap m_cap = StrokeCap.Butt; + StrokeJoin m_join = StrokeJoin.Bevel; + Gradient m_gradient; + + public Paint() + { + m_nativePaint = makeRenderPaint(); + } + + ~Paint() + { + unrefRenderPaint(m_nativePaint); + } + + internal IntPtr NativePaint + { + get + { + Flush(); + return m_nativePaint; + } + } + + /// + /// The blend mode to use when painting. + /// + /// When painting the blend mode is used to determine how the + /// source pixels are blended with the destination pixels. + /// + public BlendMode BlendMode + { + get { return m_blendMode; } + set + { + if (m_blendMode == value) + { + return; + } + m_blendMode = value; + m_dirty |= PaintDirt.BlendMode; + } + } + + /// + /// The color to use when painting. + /// + /// When painting the color is used to determine the color of the + /// shape. + /// + public Color Color + { + get { return m_color; } + set + { + if (m_color == value) + { + return; + } + m_color = value; + m_dirty |= PaintDirt.Color; + } + } + + /// + /// The style to use when painting. + /// + /// When painting the style is used to determine if the + /// shape is filled or stroked. + /// + public PaintingStyle Style + { + get { return m_style; } + set + { + if (m_style == value) + { + return; + } + m_style = value; + m_dirty |= PaintDirt.Style; + } + } + + /// + /// The thickness to use when stroking. + /// + public float Thickness + { + get { return m_thickness; } + set + { + if (m_thickness == value) + { + return; + } + m_thickness = value; + m_dirty |= PaintDirt.Thickness; + } + } + + /// + /// The join to use when stroking. + /// + /// The kind of finish to place on the joins between segments. + /// + public StrokeJoin Join + { + get { return m_join; } + set + { + if (m_join == value) + { + return; + } + m_join = value; + m_dirty |= PaintDirt.Join; + } + } + + /// + /// The cap to use when stroking. + /// + /// When stroking a path the cap is used to determine how the + /// end points of the path are drawn. + /// + public StrokeCap Cap + { + get { return m_cap; } + set + { + if (m_cap == value) + { + return; + } + m_cap = value; + m_dirty |= PaintDirt.Cap; + } + } + + /// + /// The gradient to use when painting. + /// + /// When painting the gradient is used to determine the color of the + /// shape. + /// + public Gradient Gradient + { + get { return m_gradient; } + set + { + if (m_gradient == value) + { + return; + } + m_gradient = value; + m_dirty |= PaintDirt.Gradient; + } + } + + /// + /// Flushes the paint to native memory. + /// + public void Flush() + { + if (m_dirty == PaintDirt.None) + { + return; + } + + int offset = 0; + var buffer = Path.scratchBuffer; + + if ((m_dirty & PaintDirt.Style) != 0) + { + buffer[offset++] = (byte)(m_style == PaintingStyle.Stroke ? 0 : 1); + } + if ((m_dirty & PaintDirt.Color) != 0) + { + var bytes = BitConverter.GetBytes(m_color.value); + for (int j = 0; j < 4; j++) + { + buffer[offset++] = bytes[j]; + } + } + if ((m_dirty & PaintDirt.Thickness) != 0) + { + var bytes = BitConverter.GetBytes(m_thickness); + for (int j = 0; j < 4; j++) + { + buffer[offset++] = bytes[j]; + } + } + if ((m_dirty & PaintDirt.Join) != 0) + { + buffer[offset++] = (byte)m_join; + } + if ((m_dirty & PaintDirt.Cap) != 0) + { + buffer[offset++] = (byte)m_cap; + } + if ((m_dirty & PaintDirt.BlendMode) != 0) + { + buffer[offset++] = (byte)m_blendMode; + } + + uint wroteStops = 0; + if (m_gradient != null) + { + var isRadial = m_gradient is RadialGradient; + int writeStopIndex = 0; + while (true) + { + if (isRadial) + { + m_dirty |= PaintDirt.Radial; + } + var remaining = Path.scratchSize - offset - 16; + int stopsAvailable = remaining / 8; + var stopsToWrite = Math.Min( + stopsAvailable, + (Gradient.Stops.Count - writeStopIndex) + ); + for (int i = 0; i < stopsToWrite; i++) + { + wroteStops++; + + var bytes = BitConverter.GetBytes(Gradient.Stops[writeStopIndex]); + for (int j = 0; j < 4; j++) + { + buffer[offset++] = bytes[j]; + } + + bytes = BitConverter.GetBytes(Gradient.Colors[writeStopIndex].value); + for (int j = 0; j < 4; j++) + { + buffer[offset++] = bytes[j]; + } + + writeStopIndex++; + } + + if (Gradient.Stops.Count - writeStopIndex == 0) + { + var bytes = BitConverter.GetBytes(Gradient.Start.X); + for (int j = 0; j < 4; j++) + { + buffer[offset++] = bytes[j]; + } + + bytes = BitConverter.GetBytes(Gradient.Start.Y); + for (int j = 0; j < 4; j++) + { + buffer[offset++] = bytes[j]; + } + if (isRadial) + { + var radial = Gradient as RadialGradient; + bytes = BitConverter.GetBytes(radial.Radius); + for (int j = 0; j < 4; j++) + { + buffer[offset++] = bytes[j]; + } + } + else + { + var linear = Gradient as LinearGradient; + bytes = BitConverter.GetBytes(linear.End.Y); + for (int j = 0; j < 4; j++) + { + buffer[offset++] = bytes[j]; + } + bytes = BitConverter.GetBytes(linear.End.Y); + for (int j = 0; j < 4; j++) + { + buffer[offset++] = bytes[j]; + } + } + + // Stop looping, we've built the gradient. + m_dirty |= PaintDirt.Done; + break; + } + else + { + // Gotta flush, we're out of space. + updatePaint(m_nativePaint, (ushort)m_dirty, buffer, wroteStops); + wroteStops = 0; + m_dirty = PaintDirt.None; + offset = 0; + } + } + } + updatePaint(m_nativePaint, (ushort)m_dirty, buffer, wroteStops); + m_dirty = PaintDirt.None; + } + + #region Native Methods + [DllImport(NativeLibrary.name)] + private static extern IntPtr makeRenderPaint(); + + [DllImport(NativeLibrary.name)] + private static extern void unrefRenderPaint(IntPtr nativePaint); + + [DllImport(NativeLibrary.name)] + private static extern void updatePaint( + IntPtr nativePaint, + ushort dirt, + byte[] bytes, + uint stops + ); + #endregion + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/Renderer.cs.meta b/Packages/app.rive.rive-unity/Runtime/Renderer.cs.meta new file mode 100644 index 00000000..6c7d2d2b --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Renderer.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 49a810ce86a194742a4335aabb0ff97c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Renderer.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/ReportedEvent.cs b/Packages/app.rive.rive-unity/Runtime/ReportedEvent.cs new file mode 100644 index 00000000..cedc4dc3 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/ReportedEvent.cs @@ -0,0 +1,371 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using UnityEngine.Pool; + +namespace Rive +{ + [StructLayout(LayoutKind.Sequential)] + internal struct ReportedEventData + { + public IntPtr nativeEvent; + public float secondsDelay; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct UnityCustomProperty + { + public IntPtr nativeProperty; + public IntPtr name; + public ushort type; + } + + + /// + /// Represents an event reported by a StateMachine. + /// + public class ReportedEvent : IDisposable + { + private static readonly ObjectPool s_Pool = new ObjectPool(actionOnGet: (ReportedEvent e) => { }, actionOnRelease: (ReportedEvent e) => { }, createFunc: () => new ReportedEvent()); + + /// + /// Factory method to retrieve a pooled instance. + /// + internal static ReportedEvent GetPooled(ReportedEventData data) + { + var evt = s_Pool.Get(); + evt.Initialize(data); + return evt; + } + + private bool m_isDisposed; + + + private float m_secondsDelay; + private string m_name; + private uint m_propertyCount; + private ushort m_type; + private IntPtr m_nativeEvent; + + private bool m_nameLoaded = false; + + private bool m_propertiesLoaded = false; + + + + private Dictionary m_properties; + + /// + /// The number of seconds after the event was triggered that it was reported. + /// + public float SecondsDelay + { + get { return m_secondsDelay; } + } + + /// + /// The name of the event. + /// + public string Name + { + get + { + if (!m_nameLoaded && m_nativeEvent != IntPtr.Zero) + { + m_name = Marshal.PtrToStringAnsi(NativeEventInterface.getEventName(m_nativeEvent)); + m_nameLoaded = true; + } + return m_name; + } + } + + /// + /// The associated properties of the event. + /// + /// The properties are a dictionary of key/value pairs. + /// The key is the name of the property. + /// The value can be a string, float, or boolean. + /// + /// + /// The properties can also be accessed by name using the indexer. + /// + /// + /// + /// event["myProperty"]; + /// event.properties["myProperty"]; // instead of + /// + /// + public Dictionary Properties + { + get + { + if (m_properties == null) + { + m_properties = new Dictionary(); + } + + if (!m_propertiesLoaded) + { + for (uint i = 0; i < PropertyCount; i++) + { + var property = NativeEventInterface.getEventCustomProperty(m_nativeEvent, i); + var name = Marshal.PtrToStringAnsi(property.name); + switch (property.type) + { + case (ushort)PropertyType.Bool: + m_properties[name] = NativeEventInterface.getCustomBool(property.nativeProperty); + break; + + case (ushort)PropertyType.String: + m_properties[name] = Marshal.PtrToStringAnsi( + NativeEventInterface.getCustomString(property.nativeProperty) + ); + break; + + case (ushort)PropertyType.Number: + m_properties[name] = NativeEventInterface.getCustomNumber(property.nativeProperty); + break; + } + } + + m_propertiesLoaded = true; + } + + + + return m_properties; + } + } + /// + /// The specific kind of event fired (i.e. General, OpenUrl) + /// + public ushort Type + { + get + { + return m_type; + } + } + + /// + /// The number of custom properties associated with the event. + /// + public uint PropertyCount + { + get + { + return m_propertyCount; + } + } + + /// + /// Get a property by name. + /// + public object this[string index] + { + get + { + if (Properties == null) + { + return null; + } + return Properties.TryGetValue(index, out var val) ? val : null; + } + } + + // constructor for pooling + internal ReportedEvent() { } + + internal void Initialize(ReportedEventData data) + { + // If a previous consumer called Dispose(), it doesn't matter because + // once we pop from the pool, we fully reset the object here. + m_isDisposed = false; + + // Reset old data + m_nativeEvent = IntPtr.Zero; + m_secondsDelay = 0f; + m_type = 0; + m_propertyCount = 0; + m_name = null; + m_properties?.Clear(); + + // We use this flag because we want to lazy load the properties in the Properties getter. + // If we were to update the dictionary here, we would be allocating memory for no reason if the consumer never accesses the Properties property and instead uses the TryGet methods for accessing properties. + m_propertiesLoaded = false; + + m_nameLoaded = false; + + m_nativeEvent = data.nativeEvent; + m_secondsDelay = data.secondsDelay; + + m_type = NativeEventInterface.getEventType(m_nativeEvent); + m_propertyCount = NativeEventInterface.getEventCustomPropertyCount(m_nativeEvent); + + + } + + + + /// + /// Dispose of the event. This will return the instance to the pool for reuse. + /// + public void Dispose() + { + if (m_isDisposed) + return; + + m_isDisposed = true; + ReleaseToPool(); + } + + private void ReleaseToPool() + { + s_Pool.Release(this); + } + + /// + /// Get a custom property by index. + /// + /// The index of the property to get. + /// The property at the given index. + /// + public Property GetProperty(uint index) + { + if (index >= PropertyCount) + { + throw new ArgumentOutOfRangeException(nameof(index)); + } + return new Property(NativeEventInterface.getEventCustomProperty(m_nativeEvent, index)); + } + + + + /// + /// Represents a custom property of a ReportedEvent. + /// + public struct Property + { + private readonly IntPtr m_nativeProperty; + private readonly IntPtr m_nativeName; + private string m_name; + private readonly PropertyType m_type; + + internal Property(UnityCustomProperty native) + { + m_nativeProperty = native.nativeProperty; + m_name = null; // lazy load to avoid unnecessary string allocations + m_type = (PropertyType)native.type; + m_nativeName = native.name; + + } + /// + /// The name of this property. + /// + public string Name + { + get + { + if (m_name == null) + { + m_name = Marshal.PtrToStringAnsi(m_nativeName); + } + return m_name; + } + } + + /// + /// The type of this property. + /// + public PropertyType Type => m_type; + + /// + /// Attempts to get the numeric value of this property. + /// + /// The output float value if successful. + /// True if the property is a number type and the value was retrieved, false otherwise. + public bool TryGetNumber(out float value) + { + if (m_type != PropertyType.Number) + { + value = default; + return false; + } + value = NativeEventInterface.getCustomNumber(m_nativeProperty); + return true; + } + + /// + /// Attempts to get the boolean value of this property. + /// + /// The output boolean value if successful. + /// True if the property is a boolean type and the value was retrieved, false otherwise. + public bool TryGetBool(out bool value) + { + if (m_type != PropertyType.Bool) + { + value = default; + return false; + } + value = NativeEventInterface.getCustomBool(m_nativeProperty); + return true; + } + + /// + /// Attempts to get the string value of this property. + /// + /// The output string value if successful. + /// True if the property is a string type and the value was retrieved, false otherwise. + public bool TryGetString(out string value) + { + if (m_type != PropertyType.String) + { + value = default; + return false; + } + value = Marshal.PtrToStringAnsi(NativeEventInterface.getCustomString(m_nativeProperty)); + return true; + } + } + + public enum PropertyType : ushort + { + Number = 127, + Bool = 129, + String = 130, + } + + } + + /// + /// Helper class to interface with native event data. + /// + internal class NativeEventInterface + { + [DllImport(NativeLibrary.name)] + internal static extern IntPtr getEventName(IntPtr nativeEvent); + + [DllImport(NativeLibrary.name)] + internal static extern ushort getEventType(IntPtr nativeEvent); + + [DllImport(NativeLibrary.name)] + internal static extern uint getEventCustomPropertyCount(IntPtr nativeEvent); + + [DllImport(NativeLibrary.name)] + internal static extern UnityCustomProperty getEventCustomProperty( + IntPtr nativeEvent, + uint index + ); + + [DllImport(NativeLibrary.name)] + internal static extern IntPtr getCustomString(IntPtr nativeProperty); + + [DllImport(NativeLibrary.name)] + internal static extern bool getCustomBool(IntPtr nativeProperty); + + [DllImport(NativeLibrary.name)] + internal static extern float getCustomNumber(IntPtr nativeProperty); + } + + +} diff --git a/Packages/app.rive.rive-unity/Runtime/ReportedEvent.cs.meta b/Packages/app.rive.rive-unity/Runtime/ReportedEvent.cs.meta new file mode 100644 index 00000000..c0ef827f --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/ReportedEvent.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 80a4fca346d874a78a7788d213affec0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/ReportedEvent.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Rive.Runtime.asmdef b/Packages/app.rive.rive-unity/Runtime/Rive.Runtime.asmdef new file mode 100644 index 00000000..f713d47f --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Rive.Runtime.asmdef @@ -0,0 +1,29 @@ +{ + "name": "Rive.Runtime", + "rootNamespace": "Rive", + "references": [ + "GUID:15fc0a57446b3144c949da3e2b9737a9", + "GUID:df380645f10b7bc4b97d4f5eb6303d95", + "GUID:457756d89b35d2941b3e7b37b4ece6f1" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [ + { + "name": "com.unity.render-pipelines.universal", + "expression": "12.1.15", + "define": "RIVE_USING_URP" + }, + { + "name": "com.unity.render-pipelines.high-definition", + "expression": "12.1.15", + "define": "RIVE_USING_HDRP" + } + ], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Runtime/Rive.Runtime.asmdef.meta b/Packages/app.rive.rive-unity/Runtime/Rive.Runtime.asmdef.meta new file mode 100644 index 00000000..36d7c33d --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Rive.Runtime.asmdef.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 0a82aeb665886483c867b7d137563619 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Rive.Runtime.asmdef + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/RiveFile.cs b/Packages/app.rive.rive-unity/Runtime/RiveFile.cs new file mode 100644 index 00000000..09b7dc6c --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/RiveFile.cs @@ -0,0 +1,623 @@ +using UnityEngine; +using System; +using System.Runtime.InteropServices; +using Rive.Utils; +using System.Collections.Generic; + +namespace Rive +{ + + /// + /// Represents a Rive File containing Artboards, StateMachines, and Animations. + /// + /// + /// There are higher level behaviours that you can use directly in the Unity editor. Use this class if you need direct control of the lifecycle of the Rive File. + /// + public class File : IDisposable + { + internal static class LogCodes + { + + public const string ERROR_NO_ARTBOARD_FOUND = "1001"; + + public const string ERROR_ASSET_REFERENCE_UPDATE_FAILED = "1002"; + + public const string ERROR_INVALID_FILE_ACCESS = "1003"; + + + } + + private IntPtr m_nativeFile; + private readonly int? m_assetKey; + private bool m_isDisposed = false; + + private ViewModel[] m_viewModels; + + private ViewModelEnumData[] m_viewModelEnums; + + + + internal IntPtr NativeFile + { + get { return m_nativeFile; } + } + + /// + /// Returns true if the file has been disposed. + /// + public bool IsDisposed { get => m_isDisposed; } + + internal bool IsNativeFileValid() + { + if (m_isDisposed) + { + DebugLogger.Instance.LogError($"{LogCodes.ERROR_INVALID_FILE_ACCESS}: - Attempting to access a Rive file that is no longer referenced or was not properly loaded."); + return false; + } + return true; + } + + + + private static FileLoader s_fileLoader = new FileLoader(); + + + /// + /// Use this to load custom assets from the Rive file. If you return an OutOfBandAsset, it will be used to load the asset. If you return null, then nothing will be loaded. + /// + /// The EmbeddedAssetReference data. + /// Return true if you intend on handling and loading in an asset yourself, or false if you do not want to handle asset loading for that given asset yourself, and attempt to have the runtime try to load the asset. + public delegate bool CustomAssetLoaderCallback(EmbeddedAssetReference assetReference); + + private IFallbackFileAssetLoader m_fallbackFileAssetLoader; + + internal IFallbackFileAssetLoader FallbackFileAssetLoader + { + get { return m_fallbackFileAssetLoader; } + } + + internal int? AssetKey + { + get { return m_assetKey; } + } + + /// + /// The view models in the file. + /// + public IReadOnlyList ViewModels + { + get + { + if (m_viewModels == null) + { + LoadViewModels(); + } + return m_viewModels; + } + } + + /// + /// The enums in the file. + /// + public IReadOnlyList ViewModelEnums + { + get + { + + if (m_viewModelEnums == null) + { + m_viewModelEnums = GetViewModelEnums(); + } + return m_viewModelEnums; + } + } + + /// + /// Dispose of the Rive File. + /// + public void Dispose() + { + Dispose(true); + } + + + protected virtual void Dispose(bool disposing) + { + if (!m_isDisposed) + { + // If the file was loaded with a cache key, we need to decrement the ref count and/or unload the file if it's no longer in use. + + if (m_assetKey.HasValue) + { + if (!disposing) + { + // Called from the finalizer; remove the file from the cache to account for the user not manually disposing of it. + s_fileLoader.ReleaseFile(this); + } + else + { + // Manual disposal (called from Dispose()) + bool isStillReferenced = s_fileLoader.DecrementRefCount(m_assetKey.Value); + + if (isStillReferenced) + { + // If the file is still being referenced, don't mark it as disposed yet + return; + } + + } + } + else + { + // For non-cached files, unref directly + s_fileLoader.ReleaseFile(this); + + } + m_nativeFile = IntPtr.Zero; + m_isDisposed = true; + } + } + + + + /// + /// Load a .riv File from a byte array and cache it using the provided ID. + /// + /// The name of the file. + /// The raw bytes of the Rive file. + /// The unique identifier of the file. This is used to cache and reuse the file if it's loaded multiple times with the same ID. + /// A File instance representing the loaded Rive file, either from cache or newly created. + /// + /// This method will return a cached version if the file with the provided ID was already loaded, otherwise it loads and caches a new instance in memory. + /// + public static File Load(byte[] riveFileByteContents, int cacheId) + { + return s_fileLoader.LoadWithKnownAssets(riveFileByteContents, cacheId, null); + } + + + + /// + /// Load a .riv File from a byte array using a custom asset loader. + /// + /// The raw bytes of the Rive file, e.g. fetched from a remote server. + /// This callback will be called for every asset the runtime detects from the .riv file on load, and will be responsible for either handling the load of an asset at runtime or passing on the responsibility and giving the runtime a chance to load it otherwise. + /// A new File instance representing the loaded Rive file. + /// + /// This method always creates and returns a new File instance, bypassing any caching mechanism. + /// Use this when you need custom asset loading behavior, but be aware that you'll need to manage + /// caching/reusing the instance yourself if required. + /// + public static File Load(byte[] riveFileByteContents, CustomAssetLoaderCallback customAssetLoaderCallback) + { + return s_fileLoader.LoadFileWithCallback(riveFileByteContents, customAssetLoaderCallback); + } + + + /// + /// Load a Rive File from a Unity TextAsset. Make sure the imported asset ends with the .bytes extension. + /// + /// The TextAsset to load. + /// This callback will be called for every asset the runtime detects from the .riv file on load, and will be responsible for either handling the load of an asset at runtime or passing on the responsibility and giving the runtime a chance to load it otherwise. + /// A File instance representing the loaded Rive file. + /// + /// Always creates and returns a new File instance, even if the same asset had been loaded before. Use this when you need custom asset loading behavior, but be aware that you'll need to manage caching/reusing the instance yourself if required. + /// + static public File Load(TextAsset asset, CustomAssetLoaderCallback customAssetLoaderCallback) + { + return s_fileLoader.LoadFileWithCallback(asset.bytes, customAssetLoaderCallback); + } + + /// + /// Load a Rive File from a Unity TextAsset. Make sure the imported asset ends with the .bytes extension. + /// + /// The TextAsset to load. + /// A File instance representing the loaded Rive file. + /// + /// Returns a cached version if the asset was already loaded, otherwise loads and caches a new instance in memory. + /// + static public File Load(TextAsset asset) + { + // With text assets, we don't have the embedded asset data ahead of time, but we still want them to be cached if the same asset is loaded multiple times. + return s_fileLoader.LoadWithKnownAssets(asset.bytes, asset.GetInstanceID(), null); + } + + /// + /// Load a .riv File from a Unity Rive.Asset. + /// + /// The Rive.Asset (.riv) to load. + /// A File instance representing the loaded Rive file. + /// + /// Returns a cached version if the asset was already loaded, otherwise loads and caches a new instance in memory. + /// + static public File Load(Asset asset) + { + return s_fileLoader.LoadWithKnownAssets(asset.Bytes, asset.GetInstanceID(), asset.EmbeddedAssets); + } + + /// + /// Load a .riv File from a Unity Rive.Asset. + /// + /// The Rive.Asset (.riv) to load. + /// This callback will be called for every asset the runtime detects from the .riv file on load, and will be responsible for either handling the load of an asset at runtime or passing on the responsibility and giving the runtime a chance to load it otherwise. + /// A File instance representing the loaded Rive file. + /// + /// Always creates and returns a new File instance, even if the same asset had been loaded before. Use this when you need custom asset loading behavior, but be aware that you'll need to manage caching/reusing the instance yourself if required. + /// + static public File Load(Asset asset, CustomAssetLoaderCallback customAssetLoaderCallback) + { + return s_fileLoader.LoadFileWithCallback(asset.Bytes, customAssetLoaderCallback); + } + + /// + /// Load a .riv File from a Unity Rive.Asset. + /// + /// The Rive.Asset (.riv) to load. + /// This callback will be called for every asset the runtime detects from the .riv file on load, and will be responsible for either handling the load of an asset at runtime or passing on the responsibility and giving the runtime a chance to load it otherwise. + /// If true, the runtime will attempt to load the assets assigned to the Rive.Asset in the Unity inspector if an asset is not handled by the custom loader. + /// A File instance representing the loaded Rive file. + /// + /// Always creates and returns a new File instance, even if the same asset had been loaded before. Use this when you need custom asset loading behavior, but be aware that you'll need to manage caching/reusing the instance yourself if required. + /// + static public File Load(Asset asset, CustomAssetLoaderCallback customAssetLoaderCallback, bool fallbackToAssignedAssets) + { + IEnumerable fallbackAssetData = fallbackToAssignedAssets ? asset.EmbeddedAssets : null; + return s_fileLoader.LoadFileWithCallback(asset.Bytes, customAssetLoaderCallback, fallbackAssetData); + } + + + /// + /// Update the embedded asset reference data in the Rive file. The out-of-band asset must be loaded before calling this method. + /// + /// + /// + internal void UpdateEmbeddedAssetReference(nuint assetIndex, OutOfBandAsset asset) + { + if (asset == null) + { + DebugLogger.Instance.LogError($"{LogCodes.ERROR_ASSET_REFERENCE_UPDATE_FAILED}: - The provided out-of-band asset is null. Make sure to load the out-of-band asset before updating the reference."); + return; + } + + if (asset.NativeAsset == IntPtr.Zero) + { + DebugLogger.Instance.LogError($"{LogCodes.ERROR_ASSET_REFERENCE_UPDATE_FAILED}: - The provided asset is not loaded in memory. Make sure to load the out-of-band asset before updating the reference."); + return; + } + + bool wasUpdated = NativeFileInterface.updateEmbeddedAssetReferenceInFile(NativeFile, assetIndex, asset.NativeAsset); + + if (!wasUpdated) + { + DebugLogger.Instance.LogError($"{LogCodes.ERROR_ASSET_REFERENCE_UPDATE_FAILED}: - Asset reference with index {assetIndex} not found in the file. Could the Rive file you loaded be different from the one you are trying to update?"); + } + + + } + + + + internal File(IntPtr nativeFile, int? assetKey, IFallbackFileAssetLoader fallbackFileAssetLoader) + { + m_nativeFile = nativeFile; + m_assetKey = assetKey; + m_fallbackFileAssetLoader = fallbackFileAssetLoader; + } + + ~File() + { + // If the native file was not manually released then we need to dispose of it here when the managed object is garbage collected. + Dispose(false); + + + } + + /// + /// Returns the number of artboards stored in the file. + /// + public uint ArtboardCount + { + get + { + if (!IsNativeFileValid()) return 0; + return NativeFileInterface.getArtboardCount(NativeFile); + } + } + + /// + /// Returns the name of the artboard at the given index. + /// + /// + public string ArtboardName(uint index) + { + if (!IsNativeFileValid()) return null; + return Marshal.PtrToStringAnsi(NativeFileInterface.getArtboardName(NativeFile, index)); + } + + /// + /// Instance the artboard at the given index. + /// + /// The index of the artboard to get. + /// An instance of the artboard at the given index or null if the index is out of bounds. + public Artboard Artboard(uint index) + { + if (!IsNativeFileValid()) return null; + IntPtr ptr = NativeFileInterface.instanceArtboardAtIndex(NativeFile, index); + if (ptr == IntPtr.Zero) + { + DebugLogger.Instance.LogError($"{LogCodes.ERROR_NO_ARTBOARD_FOUND}: - No Artboard found at index {index}. Could the Rive file you loaded be different from the one you are trying to access? Or is the index possibly out of bounds?"); + return null; + } + return new Artboard(ptr, this); + } + + + /// + /// Instance the artboard with the given name. + /// + /// The name of the artboard to get. + /// An instance of the artboard with the given name, or null if no artboard with the given name exists. + public Artboard Artboard(string name) + { + if (!IsNativeFileValid()) return null; + IntPtr ptr = NativeFileInterface.instanceArtboardWithName(NativeFile, name); + if (ptr == IntPtr.Zero) + { + DebugLogger.Instance.LogError($"{LogCodes.ERROR_NO_ARTBOARD_FOUND}: - No Artboard named \"{name}\". It's possible the name is misspelled or the file does not contain the named artboard."); + return null; + } + return new Artboard(ptr, this); + } + + + /// + /// Returns a bindable artboard with the given name. + /// + /// The name of the artboard. + /// A BindableArtboard instance, or null if not found. + public BindableArtboard BindableArtboard(string name) + { + return BindableArtboard(name, null); + } + + /// + /// Returns a bindable artboard with the given name and bound ViewModel instance. + /// + /// The name of the artboard. + /// The ViewModel instance to bind to the artboard. + /// A BindableArtboard instance, or null if not found. + public BindableArtboard BindableArtboard(string name, ViewModelInstance viewModelInstance) + { + if (name == null) + { + DebugLogger.Instance.LogError("Invalid name: " + name); + return null; + } + + IntPtr ptr = NativeFileInterface.getFileBindableArtboardNamed(m_nativeFile, name); + if (ptr == IntPtr.Zero) + { + DebugLogger.Instance.Log($"No bindable artboard named \"{name}\"."); + return null; + } + + return new BindableArtboard(ptr, viewModelInstance); + } + + + // Data binding methods + + public int ViewModelCount + { + get + { + if (!IsNativeFileValid()) return 0; + return (int)NativeFileInterface.getViewModelCount(NativeFile); + } + } + + /// + /// Get a view model by index in the file. + /// + /// The index of the view model to get. + /// The view model at the given index. + public ViewModel GetViewModelAtIndex(int index) + { + if (index < 0) + { + DebugLogger.Instance.LogError("Invalid index: " + index); + return null; + } + if (!IsNativeFileValid()) return null; + + + if ((nuint)index >= NativeFileInterface.getViewModelCount(NativeFile)) + { + DebugLogger.Instance.LogError("Index out of bounds: " + index); + return null; + } + + IntPtr ptr = NativeFileInterface.getViewModelAtIndex(NativeFile, (nuint)index); + if (ptr == IntPtr.Zero) + { + DebugLogger.Instance.LogError("Failed to get view model at index: " + index); + return null; + } + return new ViewModel(ptr, this); + } + + /// + /// Get a view model by name in the file. + /// + /// The name of the view model to get. + /// The view model with the given name. + public ViewModel GetViewModelByName(string name) + { + if (string.IsNullOrEmpty(name)) + { + DebugLogger.Instance.LogError("Invalid name: " + name); + return null; + } + if (!IsNativeFileValid()) return null; + IntPtr ptr = NativeFileInterface.getViewModelByName(NativeFile, name); + if (ptr == IntPtr.Zero) + { + DebugLogger.Instance.LogError("Failed to get view model with name: " + name); + return null; + } + return new ViewModel(ptr, this); + } + + + + private void LoadViewModels() + { + if (m_viewModels != null) + { + return; + } + + nuint count = (nuint)ViewModelCount; + m_viewModels = new ViewModel[count]; + for (nuint i = 0; i < count; i++) + { + IntPtr ptr = NativeFileInterface.getViewModelAtIndex(NativeFile, i); + if (ptr == IntPtr.Zero) + { + continue; + } + + m_viewModels[i] = new ViewModel(ptr, this); + } + } + + + private ViewModelEnumData[] GetViewModelEnums() + { + + nuint count = NativeFileInterface.getEnumCountFromFile(NativeFile); + var vmEnums = new ViewModelEnumData[count]; + + for (nuint i = 0; i < count; i++) + { + string enumName = Marshal.PtrToStringAnsi(NativeFileInterface.getEnumNameFromFileAtIndex(NativeFile, i)); + nuint valueCount = NativeFileInterface.getEnumValueCountFromFileEnumIndex(NativeFile, i); + string[] values = new string[valueCount]; + for (nuint j = 0; j < valueCount; j++) + { + values[j] = Marshal.PtrToStringAnsi(NativeFileInterface.getEnumValueAtFileEnumIndex(NativeFile, i, j)); + } + vmEnums[i] = new ViewModelEnumData(enumName, values); + } + + return vmEnums; + } + + internal ViewModel GetDefaultViewModelForArtboard(IntPtr artboardPtr) + { + IntPtr ptr = NativeFileInterface.getDefaultViewModelForArtboard(this.NativeFile, artboardPtr); + + if (ptr == IntPtr.Zero) + { + return null; + } + + return new ViewModel(ptr, this); + } + + } + + /// + /// Provides a way to work with the native file interface methods. + /// + internal class NativeFileInterface + { + internal static IFallbackFileAssetLoader s_NativeFileAssetLoader; + + internal delegate IntPtr NativeUnityAssetLoaderCallback(uint assetId, ushort assetType, string assetName, uint inBandByteSize); + + #region Native Methods + + [DllImport(NativeLibrary.name)] + internal static extern IntPtr loadRiveFile(byte[] bytes, uint byteCount, byte[] assetMapBytes, uint assetMapByteCount); + + [DllImport(NativeLibrary.name)] + internal static extern void unrefRiveFile(IntPtr riveFile); + + [DllImport(NativeLibrary.name)] + internal static extern bool isRiveFileValid(IntPtr riveFile); + [DllImport(NativeLibrary.name)] + internal static extern uint getArtboardCount(IntPtr riveFile); + + [DllImport(NativeLibrary.name)] + internal static extern IntPtr getArtboardName(IntPtr riveFile, uint index); + + [DllImport(NativeLibrary.name)] + internal static extern IntPtr getFileBindableArtboardNamed(IntPtr file, string name); + + [DllImport(NativeLibrary.name)] + internal static extern IntPtr instanceArtboardAtIndex(IntPtr riveFile, uint index); + + [DllImport(NativeLibrary.name)] + internal static extern IntPtr instanceArtboardWithName(IntPtr riveFile, string name); + + [DllImport(NativeLibrary.name)] + internal static extern bool updateEmbeddedAssetReferenceInFile(IntPtr riveFile, nuint assetIndex, IntPtr decodedAsset); + + [DllImport(NativeLibrary.name)] + internal static extern void clearAssignedAssetReferenceValue(IntPtr riveFile, nuint assetIndex); + + [DllImport(NativeLibrary.name)] + internal static extern IntPtr loadRiveFileWithUnityCallback(byte[] riveFileBytes, uint byteCount, NativeUnityAssetLoaderCallback callback); + + /// + /// The callback that is called by the native code to load the assets. It should return the native asset pointer to the native code. Don't call any Rive methods from this callback as it may lead to a crash due to deadlocks. + /// + /// The unique ID of the asset. + /// The type of the asset. + /// The name of the asset. + /// The size of the asset embedded in the file. + /// The native asset pointer to set in the Rive file. + [AOT.MonoPInvokeCallback(typeof(NativeUnityAssetLoaderCallback))] + internal static IntPtr AssetLoaderCallback(uint assetId, ushort assetType, string assetName, uint inBandByteSize) + { + + + if (s_NativeFileAssetLoader != null) + { + return s_NativeFileAssetLoader.NativeUnityAssetLoaderCallback(assetId, assetType, assetName, inBandByteSize); + } + + return IntPtr.Zero; + } + + + // Data binding methods + [DllImport(NativeLibrary.name)] + internal static extern nuint getViewModelCount(IntPtr riveFile); + + [DllImport(NativeLibrary.name)] + internal static extern IntPtr getViewModelAtIndex(IntPtr riveFile, nuint index); + + [DllImport(NativeLibrary.name)] + internal static extern IntPtr getViewModelByName(IntPtr riveFile, string name); + + [DllImport(NativeLibrary.name)] + internal static extern IntPtr getDefaultViewModelForArtboard(IntPtr filePtr, IntPtr artboardPtr); + + [DllImport(NativeLibrary.name)] + internal static extern nuint getEnumCountFromFile(IntPtr riveFile); + + [DllImport(NativeLibrary.name)] + internal static extern IntPtr getEnumNameFromFileAtIndex(IntPtr riveFile, nuint index); + + [DllImport(NativeLibrary.name)] + internal static extern nuint getEnumValueCountFromFileEnumIndex(IntPtr riveFile, nuint enumIndex); + + [DllImport(NativeLibrary.name)] + internal static extern IntPtr getEnumValueAtFileEnumIndex(IntPtr riveFile, nuint enumIndex, nuint valueIndex); + + #endregion + + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/RiveFile.cs.meta b/Packages/app.rive.rive-unity/Runtime/RiveFile.cs.meta new file mode 100644 index 00000000..e982dfb1 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/RiveFile.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: e61521a34f1a2429f8a9ce51443be4fa +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/RiveFile.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/RiveNative.cs b/Packages/app.rive.rive-unity/Runtime/RiveNative.cs new file mode 100644 index 00000000..f442dbd4 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/RiveNative.cs @@ -0,0 +1,56 @@ +using System; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; +using UnityEngine.Rendering; +using UnityEngine; +using Rive.Utils; + +[assembly: InternalsVisibleTo("Rive.Runtime.Components")] +[assembly: InternalsVisibleTo("Rive.Editor")] +[assembly: InternalsVisibleTo("Rive.Editor.Components")] +[assembly: InternalsVisibleTo("Rive.Tests.PlayMode")] +[assembly: InternalsVisibleTo("Rive.Tests.Shared")] +[assembly: InternalsVisibleTo("Rive.Tests.Editor")] +namespace Rive +{ + internal class NativeLibrary + { + private delegate void LogDelegate(IntPtr message); + +#if (UNITY_IOS || UNITY_TVOS || UNITY_WEBGL || UNITY_SWITCH || UNITY_VISIONOS) && !UNITY_EDITOR + public const string name = "__Internal"; +#else + public const string name = "rive"; +#endif + + [DllImport(NativeLibrary.name)] + private static extern void setUnityLog(LogDelegate callback); + + // Explicit registration entry point for platforms (like iOS/tvOS/visionOS/WebGL) + // where we can't rely solely on Unity calling UnityPluginLoad + [DllImport(NativeLibrary.name)] + private static extern void RiveRegisterRenderingPlugin(); + + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] + static void OnBeforeSceneLoadRuntimeMethod() + { + setUnityLog(UnityLog); + +#if (UNITY_WEBGL || UNITY_VISIONOS || UNITY_IOS || UNITY_TVOS) && !UNITY_EDITOR + try + { + RiveRegisterRenderingPlugin(); + } + catch (Exception e) { + DebugLogger.Instance.LogException(e); + } +#endif + } + + [AOT.MonoPInvokeCallback(typeof(LogDelegate))] + static void UnityLog(IntPtr message) + { + DebugLogger.Instance.Log("RiveNative: " + Marshal.PtrToStringAnsi(message)); + } + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/RiveNative.cs.meta b/Packages/app.rive.rive-unity/Runtime/RiveNative.cs.meta new file mode 100644 index 00000000..b859d4ce --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/RiveNative.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: da09d2b8979c54e2fa2301a95dfa6fae +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/RiveNative.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/SMIInput.cs b/Packages/app.rive.rive-unity/Runtime/SMIInput.cs new file mode 100644 index 00000000..e0b57355 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/SMIInput.cs @@ -0,0 +1,153 @@ +using System; +using System.Runtime.InteropServices; + +namespace Rive +{ + /// + /// Represents a State Machine Input. + /// + /// An Input can be a Trigger, a Boolean, or a Number. + /// Use the derived classes SMITrigger, SMIBool and SMINumber. + /// + /// + /// An SMIInput is owned by a StateMachine. + /// The SMIInput keeps the StateMachine alive by maintaining a reference to it. + /// + public class SMIInput + { + private readonly IntPtr m_nativeSMI; + + // This is a reference to the StateMachine that owns this SMIInput. + // It is used to keep the StateMachine alive while the SMIInput is alive. + private StateMachine m_stateMachineReference; + + internal IntPtr NativeSMI => m_nativeSMI; + + internal SMIInput(IntPtr smi, StateMachine stateMachineReference) + { + m_nativeSMI = smi; + m_stateMachineReference = stateMachineReference; + } + + /// + /// The name of the State Machine Input. + /// + public string Name + { + get + { + IntPtr ptr = getSMIInputName(m_nativeSMI); + return ptr == IntPtr.Zero ? null : Marshal.PtrToStringAnsi(ptr); + } + } + + /// Returns true if the SMIInput is a Boolean (SMIBool). + public bool IsBoolean => isSMIBoolean(m_nativeSMI); + + /// Returns true if the SMIInput is a Trigger (SMITrigger). + public bool IsTrigger => isSMITrigger(m_nativeSMI); + + /// Returns true if the SMIInput is a Number (SMINumber). + public bool IsNumber => isSMINumber(m_nativeSMI); + + #region Native Methods + [DllImport(NativeLibrary.name)] + internal static extern IntPtr getSMIInputName(IntPtr nativeSMI); + + [DllImport(NativeLibrary.name)] + internal static extern bool isSMIBoolean(IntPtr nativeSMI); + + [DllImport(NativeLibrary.name)] + internal static extern bool isSMITrigger(IntPtr nativeSMI); + + [DllImport(NativeLibrary.name)] + internal static extern bool isSMINumber(IntPtr nativeSMI); + #endregion + } + + /// + /// Represents a State Machine Trigger. + /// + /// + /// A SMITrigger is a boolean that is set to true for one frame. + /// + /// A SMITrigger is owned by a StateMachine. + /// The SMITrigger keeps the StateMachine alive by maintaining a reference to it. + /// + public sealed class SMITrigger : SMIInput + { + internal SMITrigger(IntPtr smi, StateMachine stateMachineReference) + : base(smi, stateMachineReference) { } + + /// Fire the State Machine Trigger. + public void Fire() + { + fireSMITriggerStateMachine(NativeSMI); + } + + #region Native Methods + + [DllImport(NativeLibrary.name)] + internal static extern void fireSMITriggerStateMachine(IntPtr nativeSMI); + + #endregion + } + + /// + /// Represents a State Machine Boolean. + /// + /// + /// A SMIBool contains a value of type boolean that can be get/set. + /// The SMIBool keeps the StateMachine alive by maintaining a reference to it. + /// + public sealed class SMIBool : SMIInput + { + internal SMIBool(IntPtr smi, StateMachine stateMachineReference) + : base(smi, stateMachineReference) { } + + /// The value of the State Machine Boolean. + public bool Value + { + get => getSMIBoolValueStateMachine(NativeSMI); + set => setSMIBoolValueStateMachine(NativeSMI, value); + } + + #region Native Methods + + [DllImport(NativeLibrary.name)] + internal static extern bool getSMIBoolValueStateMachine(IntPtr nativeSMI); + + [DllImport(NativeLibrary.name)] + internal static extern void setSMIBoolValueStateMachine(IntPtr nativeSMI, bool newValue); + + #endregion + } + + /// + /// Represents a State Machine Number. + /// + /// + /// A SMINumber contain a value of type float that can be get/set. + /// The SMINumber keeps the StateMachine alive by maintaining a reference to it. + /// + public sealed class SMINumber : SMIInput + { + internal SMINumber(IntPtr smi, StateMachine stateMachineReference) + : base(smi, stateMachineReference) { } + + /// The value of the State Machine Number. + public float Value + { + get => getSMINumberValueStateMachine(NativeSMI); + set => setSMINumberValueStateMachine(NativeSMI, value); + } + + #region Native Methods + [DllImport(NativeLibrary.name)] + internal static extern float getSMINumberValueStateMachine(IntPtr nativeSMI); + + [DllImport(NativeLibrary.name)] + internal static extern void setSMINumberValueStateMachine(IntPtr nativeSMI, float newValue); + #endregion + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/SMIInput.cs.meta b/Packages/app.rive.rive-unity/Runtime/SMIInput.cs.meta new file mode 100644 index 00000000..ffcea1a5 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/SMIInput.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: d92f8c6037ec469288725684f0047468 +timeCreated: 1701102733 +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/SMIInput.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Shaders.meta b/Packages/app.rive.rive-unity/Runtime/Shaders.meta new file mode 100644 index 00000000..3c12b0a5 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Shaders.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 12e115b69e58a4773b660d01de25576d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Runtime/Shaders/Resources.meta b/Packages/app.rive.rive-unity/Runtime/Shaders/Resources.meta new file mode 100644 index 00000000..17650da5 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Shaders/Resources.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 62573dc224ed44030905194a2ff13186 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Runtime/Shaders/Resources/RiveUIDefault.shader b/Packages/app.rive.rive-unity/Runtime/Shaders/Resources/RiveUIDefault.shader new file mode 100644 index 00000000..f8a066b7 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Shaders/Resources/RiveUIDefault.shader @@ -0,0 +1,141 @@ +Shader "Rive/UI/Default" +{ + Properties + { + // Standard UI/Main texture (per renderer) + [PerRendererData] _MainTex ("Texture", 2D) = "white" {} + _Color ("Tint", Color) = (1,1,1,1) + + // Stencil properties so Mask / RectMask2D work + [PerRendererData] _StencilComp ("Stencil Comparison", Float) = 8 + [PerRendererData] _Stencil ("Stencil ID", Float) = 0 + [PerRendererData] _StencilOp ("Stencil Operation", Float) = 0 + [PerRendererData] _StencilWriteMask ("Stencil Write Mask", Float) = 255 + [PerRendererData] _StencilReadMask ("Stencil Read Mask", Float) = 255 + + // Color mask / alpha clip for UI + [PerRendererData] _ColorMask ("Color Mask", Float) = 15 + [PerRendererData] _UseUIAlphaClip ("Use Alpha Clip", Float) = 0 + } + + SubShader + { + Tags + { + "Queue"="Transparent" + "IgnoreProjector"="True" + "RenderType"="Transparent" + "PreviewType"="Plane" + "CanUseSpriteAtlas"="True" + } + + // Stencil setup used by Mask / RectMask2D + Stencil + { + Ref [_Stencil] + Comp [_StencilComp] + Pass [_StencilOp] + ReadMask [_StencilReadMask] + WriteMask [_StencilWriteMask] + } + + ColorMask [_ColorMask] + + Cull Off + ZWrite Off + ZTest [unity_GUIZTestMode] + + + Blend One OneMinusSrcAlpha + + Pass + { + Name "RiveGammaDecodeUI" + + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #pragma target 2.0 + + #include "UnityCG.cginc" + #include "UnityUI.cginc" + + #pragma multi_compile __ UNITY_UI_CLIP_RECT + #pragma multi_compile __ UNITY_UI_ALPHACLIP + + struct appdata_t + { + float4 vertex : POSITION; + float4 color : COLOR; + float2 texcoord : TEXCOORD0; + float2 texcoord1 : TEXCOORD1; // used for RectMask2D + UNITY_VERTEX_INPUT_INSTANCE_ID + }; + + struct v2f + { + float4 vertex : SV_POSITION; + fixed4 color : COLOR; + float2 texcoord : TEXCOORD0; + float4 worldPosition : TEXCOORD1; + UNITY_VERTEX_OUTPUT_STEREO + }; + + sampler2D _MainTex; + float4 _MainTex_ST; + fixed4 _Color; + float4 _ClipRect; + + v2f vert (appdata_t v) + { + v2f o; + UNITY_SETUP_INSTANCE_ID(v); + UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); + + o.worldPosition = v.vertex; + o.vertex = UnityObjectToClipPos(v.vertex); + o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex); + o.color = v.color * _Color; + return o; + } + + half4 frag (v2f i) : SV_Target + { + // Sample texture + half4 tex = tex2D(_MainTex, i.texcoord); + + // Rive renders premultiplied alpha into the render texture. + // Convert to linear in un-premultiplied space, then premultiply again. + #if !defined(UNITY_COLORSPACE_GAMMA) + if (tex.a > 0.0h) + { + half3 unpremultiplied = tex.rgb / tex.a; + tex.rgb = GammaToLinearSpace(unpremultiplied) * tex.a; + } + #endif + + // Preserve premultiplied alpha when Unity UI applies tint/CanvasGroup alpha. + half4 color; + color.a = tex.a * i.color.a; + color.rgb = tex.rgb * i.color.rgb * i.color.a; + + // RectMask2D clipping + // we scale both RGB and A to keep premultiplied invariant + #ifdef UNITY_UI_CLIP_RECT + half clipFactor = UnityGet2DClipping(i.worldPosition.xy, _ClipRect); + color *= clipFactor; + #endif + + // Optional alpha clipping for masking + #ifdef UNITY_UI_ALPHACLIP + clip (color.a - 0.001); + #endif + + return color; + } + ENDCG + } + } + + Fallback "UI/Default" +} diff --git a/Packages/app.rive.rive-unity/Runtime/Shaders/Resources/RiveUIDefault.shader.meta b/Packages/app.rive.rive-unity/Runtime/Shaders/Resources/RiveUIDefault.shader.meta new file mode 100644 index 00000000..1c22e1b7 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Shaders/Resources/RiveUIDefault.shader.meta @@ -0,0 +1,16 @@ +fileFormatVersion: 2 +guid: 6ce86fb0d1c604912a5c633e43cb30ef +ShaderImporter: + externalObjects: {} + defaultTextures: [] + nonModifiableTextures: [] + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Shaders/Resources/RiveUIDefault.shader + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/StateMachine.cs b/Packages/app.rive.rive-unity/Runtime/StateMachine.cs new file mode 100644 index 00000000..b89782bb --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/StateMachine.cs @@ -0,0 +1,349 @@ +using UnityEngine; +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using Rive.Utils; + +namespace Rive +{ + /// + /// Represents a Rive StateMachine from an Artboard. A StateMachine contains Inputs. + /// + public class StateMachine : IDisposable + { + private readonly IntPtr m_nativeStateMachine; + private ViewModelInstance m_currentViewModelInstance; + + private string m_stateMachineName; + private bool m_isDisposed = false; + + internal IntPtr NativeStateMachine => m_nativeStateMachine; + + /// + /// Returns true if the state machine has been disposed. + /// + public bool IsDisposed { get => m_isDisposed; } + + internal StateMachine(IntPtr nativeStateMachine) + { + m_nativeStateMachine = nativeStateMachine; + } + + /// + /// Dispose of the StateMachine and release native resources. + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (!m_isDisposed) + { + if (m_nativeStateMachine != IntPtr.Zero) + { + unrefStateMachine(m_nativeStateMachine); + } + m_isDisposed = true; + } + } + + ~StateMachine() + { + Dispose(false); + } + + public string Name + { + get + { + if (m_stateMachineName == null) + { + m_stateMachineName = Marshal.PtrToStringAnsi(stateMachineGetName(m_nativeStateMachine)); + } + return m_stateMachineName; + } + } + + /// + /// The current ViewModelInstance set as the data context of the StateMachine. + /// + public ViewModelInstance ViewModelInstance + { + get { return m_currentViewModelInstance; } + } + + public bool Advance(float seconds) + { + return advanceStateMachine(m_nativeStateMachine, seconds); + } + + /// The number of Inputs stored in the StateMachine. + public uint InputCount() + { + return getSMIInputCountStateMachine(m_nativeStateMachine); + } + + /// The SMIInput at the given index. + public SMIInput Input(uint index) + { + IntPtr ptr = getSMIInputFromIndexStateMachine(m_nativeStateMachine, index); + return ptr == IntPtr.Zero ? null : new SMIInput(ptr, this); + } + + private SMIInput ConvertInput(SMIInput input) + { + if (input.IsBoolean) + { + return new SMIBool(input.NativeSMI, this); + } + else if (input.IsTrigger) + { + return new SMITrigger(input.NativeSMI, this); + } + else if (input.IsNumber) + { + return new SMINumber(input.NativeSMI, this); + } + else + { + return null; + } + } + + /// A list of all the SMIInputs stored in the StateMachine. + public List Inputs() + { + var list = new List(); + for (uint i = 0; i < InputCount(); i++) + { + var inputAtIndex = Input(i); + if (inputAtIndex == null) + { + continue; + } + + var converted = ConvertInput(inputAtIndex); + if (converted != null) + { + list.Add(converted); + } + } + + return list; + } + + /// + /// Get a SMIBool by name. + /// + /// + /// A SMIBool.value is a boolean that can be get/set + /// + public SMIBool GetBool(string name) + { + IntPtr ptr = getSMIBoolStateMachine(m_nativeStateMachine, name); + if (ptr != IntPtr.Zero) + return new SMIBool(ptr, this); + DebugLogger.Instance.Log($"No SMIBool found with name: {name}."); + return null; + } + + /// + /// Get a SMITrigger by name. + /// + /// + /// A SMITrigger contains a fire method to trigger. + /// + public SMITrigger GetTrigger(string name) + { + IntPtr ptr = getSMITriggerStateMachine(m_nativeStateMachine, name); + if (ptr != IntPtr.Zero) + return new SMITrigger(ptr, this); + DebugLogger.Instance.Log($"No SMITrigger found with name: {name}."); + return null; + } + + /// + /// Get a SMINumber by name. + /// + /// + /// A SMINumber.value is a float that can be get/set + /// + public SMINumber GetNumber(string name) + { + IntPtr ptr = getSMINumberStateMachine(m_nativeStateMachine, name); + if (ptr != IntPtr.Zero) + return new SMINumber(ptr, this); + DebugLogger.Instance.Log($"No SMINumber found with name: {name}."); + return null; + } + + /// + /// Move the pointer to the given position + /// + public HitResult PointerMove(Vector2 position, int pointerId = 0) + { + return (HitResult)pointerMoveStateMachineWithHit(m_nativeStateMachine, position.x, position.y, pointerId); + } + + /// + /// Press the pointer at the given position + /// + public HitResult PointerDown(Vector2 position, int pointerId = 0) + { + return (HitResult)pointerDownStateMachineWithHit(m_nativeStateMachine, position.x, position.y, pointerId); + } + + /// + /// Release the pointer at the given position + /// + public HitResult PointerUp(Vector2 position, int pointerId = 0) + { + return (HitResult)pointerUpStateMachineWithHit(m_nativeStateMachine, position.x, position.y, pointerId); + } + + /// + /// Exit the pointer at the given position + /// + public HitResult PointerExit(Vector2 position, int pointerId = 0) + { + return (HitResult)pointerExitStateMachineWithHit(m_nativeStateMachine, position.x, position.y, pointerId); + } + + /// + /// Performs a hit test at the given position + /// + /// The position to test in local coordinates + /// True if the position hits a component with a listener, false otherwise + public bool HitTest(Vector2 position) + { + return hitTestStateMachine(m_nativeStateMachine, position.x, position.y); + } + + /// + /// A list of all the reported events received in the past frame. + /// + public List ReportedEvents() + { + uint count = getReportedEventCount(m_nativeStateMachine); + var list = new List(); + for (uint i = 0; i < count; i++) + { + list.Add(ReportedEvent.GetPooled(getReportedEventAt(m_nativeStateMachine, i))); + } + return list; + } + + + + /// + /// Fetches the reported events received by the StateMachine in the past frame and populates the given list. + /// + /// The list to populate with reported events. + public void ReportedEvents(List reportedEvents) + { + uint count = getReportedEventCount(m_nativeStateMachine); + for (uint i = 0; i < count; i++) + { + reportedEvents.Add(ReportedEvent.GetPooled(getReportedEventAt(m_nativeStateMachine, i))); + } + } + + /// + /// Enumerates through all reported events received by the StateMachine in the past frame. + /// + /// An IEnumerable of ReportedEvents + public IEnumerable EnumerateReportedEvents() + { + uint count = getReportedEventCount(m_nativeStateMachine); + for (uint i = 0; i < count; i++) + { + yield return ReportedEvent.GetPooled(getReportedEventAt(m_nativeStateMachine, i)); + } + } + + /// + /// Sets the data context of the StateMachine from the given ViewModelInstance. + /// + /// + /// This method also binds the underlying Artboard to the ViewModelInstance. It is recommended to call this method to automatically bind the ViewModelInstance to the StateMachine and the Artboard. + /// + /// The ViewModelInstance to bind to the StateMachine. + public void BindViewModelInstance(ViewModelInstance viewModelInstance) + { + if (viewModelInstance == null) + { + DebugLogger.Instance.LogError("ViewModelInstance is null."); + return; + } + + bindViewModelInstanceToStateMachine(m_nativeStateMachine, viewModelInstance.NativeSafeHandle); + + m_currentViewModelInstance = viewModelInstance; // Store the current ViewModelInstance to keep the VM alive + + } + + #region Native Methods + [DllImport(NativeLibrary.name)] + internal static extern void unrefStateMachine(IntPtr stateMachine); + + [DllImport(NativeLibrary.name)] + internal static extern bool advanceStateMachine(IntPtr stateMachine, float seconds); + + [DllImport(NativeLibrary.name)] + internal static extern uint getSMIInputCountStateMachine(IntPtr stateMachine); + + [DllImport(NativeLibrary.name)] + internal static extern IntPtr getSMIInputFromIndexStateMachine( + IntPtr stateMachine, + uint index + ); + + [DllImport(NativeLibrary.name)] + internal static extern IntPtr getSMIBoolStateMachine(IntPtr stateMachine, string name); + + [DllImport(NativeLibrary.name)] + internal static extern IntPtr getSMITriggerStateMachine(IntPtr stateMachine, string name); + + [DllImport(NativeLibrary.name)] + internal static extern IntPtr getSMINumberStateMachine(IntPtr stateMachine, string name); + + + [DllImport(NativeLibrary.name)] + internal static extern byte pointerMoveStateMachineWithHit(IntPtr smi, float x, float y, int pointerId); + + [DllImport(NativeLibrary.name)] + internal static extern byte pointerDownStateMachineWithHit(IntPtr smi, float x, float y, int pointerId); + + [DllImport(NativeLibrary.name)] + internal static extern byte pointerUpStateMachineWithHit(IntPtr smi, float x, float y, int pointerId); + + [DllImport(NativeLibrary.name)] + internal static extern byte pointerExitStateMachineWithHit(IntPtr smi, float x, float y, int pointerId); + + [DllImport(NativeLibrary.name)] + internal static extern bool hitTestStateMachine(IntPtr stateMachine, float x, float y); + + [DllImport(NativeLibrary.name)] + internal static extern uint getReportedEventCount(IntPtr stateMachine); + + [DllImport(NativeLibrary.name)] + internal static extern ReportedEventData getReportedEventAt( + IntPtr stateMachine, + uint index + ); + + [DllImport(NativeLibrary.name)] + internal static extern IntPtr stateMachineGetName(IntPtr stateMachine); + + // Data binding + + [DllImport(NativeLibrary.name)] + internal static extern void bindViewModelInstanceToStateMachine(IntPtr stateMachine, ViewModelInstanceSafeHandle viewModelInstance); + + + #endregion + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/StateMachine.cs.meta b/Packages/app.rive.rive-unity/Runtime/StateMachine.cs.meta new file mode 100644 index 00000000..f0f5d3d3 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/StateMachine.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 5d9d362f578124d22b83ab95af9968dd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/StateMachine.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/TextureHelper.cs b/Packages/app.rive.rive-unity/Runtime/TextureHelper.cs new file mode 100644 index 00000000..33959b74 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/TextureHelper.cs @@ -0,0 +1,147 @@ +using Rive.Utils; +using UnityEngine; +using UnityEngine.Experimental.Rendering; +using UnityEngine.Rendering; + +namespace Rive +{ + public static class TextureHelper + { + /// + /// Returns a compatible GraphicsFormat for creating RenderTextures that + /// work with Rive's Renderer. + /// + public static GraphicsFormat Format => GraphicsFormat.R8G8B8A8_UNorm; + + private static Material s_gammaToLinearUIMaterial; + + const string GAMMA_TO_LINEAR_UI_SHADER_NAME = "Rive/UI/Default"; + + /// + /// Lazily creates and returns a material that decodes gamma content to linear + /// Used to display Rive's RenderTexture correctly in Linear color space without relying on sRGB RenderTextures (which are unreliable on some backends). + /// + internal static Material GammaToLinearUIMaterial + { + get + { + if (s_gammaToLinearUIMaterial == null) + { + var shader = Shader.Find(GAMMA_TO_LINEAR_UI_SHADER_NAME); + if (shader != null) + { + s_gammaToLinearUIMaterial = new Material(shader) + { + name = "Rive_UI_Default", + hideFlags = HideFlags.HideAndDontSave + }; + } + else + { + DebugLogger.Instance.LogError($"Shader '{GAMMA_TO_LINEAR_UI_SHADER_NAME}' not found."); + } + } + + return s_gammaToLinearUIMaterial; + } + } + + /// + /// Whether we should decode Gamma content to linear when displaying Rive RenderTextures. + /// + internal static bool ProjectNeedsColorSpaceFix + { + get + { + return QualitySettings.activeColorSpace == ColorSpace.Linear; + } + } + + /// + /// Returns a RenderTexture descriptor guaranteed to be compatible with + /// Rive's Renderer. + /// + /// The width of the texture in pixels. + /// The height of the texture in pixels. + /// + public static RenderTextureDescriptor Descriptor(int width, int height) + { + return new RenderTextureDescriptor(width, height, Format, 0) + { + enableRandomWrite = + (UnityEngine.SystemInfo.graphicsDeviceType + == UnityEngine.Rendering.GraphicsDeviceType.Direct3D11) || + (UnityEngine.SystemInfo.graphicsDeviceType + == UnityEngine.Rendering.GraphicsDeviceType.Direct3D12) + }; + } + + /// + /// Determines if the texture should be flipped based on the graphics API. + /// + /// + public static bool ShouldFlipTexture() + { + switch (SystemInfo.graphicsDeviceType) + { + case GraphicsDeviceType.Metal: + case GraphicsDeviceType.Vulkan: + case GraphicsDeviceType.Direct3D11: + case GraphicsDeviceType.Direct3D12: + return true; + default: + return false; + } + } + + public static bool IsOpenGLPlatform() + { + GraphicsDeviceType deviceType = SystemInfo.graphicsDeviceType; + bool isOpenGL = deviceType == GraphicsDeviceType.OpenGLCore || + deviceType == GraphicsDeviceType.OpenGLES3; + +#if !UNITY_2023_1_OR_NEWER + // OpenGLES2 is not supported in Unity 2023.1 and newer + isOpenGL = isOpenGL || deviceType == GraphicsDeviceType.OpenGLES2; +#endif + +#if UNITY_WEBGL && !UNITY_EDITOR + isOpenGL = true; +#endif + + return isOpenGL; + } + + public static bool IsDirect3DPlatform() + { + return SystemInfo.graphicsDeviceType == GraphicsDeviceType.Direct3D11 || SystemInfo.graphicsDeviceType == GraphicsDeviceType.Direct3D12; + } + + /// + /// Determines if the input should be flipped based on the graphics API. + /// + /// True if the input should be flipped, false otherwise. + public static bool ShouldFlipInput() + { + // OpenGL platforms require flipping the input, even if the texture doesn't need to be flipped. + if (IsOpenGLPlatform()) + { + return true; + } + + return ShouldFlipTexture(); + } + + internal static bool NeedsRenderTargetSetOnCommandBuffer() + { + // Direct3D11 requires that we call SetRenderTarget on the command buffer. Otherwise, nothing will be rendered. + if (SystemInfo.graphicsDeviceType == GraphicsDeviceType.Direct3D11) + { + return true; + } + + return false; + } + + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/TextureHelper.cs.meta b/Packages/app.rive.rive-unity/Runtime/TextureHelper.cs.meta new file mode 100644 index 00000000..ceffa101 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/TextureHelper.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 9bd6e3dbf07d65b46a7b17e6b1fde97c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/TextureHelper.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Utility.cs b/Packages/app.rive.rive-unity/Runtime/Utility.cs new file mode 100644 index 00000000..897b9380 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Utility.cs @@ -0,0 +1,15 @@ +namespace Rive +{ + public static class Extensions + { + public static System.Numerics.Vector2 ToVector2(this UnityEngine.Vector2 vec2) + { + return new System.Numerics.Vector2(vec2.x, vec2.y); + } + + public static UnityEngine.Vector2 ToVector2(this System.Numerics.Vector2 vec2) + { + return new UnityEngine.Vector2(vec2.X, vec2.Y); + } + } +} diff --git a/Packages/app.rive.rive-unity/Runtime/Utility.cs.meta b/Packages/app.rive.rive-unity/Runtime/Utility.cs.meta new file mode 100644 index 00000000..7f72c93f --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Utility.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 305ce27c37c1e466b9382ec5e75c30aa +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Utility.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/Runtime/Utils.meta b/Packages/app.rive.rive-unity/Runtime/Utils.meta new file mode 100644 index 00000000..20e5f7b6 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Utils.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0573fd22f87704ef6a3d4ae152eea444 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/app.rive.rive-unity/Runtime/Utils/DebugLogger.cs b/Packages/app.rive.rive-unity/Runtime/Utils/DebugLogger.cs new file mode 100644 index 00000000..d46e53e3 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Utils/DebugLogger.cs @@ -0,0 +1,51 @@ +using System; +using UnityEngine; +namespace Rive.Utils +{ + /// + /// A custom logger for Rive that logs messages to the Unity console. + /// + public class DebugLogger : IDebugLogger + { + private static readonly IDebugLogger _instance = new DebugLogger(); + + private static IDebugLogger _customInstance; + + public static IDebugLogger Instance + { + get + { + if (_customInstance != null) + { + return _customInstance; + } + return _instance; + } + set + { + _customInstance = value; + } + } + + public void Log(string message) + { + Debug.Log($"[Rive]: {message}"); + } + + public void LogWarning(string message) + { + Debug.LogWarning($"[Rive]: {message}"); + } + + public void LogError(string message) + { + Debug.LogError($"[Rive]: {message}"); + } + + public void LogException(Exception exception) + { + Debug.LogException(exception); + } + + } +} \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/Runtime/Utils/DebugLogger.cs.meta b/Packages/app.rive.rive-unity/Runtime/Utils/DebugLogger.cs.meta new file mode 100644 index 00000000..a2ac5088 --- /dev/null +++ b/Packages/app.rive.rive-unity/Runtime/Utils/DebugLogger.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: bb6a5f7be608e40a88a8d526301c9f12 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/Runtime/Utils/DebugLogger.cs + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/documentation.md b/Packages/app.rive.rive-unity/documentation.md new file mode 100644 index 00000000..c368ec6b --- /dev/null +++ b/Packages/app.rive.rive-unity/documentation.md @@ -0,0 +1,44 @@ +# Rive for Unity: Quick Start + +This guide covers the essentials for getting started with Rive in Unity immediately. + +--- + +## 1) Display the Included Rive File +> Note:the `com.unity.ugui` package is required (typically included by default in new Unity projects). + +Locate the included sample in: +`/Demo/RiveFiles/quick_start_health_bar.riv` + +Then choose how you want to display it: + +**In UI (Canvas):** Drag the file into the **Scene Hierarchy** to create a screen-space setup inside a uGUI Canvas. + + +**On a Mesh:** Drag the file onto a GameObject with a `MeshRenderer`. Unity sets up a **Rive Panel** and **Rive Texture Renderer** automatically. + +**Via the context menu:** Right-click in the Scene Hierarchy and use: +- `Rive > Rive Panel` +- `Rive > Rive Panel (Canvas)` +- `Rive > Widgets > Rive Widget` + +--- + +## 2) Add More Rive Files + +Once you've tested with the included file, import additional `.riv` files by dragging them into the Unity **Project** window. To find more files to download or remix: +- [Rive Marketplace](https://rive.app/marketplace) + +--- + +## Video Tutorial + +Watch: **How to use Rive Files in UNITY 👾** +[YouTube](https://www.youtube.com/watch?v=FrzJYkSr5kM) + +--- + +## Full Documentation (Online) + +For complete setup, feature support, and up-to-date guidance: +[Rive Unity Getting Started](https://rive.app/docs/game-runtimes/unity/getting-started) \ No newline at end of file diff --git a/Packages/app.rive.rive-unity/documentation.md.meta b/Packages/app.rive.rive-unity/documentation.md.meta new file mode 100644 index 00000000..732f9974 --- /dev/null +++ b/Packages/app.rive.rive-unity/documentation.md.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: e4e219fe48c914555ad74c48884b7b4d +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/documentation.md + uploadId: 896810 diff --git a/Packages/app.rive.rive-unity/package.json b/Packages/app.rive.rive-unity/package.json new file mode 100644 index 00000000..a1c37394 --- /dev/null +++ b/Packages/app.rive.rive-unity/package.json @@ -0,0 +1,24 @@ +{ + "name": "app.rive.rive-unity", + "version": "0.4.2", + "displayName": "Rive", + "description": "Create and ship interactive animations to any platform", + "unity": "2021.3", + "unityRelease": "0a10", + "documentationUrl": "https://rive.app/community/doc/getting-started/docQycIiNOv4", + "changelogUrl": "https://github.com/rive-app/rive-unity/tags", + "licensesUrl": "https://github.com/rive-app/rive-unity/license", + "keywords": [ + "Vector", + "Graphics", + "Animation" + ], + "author": { + "name": "Rive Team", + "email": "hello@rive.app", + "url": "https://rive.app" + }, + "dependencies": { + "com.unity.shadergraph": "14.0.11" + } +} diff --git a/Packages/app.rive.rive-unity/package.json.meta b/Packages/app.rive.rive-unity/package.json.meta new file mode 100644 index 00000000..ff23c27e --- /dev/null +++ b/Packages/app.rive.rive-unity/package.json.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: a9c29d5d602474f528cd8a9121a86656 +PackageManifestImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 350858 + packageName: Rive + packageVersion: 0.4.2 + assetPath: Packages/app.rive.rive-unity/package.json + uploadId: 896810 diff --git a/Packages/manifest.json b/Packages/manifest.json index d15f8bcd..f42f64cb 100644 --- a/Packages/manifest.json +++ b/Packages/manifest.json @@ -8,6 +8,7 @@ "com.unity.ide.rider": "3.0.39", "com.unity.ide.visualstudio": "2.0.26", "com.unity.inputsystem": "1.18.0", + "com.unity.localization": "1.5.11", "com.unity.multiplayer.center": "1.0.1", "com.unity.nuget.mono-cecil": "1.10.2", "com.unity.nuget.newtonsoft-json": "3.2.2", diff --git a/Packages/packages-lock.json b/Packages/packages-lock.json index 4df6437b..de134df7 100644 --- a/Packages/packages-lock.json +++ b/Packages/packages-lock.json @@ -1,5 +1,13 @@ { "dependencies": { + "app.rive.rive-unity": { + "version": "file:app.rive.rive-unity", + "depth": 0, + "source": "embedded", + "dependencies": { + "com.unity.shadergraph": "14.0.11" + } + }, "com.kyrylokuzyk.primetween": { "version": "file:../Assets/Third Parties/Plugins/PrimeTween/internal/com.kyrylokuzyk.primetween.tgz", "depth": 0, @@ -22,6 +30,22 @@ "source": "builtin", "dependencies": {} }, + "com.unity.addressables": { + "version": "2.9.0", + "depth": 1, + "source": "registry", + "dependencies": { + "com.unity.profiling.core": "1.0.2", + "com.unity.test-framework": "1.4.5", + "com.unity.modules.assetbundle": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.imageconversion": "1.0.0", + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.scriptablebuildpipeline": "2.6.0", + "com.unity.modules.unitywebrequestassetbundle": "1.0.0" + }, + "url": "https://packages.unity.com" + }, "com.unity.ai.navigation": { "version": "2.0.10", "depth": 0, @@ -94,6 +118,16 @@ }, "url": "https://packages.unity.com" }, + "com.unity.localization": { + "version": "1.5.11", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.addressables": "1.25.0", + "com.unity.nuget.newtonsoft-json": "3.0.2" + }, + "url": "https://packages.unity.com" + }, "com.unity.mathematics": { "version": "1.3.3", "depth": 2, @@ -123,6 +157,13 @@ "dependencies": {}, "url": "https://packages.unity.com" }, + "com.unity.profiling.core": { + "version": "1.0.3", + "depth": 2, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, "com.unity.render-pipelines.core": { "version": "17.3.0", "depth": 1, @@ -155,6 +196,16 @@ "com.unity.render-pipelines.core": "17.0.3" } }, + "com.unity.scriptablebuildpipeline": { + "version": "2.6.0", + "depth": 2, + "source": "registry", + "dependencies": { + "com.unity.test-framework": "1.4.5", + "com.unity.modules.assetbundle": "1.0.0" + }, + "url": "https://packages.unity.com" + }, "com.unity.searcher": { "version": "4.9.4", "depth": 2,