diff --git a/Assets/FImpossible Creations/Directories Description.txt b/Assets/FImpossible Creations/Directories Description.txt
index 7018f508c..19d8cbf25 100644
--- a/Assets/FImpossible Creations/Directories Description.txt
+++ b/Assets/FImpossible Creations/Directories Description.txt
@@ -1,7 +1,8 @@
This directories are splitted into different categories for Assembly Definitions.
+(All directories mentioned below will appear when importing fimpossible assembly definitions)
You can use Assembly Definitions to speed up compilation time.
-Import .unitypackage FImpossible Assembly Definitions to have them prepared automatically.
+Import .unitypackage "FImpossible Assembly Definitions to have them prepared automatically.
/Editor - Scripts responsible for drawing inspector windows and other gui for plugins
@@ -12,4 +13,4 @@ and also additional editor menus
/Plugins - Level Design - All plugins related to level design grouped in one directory
/Plugins - Other - All plugins related to other things like optimization grouped in one directory
/Plugins - Shared - Demos plugins or my other free packages used in shared way for rest of the packages
-/Shared Tools - Shared tools for inspector windows or shared math logics
\ No newline at end of file
+/Shared Tools - Shared tools for inspector windows or shared math logics, this directory is used by all other plugins
\ No newline at end of file
diff --git a/Assets/FImpossible Creations/Editor/Editor Tools/Files and Components Support/FEditor_ScriptMenuAddOptions.Prefabs.cs b/Assets/FImpossible Creations/Editor/Editor Tools/Files and Components Support/FEditor_ScriptMenuAddOptions.Prefabs.cs
index 04134806e..a2799651c 100644
--- a/Assets/FImpossible Creations/Editor/Editor Tools/Files and Components Support/FEditor_ScriptMenuAddOptions.Prefabs.cs
+++ b/Assets/FImpossible Creations/Editor/Editor Tools/Files and Components Support/FEditor_ScriptMenuAddOptions.Prefabs.cs
@@ -115,7 +115,7 @@ namespace FIMSpace.FEditor
[MenuItem("Assets/Utilities/Sub-Assets/Destroy Sub Asset", true)]
private static bool DestroySubAssetCheck(MenuCommand menuCommand)
- { if( Selection.objects.Length == 0 ) return false; return AssetDatabase.IsSubAsset(Selection.objects[0]); }
+ { return AssetDatabase.IsSubAsset(Selection.objects[0]); }
[MenuItem("Assets/Utilities/Sub-Assets/Destroy Sub Asset", false)]
private static void DestroySubAsset(MenuCommand menuCommand)
diff --git a/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator.meta b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator.meta
new file mode 100644
index 000000000..7aa4b78ee
--- /dev/null
+++ b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 511704c08bd35394ea37e60b93d63513
+folderAsset: yes
+timeCreated: 1603290412
+licenseType: Store
+DefaultImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources.meta b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources.meta
new file mode 100644
index 000000000..d13d34f2f
--- /dev/null
+++ b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources.meta
@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: 8504e6f0ad3ec1040b6c91b589b00907
+folderAsset: yes
+timeCreated: 1532351210
+licenseType: Store
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator.meta b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator.meta
new file mode 100644
index 000000000..6b67d4e8b
--- /dev/null
+++ b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 7df895321e8326c49996143255a443cd
+folderAsset: yes
+timeCreated: 1553950449
+licenseType: Store
+DefaultImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/Deflection.png b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/Deflection.png
new file mode 100644
index 000000000..5ddab67c2
Binary files /dev/null and b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/Deflection.png differ
diff --git a/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/Deflection.png.meta b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/Deflection.png.meta
new file mode 100644
index 000000000..41efed7b0
--- /dev/null
+++ b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/Deflection.png.meta
@@ -0,0 +1,116 @@
+fileFormatVersion: 2
+guid: 2d136b24af83be649b68f39b1e0ce67d
+TextureImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 11
+ 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
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: -1
+ aniso: 1
+ mipBias: -100
+ wrapU: 1
+ wrapV: 1
+ wrapW: -1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ applyGammaDecoding: 0
+ platformSettings:
+ - serializedVersion: 3
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: 4
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 1
+ 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
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ spritePackingTag:
+ pSDRemoveMatte: 0
+ pSDShowRemoveMatteOption: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/FTail_CollisionHelper Icon.png b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/FTail_CollisionHelper Icon.png
new file mode 100644
index 000000000..a5579669c
Binary files /dev/null and b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/FTail_CollisionHelper Icon.png differ
diff --git a/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/FTail_CollisionHelper Icon.png.meta b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/FTail_CollisionHelper Icon.png.meta
new file mode 100644
index 000000000..89cf8d7e3
--- /dev/null
+++ b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/FTail_CollisionHelper Icon.png.meta
@@ -0,0 +1,74 @@
+fileFormatVersion: 2
+guid: 6e4e9af30ed1bf944be42dfa1b3842e3
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 4
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ sRGBTexture: 0
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: -1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Standalone
+ maxTextureSize: 2048
+ textureFormat: 4
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 1
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/IKIcon.png b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/IKIcon.png
new file mode 100644
index 000000000..979e908ee
Binary files /dev/null and b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/IKIcon.png differ
diff --git a/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/IKIcon.png.meta b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/IKIcon.png.meta
new file mode 100644
index 000000000..53dd1be1a
--- /dev/null
+++ b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/IKIcon.png.meta
@@ -0,0 +1,104 @@
+fileFormatVersion: 2
+guid: e8206fdb058138940aeb32c519d84281
+TextureImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 11
+ 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
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: -1
+ aniso: 1
+ mipBias: -100
+ wrapU: 1
+ wrapV: 1
+ wrapW: -1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ applyGammaDecoding: 0
+ platformSettings:
+ - serializedVersion: 3
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: 4
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 1
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ spritePackingTag:
+ pSDRemoveMatte: 0
+ pSDShowRemoveMatteOption: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/PartialBlendIcon.png b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/PartialBlendIcon.png
new file mode 100644
index 000000000..6ac5c6186
Binary files /dev/null and b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/PartialBlendIcon.png differ
diff --git a/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/PartialBlendIcon.png.meta b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/PartialBlendIcon.png.meta
new file mode 100644
index 000000000..7a028b9c0
--- /dev/null
+++ b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/PartialBlendIcon.png.meta
@@ -0,0 +1,86 @@
+fileFormatVersion: 2
+guid: 1be512d4fc0d19d4b957fa92fe767f3e
+TextureImporter:
+ fileIDToRecycleName: {}
+ externalObjects: {}
+ serializedVersion: 4
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ sRGBTexture: 0
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapU: 1
+ wrapV: 1
+ wrapW: -1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ - buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: 4
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 1
+ androidETC2FallbackOverride: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/SPR_TailAnimatorWindIcon.png b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/SPR_TailAnimatorWindIcon.png
new file mode 100644
index 000000000..f45431a11
Binary files /dev/null and b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/SPR_TailAnimatorWindIcon.png differ
diff --git a/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/SPR_TailAnimatorWindIcon.png.meta b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/SPR_TailAnimatorWindIcon.png.meta
new file mode 100644
index 000000000..9866152dd
--- /dev/null
+++ b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/SPR_TailAnimatorWindIcon.png.meta
@@ -0,0 +1,116 @@
+fileFormatVersion: 2
+guid: 73e848e8b105ad4419739438d540ff07
+TextureImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 11
+ 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
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: -1
+ aniso: 1
+ mipBias: -100
+ wrapU: 1
+ wrapV: 1
+ wrapW: -1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ applyGammaDecoding: 0
+ platformSettings:
+ - serializedVersion: 3
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: 4
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 1
+ 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
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ spritePackingTag:
+ pSDRemoveMatte: 0
+ pSDShowRemoveMatteOption: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/Tail Animator Collision Helper Icon.png b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/Tail Animator Collision Helper Icon.png
new file mode 100644
index 000000000..d5d6a5398
Binary files /dev/null and b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/Tail Animator Collision Helper Icon.png differ
diff --git a/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/Tail Animator Collision Helper Icon.png.meta b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/Tail Animator Collision Helper Icon.png.meta
new file mode 100644
index 000000000..b3d404b2b
--- /dev/null
+++ b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/Tail Animator Collision Helper Icon.png.meta
@@ -0,0 +1,116 @@
+fileFormatVersion: 2
+guid: a05a4f2884a2af44eaeedea1ea5ca396
+TextureImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 11
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: -1
+ aniso: 1
+ mipBias: -100
+ wrapU: 1
+ wrapV: 1
+ wrapW: -1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ applyGammaDecoding: 0
+ platformSettings:
+ - serializedVersion: 3
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: 4
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 1
+ 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
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ spritePackingTag:
+ pSDRemoveMatte: 0
+ pSDShowRemoveMatteOption: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/Tail Animator Icon Small.png b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/Tail Animator Icon Small.png
new file mode 100644
index 000000000..cb61204c0
Binary files /dev/null and b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/Tail Animator Icon Small.png differ
diff --git a/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/Tail Animator Icon Small.png.meta b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/Tail Animator Icon Small.png.meta
new file mode 100644
index 000000000..68f005f2d
--- /dev/null
+++ b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/Tail Animator Icon Small.png.meta
@@ -0,0 +1,86 @@
+fileFormatVersion: 2
+guid: 10dc66ee21c31144882ddd7d2f13ae77
+TextureImporter:
+ fileIDToRecycleName: {}
+ externalObjects: {}
+ serializedVersion: 4
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ sRGBTexture: 0
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapU: 1
+ wrapV: 1
+ wrapW: -1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ - buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: 4
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 1
+ androidETC2FallbackOverride: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/Tail Animator Icon.png b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/Tail Animator Icon.png
new file mode 100644
index 000000000..14009f167
Binary files /dev/null and b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/Tail Animator Icon.png differ
diff --git a/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/Tail Animator Icon.png.meta b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/Tail Animator Icon.png.meta
new file mode 100644
index 000000000..ea24d5062
--- /dev/null
+++ b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/Tail Animator Icon.png.meta
@@ -0,0 +1,86 @@
+fileFormatVersion: 2
+guid: 2e215648cc15ce04297817f7407c4e7b
+TextureImporter:
+ fileIDToRecycleName: {}
+ externalObjects: {}
+ serializedVersion: 4
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 0
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ 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: 2
+ textureShape: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ - buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: 4
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 1
+ androidETC2FallbackOverride: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/Tail Animator Skinner API Icon.png b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/Tail Animator Skinner API Icon.png
new file mode 100644
index 000000000..6c0ca6d5d
Binary files /dev/null and b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/Tail Animator Skinner API Icon.png differ
diff --git a/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/Tail Animator Skinner API Icon.png.meta b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/Tail Animator Skinner API Icon.png.meta
new file mode 100644
index 000000000..fbd7fbfb5
--- /dev/null
+++ b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/Tail Animator Skinner API Icon.png.meta
@@ -0,0 +1,116 @@
+fileFormatVersion: 2
+guid: f1f543bbb761e234cbb384a09c3482cc
+TextureImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 11
+ 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
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: -1
+ aniso: 1
+ mipBias: -100
+ wrapU: 1
+ wrapV: 1
+ wrapW: -1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ applyGammaDecoding: 0
+ platformSettings:
+ - serializedVersion: 3
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: 4
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 1
+ 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
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ spritePackingTag:
+ pSDRemoveMatte: 0
+ pSDShowRemoveMatteOption: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/Tail Animator Skinner Icon.png b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/Tail Animator Skinner Icon.png
new file mode 100644
index 000000000..ba921166a
Binary files /dev/null and b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/Tail Animator Skinner Icon.png differ
diff --git a/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/Tail Animator Skinner Icon.png.meta b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/Tail Animator Skinner Icon.png.meta
new file mode 100644
index 000000000..e6a92a957
--- /dev/null
+++ b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/Tail Animator Skinner Icon.png.meta
@@ -0,0 +1,116 @@
+fileFormatVersion: 2
+guid: 7958d01c62579034fa1ffbb911dd6b59
+TextureImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 11
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: -1
+ aniso: 1
+ mipBias: -100
+ wrapU: 1
+ wrapV: 1
+ wrapW: -1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ applyGammaDecoding: 0
+ platformSettings:
+ - serializedVersion: 3
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: 4
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 1
+ 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
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ spritePackingTag:
+ pSDRemoveMatte: 0
+ pSDShowRemoveMatteOption: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/TailAnimatorWindIconSmall.png b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/TailAnimatorWindIconSmall.png
new file mode 100644
index 000000000..f3d53e2ac
Binary files /dev/null and b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/TailAnimatorWindIconSmall.png differ
diff --git a/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/TailAnimatorWindIconSmall.png.meta b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/TailAnimatorWindIconSmall.png.meta
new file mode 100644
index 000000000..e2a6d504b
--- /dev/null
+++ b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/TailAnimatorWindIconSmall.png.meta
@@ -0,0 +1,76 @@
+fileFormatVersion: 2
+guid: 2364e2c6718af0c4aaf6d3b166d5bb6e
+timeCreated: 1600109893
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 4
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ sRGBTexture: 0
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: -1
+ mipBias: -1
+ wrapMode: -1
+ nPOTScale: 1
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Standalone
+ maxTextureSize: 2048
+ textureFormat: 4
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 1
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/TailAnimator_Langs.xml b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/TailAnimator_Langs.xml
new file mode 100644
index 000000000..651691cf0
--- /dev/null
+++ b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/TailAnimator_Langs.xml
@@ -0,0 +1,192 @@
+
+
+
+
+ Main Setup
+ Tail Chain
+ Optimization & More
+
+ Setup
+ Tweak
+ Features
+ Shaping
+
+ Tweak Animation
+ Limiting Motion
+ Smoothing Motion
+ Additional Parameters
+
+ Additional Modules
+ Auto Waving
+ Collisions
+ Colliders Setup
+
+ Partial Blend
+ Inverse Kinematics (IK)
+ Deflection
+ Disable when Far
+
+ Additional Shaping
+
+ Physical Effectors
+ Wind Effect
+
+
+
+ Konfiguracja
+ Łańcuch
+ Optymalizacja i Inne
+
+ Przygotuj
+ Dostosuj
+ Dodatki
+ Kształt
+
+ Przystosowanie Animacji
+ Limitowanie
+ Wygładzanie Ruchu
+ Parametry Dodatkowe
+
+ Dodatkowe Moduły
+ Machanie
+ Kolizje
+ Konfiguracja Koliderów
+
+ Częściowy Wpływ Animatora
+ Odwrócona Kinematyka (IK)
+ Odgięcia
+ Wyłącz gdy zbyt daleko
+
+ Dodatkowe Kształtowanie
+
+ Efekty Fizyczne
+ Efekt Wiatru
+
+
+ <русский>
+ Основная настройка
+ хвост цепи
+ Оптимизация и многое другое
+
+ Настройка
+ Настройки
+ Возможности
+ Формирование
+
+ Настроить анимацию
+ Ограничение движения
+ Сглаживание движения
+ Дополнительные параметры
+
+ Дополнительные модули
+ Авто Размахивая
+ Столкновения
+ Коллайдеры Настройка
+
+ Частичная смесь
+ Обратная кинематика (IK)
+ Отражение
+ Выключите, когда далеко
+
+ Дополнительные формы
+
+ Физические эффекторы
+ Воздействие ветра
+ русский>
+
+ <中文>
+ 主设置
+ 尾链
+ 优化和更多
+
+ 设置
+ 调整
+ 功能
+ 形状
+
+ 调整动画
+ 限制运动
+ 平滑运动
+ 附加参数
+
+ 附加模块
+ 自动挥动
+ 碰撞
+ 碰撞器设置
+
+ 部分混合
+ 反向运动 (IK)
+ 偏转
+ 远方时关闭
+
+ 附加整形
+
+ 物理效应器
+ 风效应
+ 中文>
+
+
+ <日本語>
+ メインセットアップ
+ テールチェーン
+ 最適化と、モーションを制限するアニメーション
+
+ セットアップ
+ 微調整
+ 機能
+ シェーピング
+
+ スムージングモーション
+ を制限するアニメーションを
+ ツイークする追加パラメータ
+ 追加のパラメータ
+
+ コライダの自動
+ ウェーブ
+ コライダ設定
+ コライダ設定
+
+ 部分ブレンド
+ インバースキネマティクス (IK)
+ 偏向
+ 遠く離れたときにオフにする
+
+ 追加シェーピング
+
+ フィジカルエフェクター
+ 風の効果
+ 日本語>
+
+
+ <한국어>
+ 메인 설정
+ 테일 체인
+ 최적화 및 더 많은
+
+ 설정
+ 조정
+ 기능
+ 모양
+
+ 애니메이션 조정
+ 모션 제한
+ 스무딩 모션
+ 추가 매개 변수
+
+ 추가 모듈
+ 자동 흔들기
+ 충돌
+ 콜라이더 설정
+
+ 부분 혼합
+ 역 역학 (IK)
+ 편향
+ 멀리 떨어져 있을 때 끄기
+
+ 추가 성형
+
+ 물리 효과
+ 바람 효과
+ 한국어>
+
+
\ No newline at end of file
diff --git a/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/TailAnimator_Langs.xml.meta b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/TailAnimator_Langs.xml.meta
new file mode 100644
index 000000000..c1a9310d1
--- /dev/null
+++ b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/TailAnimator_Langs.xml.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: a7eb67ced331ec24b845911cd4ae82d1
+TextScriptImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/WavingIcon.png b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/WavingIcon.png
new file mode 100644
index 000000000..23f344640
Binary files /dev/null and b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/WavingIcon.png differ
diff --git a/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/WavingIcon.png.meta b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/WavingIcon.png.meta
new file mode 100644
index 000000000..b314a0e53
--- /dev/null
+++ b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/WavingIcon.png.meta
@@ -0,0 +1,86 @@
+fileFormatVersion: 2
+guid: 3b86ed89e09bbe5428b182b3ca650663
+TextureImporter:
+ fileIDToRecycleName: {}
+ externalObjects: {}
+ serializedVersion: 4
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ sRGBTexture: 0
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ 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: 2
+ textureShape: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ - buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: 4
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 1
+ androidETC2FallbackOverride: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/Wind.png b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/Wind.png
new file mode 100644
index 000000000..a6d2cc3d1
Binary files /dev/null and b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/Wind.png differ
diff --git a/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/Wind.png.meta b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/Wind.png.meta
new file mode 100644
index 000000000..72487f403
--- /dev/null
+++ b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/Resources/Tail Animator/Wind.png.meta
@@ -0,0 +1,116 @@
+fileFormatVersion: 2
+guid: bedb2c7a06ea4464b949cc2c4a4ef4fa
+TextureImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 11
+ 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
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: -1
+ aniso: 1
+ mipBias: -100
+ wrapU: 1
+ wrapV: 1
+ wrapW: -1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ applyGammaDecoding: 0
+ platformSettings:
+ - serializedVersion: 3
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: 4
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 1
+ 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
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ spritePackingTag:
+ pSDRemoveMatte: 0
+ pSDShowRemoveMatteOption: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/TailAnimator.Editor.Elements.cs b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/TailAnimator.Editor.Elements.cs
new file mode 100644
index 000000000..b9d32673c
--- /dev/null
+++ b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/TailAnimator.Editor.Elements.cs
@@ -0,0 +1,779 @@
+using FIMSpace.FEditor;
+using UnityEditor;
+using UnityEngine;
+
+namespace FIMSpace.FTail
+{
+ public partial class FTailAnimator2_Editor
+ {
+ private bool drawHeaderFoldout = false;
+ private void HeaderBoxMain(string title, ref bool drawGizmos, ref bool defaultInspector, Texture2D scrIcon, MonoBehaviour target, int height = 22)
+ {
+ EditorGUILayout.BeginVertical(FGUI_Resources.HeaderBoxStyle);
+
+ EditorGUILayout.BeginHorizontal();
+
+ if (GUILayout.Button(new GUIContent(scrIcon), EditorStyles.label, new GUILayoutOption[2] { GUILayout.Width(height - 2), GUILayout.Height(height - 2) }))
+ {
+ MonoScript script = MonoScript.FromMonoBehaviour(target);
+ if (script) EditorGUIUtility.PingObject(script);
+ drawHeaderFoldout = !drawHeaderFoldout;
+ }
+
+ if (GUILayout.Button(title, FGUI_Resources.GetTextStyle(14, true, TextAnchor.MiddleLeft), GUILayout.Height(height)))
+ {
+ MonoScript script = MonoScript.FromMonoBehaviour(target);
+ if (script) EditorGUIUtility.PingObject(script);
+ drawHeaderFoldout = !drawHeaderFoldout;
+ }
+
+ if (EditorGUIUtility.currentViewWidth > 326)
+ // Youtube channel button
+ if (GUILayout.Button(new GUIContent(FGUI_Resources.Tex_Tutorials, "Open FImpossible Creations Channel with tutorial videos in your web browser"), FGUI_Resources.ButtonStyle, new GUILayoutOption[2] { GUILayout.Width(height), GUILayout.Height(height) }))
+ {
+ Application.OpenURL("https://www.youtube.com/c/FImpossibleCreations");
+ }
+
+ if (EditorGUIUtility.currentViewWidth > 292)
+ // Store site button
+ if (GUILayout.Button(new GUIContent(FGUI_Resources.Tex_Website, "Open FImpossible Creations Asset Store Page inside your web browser"), FGUI_Resources.ButtonStyle, new GUILayoutOption[2] { GUILayout.Width(height), GUILayout.Height(height) }))
+ {
+ Application.OpenURL("https://assetstore.unity.com/publishers/37262");
+ }
+
+ // Manual file button
+ if (_manualFile == null) _manualFile = AssetDatabase.LoadAssetAtPath(System.IO.Path.GetDirectoryName(AssetDatabase.GetAssetPath(MonoScript.FromMonoBehaviour(target))) + "/Tail Animator - User Manual.pdf");
+ if (_manualFile)
+ if (GUILayout.Button(new GUIContent(FGUI_Resources.Tex_Manual, "Open .PDF user manual file for Tail Animator"), FGUI_Resources.ButtonStyle, new GUILayoutOption[2] { GUILayout.Width(height), GUILayout.Height(height) }))
+ {
+ EditorGUIUtility.PingObject(_manualFile);
+ Application.OpenURL(Application.dataPath + "/" + AssetDatabase.GetAssetPath(_manualFile).Replace("Assets/", ""));
+ }
+
+ FGUI_Inspector.DrawSwitchButton(ref drawGizmos, FGUI_Resources.Tex_GizmosOff, FGUI_Resources.Tex_Gizmos, "Toggle drawing gizmos on character in scene window", height, height, true);
+ FGUI_Inspector.DrawSwitchButton(ref drawHeaderFoldout, FGUI_Resources.Tex_LeftFold, FGUI_Resources.Tex_DownFold, "Toggle to view additional options for foldouts", height, height);
+
+ EditorGUILayout.EndHorizontal();
+
+ if (drawHeaderFoldout)
+ {
+ FGUI_Inspector.DrawUILine(0.07f, 0.1f, 1, 4, 0.99f);
+
+ EditorGUILayout.BeginHorizontal();
+
+ EditorGUI.BeginChangeCheck();
+ choosedLang = (ELangs)EditorGUILayout.EnumPopup(choosedLang, new GUIStyle(EditorStyles.layerMaskField) { fixedHeight = 0 }, new GUILayoutOption[2] { GUILayout.Width(80), GUILayout.Height(22) });
+ if (EditorGUI.EndChangeCheck())
+ {
+ PlayerPrefs.SetInt("FimposLang", (int)choosedLang);
+ SetupLangs();
+ }
+
+ GUILayout.FlexibleSpace();
+
+
+ bool hierSwitchOn = PlayerPrefs.GetInt("AnimsH", 1) == 1;
+ FGUI_Inspector.DrawSwitchButton(ref hierSwitchOn, FGUI_Resources.Tex_HierSwitch, null, "Switch drawing small icons in hierarchy", height, height, true);
+ PlayerPrefs.SetInt("AnimsH", hierSwitchOn ? 1 : 0);
+
+
+ if (GUILayout.Button(new GUIContent(FGUI_Resources.Tex_Rename, "Change component title to yours (current: '" + Get._editor_Title + "'"), FGUI_Resources.ButtonStyle, new GUILayoutOption[2] { GUILayout.Width(height), GUILayout.Height(height) }))
+ {
+ string filename = EditorUtility.SaveFilePanelInProject("Type your title (no file will be created)", Get._editor_Title, "", "Type your title (no file will be created)");
+ if (!string.IsNullOrEmpty(filename))
+ {
+ filename = System.IO.Path.GetFileNameWithoutExtension(filename);
+ if (!string.IsNullOrEmpty(filename))
+ { Get._editor_Title = filename; serializedObject.ApplyModifiedProperties(); }
+ }
+ }
+
+ // Old new UI Button
+ //FGUI_Inspector.DrawSwitchButton(ref drawNewInspector, FGUI_Resources.Tex_AB, null, "Switch GUI Style to old / new", height, height, true);
+ //if (!drawNewInspector && drawDefaultInspector) drawDefaultInspector = false;
+
+ // Default inspector switch
+ FGUI_Inspector.DrawSwitchButton(ref defaultInspector, FGUI_Resources.Tex_Default, null, "Toggle inspector view to default inspector.\n\nIf you ever edit source code of Look Animator and add custom variables, you can see them by entering this mode, also sometimes there can be additional/experimental variables to play with.", height, height);
+
+ EditorGUILayout.EndHorizontal();
+ }
+
+ EditorGUILayout.EndVertical();
+ }
+
+
+ public bool hideSkin = false;
+ void El_DrawOptimizeWithMesh()
+ {
+ // Drawing box informing if spine animator is working by mesh visibility factor
+ if (Get.OptimizeWithMesh)
+ {
+ if (Application.isPlaying)
+ {
+ GUI.color = new Color(1f, 1f, 1f, .5f);
+ EditorGUILayout.BeginHorizontal(EditorStyles.helpBox);
+
+ if (!Get.DisabledByInvisibility())
+ EditorGUILayout.LabelField("Spine Animator Is Active", FGUI_Resources.HeaderStyle);
+ else
+ {
+ GUI.enabled = false;
+ EditorGUILayout.LabelField("Spine Animator Is Inactive", FGUI_Resources.HeaderStyle);
+ GUI.enabled = true;
+ }
+
+ EditorGUILayout.EndHorizontal();
+ GUI.color = c;
+ }
+ }
+
+
+ EditorGUILayout.BeginHorizontal();
+
+ EditorGUIUtility.labelWidth = 144;
+ EditorGUILayout.PropertyField(sp_OptimizeWithMesh);
+ EditorGUIUtility.labelWidth = 0;
+
+ if (Get.OptimizeWithMesh == null)
+ {
+ if (GUILayout.Button("Find", new GUILayoutOption[1] { GUILayout.Width(44) }))
+ {
+ if (Get.OptimizeWithMesh == null)
+ {
+ Get.OptimizeWithMesh = Get.transform.GetComponent();
+ if (!Get.OptimizeWithMesh) Get.OptimizeWithMesh = Get.transform.GetComponentInChildren();
+ if (!Get.OptimizeWithMesh) if (Get.transform.parent != null) Get.OptimizeWithMesh = Get.transform.parent.GetComponentInChildren();
+ if (!Get.OptimizeWithMesh) if (Get.transform.parent != null) if (Get.transform.parent.parent != null) Get.OptimizeWithMesh = Get.transform.parent.parent.GetComponentInChildren();
+ if (!Get.OptimizeWithMesh) if (Get.transform.parent != null) if (Get.transform.parent.parent != null) if (Get.transform.parent.parent.parent != null) Get.OptimizeWithMesh = Get.transform.parent.parent.parent.GetComponentInChildren();
+ }
+ }
+ }
+ else
+ {
+ if (GUILayout.Button(hideSkin ? "Show" : "Hide", new GUILayoutOption[1] { GUILayout.Width(44) }))
+ {
+ hideSkin = !hideSkin;
+
+ if (hideSkin)
+ for (int i = 0; i < skins.Count; i++) skins[i].shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.ShadowsOnly;
+ else
+ for (int i = 0; i < skins.Count; i++) skins[i].shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.On;
+ }
+ }
+
+ EditorGUILayout.EndHorizontal();
+
+ if ( Get.OptimizeWithMesh)
+ {
+ SerializedProperty spc = sp_OptimizeWithMesh.Copy();
+ spc.Next(false);
+ EditorGUILayout.PropertyField(spc);
+ }
+ }
+
+
+ void El_DrawSpringiness()
+ {
+ GUI.color = new Color(1f, 1f, 1f, 0.7f);
+ EditorGUILayout.BeginVertical();
+
+ string balAdd = "";
+ string balTip = "";
+
+ if (!Get.UseCurlingCurve && !Get.UseSpringCurve && !Get.UseSlitheryCurve)
+ if (Get.Curling > 0.3f)
+ {
+ if (Get.Springiness > Mathf.Epsilon)
+ {
+ float treshold = Mathf.Lerp(0.3f, 0.08f, Get.Slithery);
+
+ if (Get.Springiness + treshold < Get.Curling)
+ {
+ balAdd = " ► ";
+ balTip = "Springiness should be set higher to notice bouncy motion";
+ }
+ else
+ if (Get.Springiness - treshold * 0.7f > Get.Curling)
+ {
+ balAdd = " ◄ ";
+ balTip = "Springiness should be set lower to avoid too rapid bounces";
+ }
+ }
+ }
+
+
+ // Tooltip texts
+ EditorGUILayout.BeginHorizontal();
+ if (Get.UseSpringCurve)
+ GUILayout.Label(" Tail Start", smallStyle);
+ else
+ GUILayout.Label(new GUIContent(" Balanced" + " " + balAdd, balTip), smallStyle);
+
+ GUILayout.FlexibleSpace();
+
+ if (Get.UseSpringCurve)
+ GUILayout.Label("Tail End ", smallStyle);
+ else
+ GUILayout.Label(new GUIContent(balAdd + " " + "Bouncy ", balTip), smallStyle);
+
+ EditorGUILayout.EndHorizontal();
+
+ if (Get.UseSpringCurve)
+ GUILayout.Space(-0f);
+ else
+ GUILayout.Space(-4f);
+
+ //if (Get.Springiness == 0.0f) GUI.color = defaultValC; else
+ GUI.color = c;
+
+ if (Get.UseSpringCurve)
+ {
+ EditorGUILayout.BeginHorizontal();
+ EditorGUILayout.PropertyField(sp_SpringCurve, new GUIContent(sp_Springiness.displayName, sp_Springiness.tooltip), GUILayout.MaxHeight(18)); GUILayout.Space(3f);
+ EditorGUI.BeginChangeCheck();
+ SwitchButton(ref Get.UseSpringCurve, "Spread springiness speed parameter weight over tail segments", curveIcon);
+ if (EditorGUI.EndChangeCheck())
+ {
+ GetSelectedTailAnimators(); for (int i = 0; i < lastSelected.Count; i++)
+ {
+ lastSelected[i].UseSpringCurve = Get.UseSpringCurve; new SerializedObject(lastSelected[i]).ApplyModifiedProperties();
+ }
+ }
+ EditorGUILayout.EndHorizontal();
+ GUILayout.Space(2f);
+ }
+ else
+ {
+ EditorGUILayout.BeginHorizontal(); EditorGUIUtility.fieldWidth = 38;
+ EditorGUILayout.PropertyField(sp_Springiness); EditorGUIUtility.fieldWidth = 0;
+ EditorGUI.BeginChangeCheck();
+ SwitchButton(ref Get.UseSpringCurve, "Spread springiness speed parameter weight over tail segments", curveIcon);
+ if (EditorGUI.EndChangeCheck()) { GetSelectedTailAnimators(); for (int i = 0; i < lastSelected.Count; i++) { lastSelected[i].UseSpringCurve = Get.UseSpringCurve; new SerializedObject(lastSelected[i]).ApplyModifiedProperties(); } }
+ EditorGUILayout.EndHorizontal();
+ }
+
+
+ GUI.color = c;
+ EditorGUILayout.EndVertical();
+
+ EditorGUILayout.BeginVertical();
+ }
+
+
+ void El_DrawSlippery()
+ {
+ EditorGUILayout.BeginVertical();
+
+ if (Get.UseSlipperyCurve)
+ {
+ EditorGUILayout.BeginHorizontal();
+ GUI.color = new Color(1f, 1f, 1f, 0.7f);
+
+ GUILayout.Label(" Tail Start", smallStyle);
+
+ GUILayout.FlexibleSpace();
+
+ GUILayout.Label("Tail End ", smallStyle);
+ GUI.color = c;
+
+ EditorGUILayout.EndHorizontal();
+
+ EditorGUILayout.BeginHorizontal();
+ EditorGUILayout.PropertyField(sp_SlipperyCurve, new GUIContent("Collision Slippery", sp_SlipperyCurve.tooltip), GUILayout.MaxHeight(18)); GUILayout.Space(3f);
+ EditorGUI.BeginChangeCheck();
+ SwitchButton(ref Get.UseSlipperyCurve, "Spread collision slippery parameter over tail segments", curveIcon);
+ if (EditorGUI.EndChangeCheck()) { GetSelectedTailAnimators(); for (int i = 0; i < lastSelected.Count; i++) { lastSelected[i].UseSlipperyCurve = Get.UseSlipperyCurve; new SerializedObject(lastSelected[i]).ApplyModifiedProperties(); } }
+ EditorGUILayout.EndHorizontal();
+ GUILayout.Space(2f);
+ }
+ else
+ {
+ EditorGUILayout.BeginHorizontal(); EditorGUIUtility.fieldWidth = 38;
+ EditorGUILayout.PropertyField(sp_CollisionSlippery); EditorGUIUtility.fieldWidth = 0;
+ EditorGUI.BeginChangeCheck();
+ SwitchButton(ref Get.UseSlipperyCurve, "Spread collision slippery parameter over tail segments", curveIcon);
+ if (EditorGUI.EndChangeCheck()) { GetSelectedTailAnimators(); for (int i = 0; i < lastSelected.Count; i++) { lastSelected[i].UseSlipperyCurve = Get.UseSlipperyCurve; new SerializedObject(lastSelected[i]).ApplyModifiedProperties(); } }
+ EditorGUILayout.EndHorizontal();
+ }
+
+ EditorGUILayout.EndVertical();
+ //EditorGUILayout.BeginVertical();
+ }
+
+
+ void El_DrawSlithery()
+ {
+ GUI.color = new Color(1f, 1f, 1f, 0.7f);
+ EditorGUILayout.BeginHorizontal();
+ if (Get.UseSlitheryCurve)
+ GUILayout.Label(" Tail Start", smallStyle);
+ else
+ GUILayout.Label(" Stiff", smallStyle);
+
+ GUILayout.FlexibleSpace();
+
+ if (Get.UseSlitheryCurve)
+ GUILayout.Label("Tail End ", smallStyle);
+ else
+ GUILayout.Label("Smooth ", smallStyle);
+
+ EditorGUILayout.EndHorizontal();
+ GUI.color = c;
+
+ if (Get.UseSlitheryCurve)
+ GUILayout.Space(0f);
+ else
+ GUILayout.Space(-3f);
+
+
+ if (Get.UseSlitheryCurve)
+ {
+ EditorGUILayout.BeginHorizontal();
+ EditorGUILayout.PropertyField(sp_SlitCurve, new GUIContent(sp_Slithery.displayName, sp_Slithery.tooltip), GUILayout.MaxHeight(18)); GUILayout.Space(3f);
+ EditorGUI.BeginChangeCheck();
+ SwitchButton(ref Get.UseSlitheryCurve, "Spread sensitivity speed parameter weight over tail segments", curveIcon);
+ if (EditorGUI.EndChangeCheck()) { GetSelectedTailAnimators(); for (int i = 0; i < lastSelected.Count; i++) { lastSelected[i].UseSlitheryCurve = Get.UseSlitheryCurve; new SerializedObject(lastSelected[i]).ApplyModifiedProperties(); } }
+ EditorGUILayout.EndHorizontal();
+ }
+ else
+ {
+ EditorGUILayout.BeginHorizontal(); EditorGUIUtility.fieldWidth = 38;
+ EditorGUILayout.PropertyField(sp_Slithery); EditorGUIUtility.fieldWidth = 0;
+ EditorGUI.BeginChangeCheck();
+ SwitchButton(ref Get.UseSlitheryCurve, "Spread sensitivity speed parameter weight over tail segments", curveIcon);
+ if (EditorGUI.EndChangeCheck()) { GetSelectedTailAnimators(); for (int i = 0; i < lastSelected.Count; i++) { lastSelected[i].UseSlitheryCurve = Get.UseSlitheryCurve; new SerializedObject(lastSelected[i]).ApplyModifiedProperties(); } }
+ EditorGUILayout.EndHorizontal();
+ }
+
+ GUI.color = c;
+ }
+
+
+ void El_DrawCurling()
+ {
+
+ GUI.color = new Color(1f, 1f, 1f, 0.7f);
+
+ EditorGUILayout.BeginHorizontal();
+
+
+
+ string straiAdd = "";
+ string straiTip = "";
+
+ if (!Get.UseCurlingCurve && !Get.UseSpringCurve && !Get.UseSlitheryCurve)
+ if (Get.Springiness > Mathf.Epsilon)
+ {
+ //float treshold = Mathf.Lerp(0.3f, 0.08f, Get.Slithery);
+
+ if (Get.Curling < Get.Springiness)
+ {
+ straiAdd = " ► ";
+ straiTip = "Feel free to boost curling high when you're using springiness";
+ }
+ }
+
+
+ if (Get.UseCurlingCurve)
+ GUILayout.Label(" Tail Start", smallStyle);
+ else
+ GUILayout.Label(new GUIContent(" Straightened " + straiAdd, straiTip), smallStyle);
+
+ GUILayout.FlexibleSpace();
+
+ if (Get.UseCurlingCurve)
+ GUILayout.Label("Tail End ", smallStyle);
+ else
+ GUILayout.Label("Tangled ", smallStyle);
+
+ EditorGUILayout.EndHorizontal();
+ GUI.color = c;
+
+ if (Get.UseCurlingCurve)
+ GUILayout.Space(0f);
+ else
+ GUILayout.Space(-2f);
+
+
+ //if (Get.Curling == 0.5f) GUI.color = defaultValC; else
+ GUI.color = c;
+
+
+ if (Get.UseCurlingCurve)
+ {
+ EditorGUILayout.BeginHorizontal();
+ EditorGUILayout.PropertyField(sp_CurlingCurve, new GUIContent(sp_Curling.displayName, sp_Curling.tooltip), GUILayout.MaxHeight(18)); GUILayout.Space(3f);
+ EditorGUI.BeginChangeCheck();
+ SwitchButton(ref Get.UseCurlingCurve, "Spread curling over tail segments", curveIcon);
+ if (EditorGUI.EndChangeCheck()) { GetSelectedTailAnimators(); for (int i = 0; i < lastSelected.Count; i++) { lastSelected[i].UseCurlingCurve = Get.UseCurlingCurve; new SerializedObject(lastSelected[i]).ApplyModifiedProperties(); } }
+ EditorGUILayout.EndHorizontal();
+ }
+ else
+ {
+ EditorGUILayout.BeginHorizontal(); EditorGUIUtility.fieldWidth = 38;
+ EditorGUILayout.PropertyField(sp_Curling); EditorGUIUtility.fieldWidth = 0;
+ EditorGUI.BeginChangeCheck();
+ SwitchButton(ref Get.UseCurlingCurve, "Spread curling parameter over tail segments", curveIcon);
+ if (EditorGUI.EndChangeCheck()) { GetSelectedTailAnimators(); for (int i = 0; i < lastSelected.Count; i++) { lastSelected[i].UseCurlingCurve = Get.UseCurlingCurve; new SerializedObject(lastSelected[i]).ApplyModifiedProperties(); } }
+ EditorGUILayout.EndHorizontal();
+ }
+
+ GUI.color = c;
+ }
+
+
+ void El_DrawLimitingAngle()
+ {
+ if (Get.AngleLimit > 180) GUI.color = defaultValC;
+ EditorGUILayout.PropertyField(sp_AngleLimit);
+ GUI.color = c;
+
+ if (Get.AngleLimit < 181)
+ {
+ if (Get.AngleLimitAxis == Vector3.zero) GUI.color = c * new Color(1f, 1f, 1f, 0.6f);
+ EditorGUILayout.PropertyField(sp_AngleLimitAxis);
+ GUI.color = c;
+
+ if (Get.AngleLimitAxis != Vector3.zero)
+ {
+ if (Get.LimitAxisRange.x == Get.LimitAxisRange.y) GUI.color = c * new Color(1f, 1f, 1f, 0.6f);
+ EditorGUILayout.MinMaxSlider(new GUIContent("Range", "If you want limit axes symmetrically leave this parameter unchanged, if you want limit one direction of axis more than reversed, tweak this parameter"),
+ ref Get.LimitAxisRange.x, ref Get.LimitAxisRange.y, -90f, 90f);
+ GUI.color = c;
+ }
+
+ EditorGUILayout.PropertyField(sp_LimitSmoothing);
+
+ GUILayout.Space(5f);
+ }
+
+ GUI.color = c;
+ }
+
+
+ static bool drawInclud = true;
+ void El_DrawSelectiveCollisionBox()
+ {
+ if (Get.IncludedColliders == null) Get.IncludedColliders = new System.Collections.Generic.List();
+ Get._editor_IsInspectorViewingIncludedColliders = drawInclud;
+
+ GUILayout.Space(1f);
+ GUI.color = new Color(0.85f, 1f, 0.85f, 1f);
+ EditorGUILayout.BeginHorizontal(FGUI_Resources.HeaderBoxStyleH);
+ string f = FGUI_Resources.GetFoldSimbol(drawInclud); int inclC = Get.IncludedColliders.Count;
+ GUI.color = c;
+
+ GUILayout.Label(new GUIContent(" "), GUILayout.Width(1));
+ string inclColFoldTitle = "";
+
+ if (Get.DynamicWorldCollidersInclusion)
+ {
+ if (Application.isPlaying)
+ inclColFoldTitle = Lang("Collide With") + " (Dynamic" + " : " + inclC + ")";
+ else
+ inclColFoldTitle = "Always Include (" + inclC + ")";
+ }
+ else
+ inclColFoldTitle = Lang("Collide With") + " (" + (inclC == 0 ? "0 !!!" : inclC.ToString()) + ")";
+
+ if (GUILayout.Button(new GUIContent(" " + f + " " + inclColFoldTitle, FGUI_Resources.TexBehaviourIcon), FGUI_Resources.FoldStyle, GUILayout.Height(24))) drawInclud = !drawInclud;
+
+ //if (!Application.isPlaying)
+ // if (Get.DynamicWorldCollidersInclusion) drawInclud = false;
+
+ //bool checkNullIncludColls = true;
+ if (drawInclud)
+ {
+ //if (GUILayout.Button("+", new GUILayoutOption[2] { GUILayout.MaxWidth(24), GUILayout.MaxHeight(22) }))
+ //{
+ // Get.IncludedColliders.Add(null);
+ // //Get._editor_checkInclCollidersForNulls = -10;
+ // //checkNullIncludColls = false;
+ // serializedObject.Update();
+ // serializedObject.ApplyModifiedProperties();
+ //}
+ }
+
+ EditorGUILayout.EndHorizontal();
+
+ if (drawInclud)
+ {
+ FGUI_Inspector.VSpace(-3, -5);
+ GUI.color = new Color(0.6f, .9f, 0.6f, 1f);
+ EditorGUILayout.BeginVertical(FGUI_Resources.BGInBoxStyleH);
+ GUI.color = c;
+ GUILayout.Space(5f);
+
+
+ // Drawing colliders from list
+ if (Get.IncludedColliders.Count == 0)
+ {
+ EditorGUILayout.LabelField("Please add here colliders", FGUI_Resources.HeaderStyle);
+ GUILayout.Space(2f);
+ }
+ else
+ {
+ Get.CheckForColliderDuplicatesAndNulls();
+
+ EditorGUI.BeginChangeCheck();
+ for (int i = 0; i < Get.IncludedColliders.Count; i++)
+ {
+ EditorGUILayout.BeginHorizontal();
+
+ if (Get.IncludedColliders[i] != null)
+ {
+ if (!Get.IncludedColliders[i].gameObject.activeInHierarchy) GUI.color = new Color(1f, 1f, 1f, 0.5f);
+ Get.IncludedColliders[i] = (Collider)EditorGUILayout.ObjectField(Get.IncludedColliders[i], typeof(Collider), true);
+ if (!Get.IncludedColliders[i].gameObject.activeInHierarchy) GUI.color = c;
+ }
+
+ if (GUILayout.Button("X", new GUILayoutOption[2] { GUILayout.MaxWidth(22), GUILayout.MaxHeight(16) }))
+ {
+ Get.IncludedColliders.RemoveAt(i);
+ serializedObject.Update();
+ serializedObject.ApplyModifiedProperties();
+ return;
+ }
+
+ EditorGUILayout.EndHorizontal();
+ }
+
+ if (EditorGUI.EndChangeCheck())
+ {
+ Get.CheckForColliderDuplicatesAndNulls();
+ serializedObject.Update();
+ serializedObject.ApplyModifiedProperties();
+ }
+ }
+
+ GUILayout.Space(6f);
+
+ // Lock button
+ GUILayout.BeginVertical();
+ if (ActiveEditorTracker.sharedTracker.isLocked) GUI.color = new Color(0.44f, 0.44f, 0.44f, 0.8f); else GUI.color = new Color(0.95f, 0.95f, 0.99f, 0.9f);
+ if (GUILayout.Button(new GUIContent("Lock Inspector for Drag & Drop Colliders", "Drag & drop colliders to 'Included Colliders' List from the hierarchy"), FGUI_Resources.ButtonStyle, GUILayout.Height(18))) ActiveEditorTracker.sharedTracker.isLocked = !ActiveEditorTracker.sharedTracker.isLocked;
+ GUI.color = c;
+ GUILayout.EndVertical();
+
+ // Drag and drop box
+ El_DrawDragAndDropCollidersBox();
+
+ GUILayout.Space(3f);
+
+ if (Get.IncludedColliders.Count > 0)
+ {
+ EditorGUILayout.HelpBox("You can disable collider components on the objects - tail animator will still detect collision. If you deactivate the Game Object with collider - tail animator will not detect collision with it.", MessageType.Info);
+ }
+
+ EditorGUILayout.EndVertical();
+ }
+
+ }
+
+ void El_DrawSelectiveCollisionBox2D()
+ {
+ GUILayout.Space(1f);
+ GUI.color = new Color(0.85f, 1f, 0.85f, 1f);
+ EditorGUILayout.BeginHorizontal(FGUI_Resources.HeaderBoxStyleH);
+ string f = FGUI_Resources.GetFoldSimbol(drawInclud); int inclC = Get.IncludedColliders2D.Count;
+ GUI.color = c;
+
+ GUILayout.Label(new GUIContent(" "), GUILayout.Width(1));
+ string inclColFoldTitle = "";
+
+ inclColFoldTitle = "2D " + Lang("Collide With") + " (" + (inclC == 0 ? "None" : inclC.ToString()) + ")";
+
+ if (GUILayout.Button(new GUIContent(" " + f + " " + inclColFoldTitle, FGUI_Resources.TexBehaviourIcon), FGUI_Resources.FoldStyle, GUILayout.Height(24))) drawInclud = !drawInclud;
+
+ if (drawInclud)
+ if (GUILayout.Button("+", new GUILayoutOption[2] { GUILayout.MaxWidth(24), GUILayout.MaxHeight(22) }))
+ {
+ Get.IncludedColliders2D.Add(null);
+ serializedObject.Update();
+ serializedObject.ApplyModifiedProperties();
+ }
+
+ EditorGUILayout.EndHorizontal();
+
+ if (drawInclud)
+ {
+ FGUI_Inspector.VSpace(-3, -5);
+ GUI.color = new Color(0.6f, .9f, 0.6f, 1f);
+ EditorGUILayout.BeginVertical(FGUI_Resources.BGInBoxStyleH);
+ GUI.color = c;
+ GUILayout.Space(5f);
+
+ EditorGUILayout.HelpBox("2D Collision is supported ONLY FOR CIRCLE, CAPSULE, BOX and POLYGON colliders for now!", MessageType.None);
+
+ // Drawing colliders from list
+ if (Get.IncludedColliders2D.Count == 0)
+ {
+ EditorGUILayout.LabelField("Please add here 2D colliders", FGUI_Resources.HeaderStyle);
+ GUILayout.Space(2f);
+ }
+ else
+ {
+ Get.CheckForColliderDuplicatesAndNulls2D();
+
+ EditorGUI.BeginChangeCheck();
+ for (int i = 0; i < Get.IncludedColliders2D.Count; i++)
+ {
+ EditorGUILayout.BeginHorizontal();
+
+ if (Get.IncludedColliders2D[i] != null)
+ {
+ if (!Get.IncludedColliders2D[i].gameObject.activeInHierarchy) GUI.color = new Color(1f, 1f, 1f, 0.5f);
+ Get.IncludedColliders2D[i] = (Collider2D)EditorGUILayout.ObjectField(Get.IncludedColliders2D[i], typeof(Collider2D), true);
+ if (!Get.IncludedColliders2D[i].gameObject.activeInHierarchy) GUI.color = c;
+ }
+ else
+ {
+ Get.IncludedColliders2D[i] = (Collider2D)EditorGUILayout.ObjectField(Get.IncludedColliders2D[i], typeof(Collider2D), true);
+ }
+
+ if (GUILayout.Button("X", new GUILayoutOption[2] { GUILayout.MaxWidth(22), GUILayout.MaxHeight(16) }))
+ {
+ Get.IncludedColliders2D.RemoveAt(i);
+ serializedObject.Update();
+ serializedObject.ApplyModifiedProperties();
+ return;
+ }
+
+ EditorGUILayout.EndHorizontal();
+ }
+
+ if (EditorGUI.EndChangeCheck())
+ {
+ Get.CheckForColliderDuplicatesAndNulls();
+ serializedObject.Update();
+ serializedObject.ApplyModifiedProperties();
+ }
+ }
+
+ GUILayout.Space(3f);
+
+ // Lock button
+ GUILayout.BeginVertical();
+ if (ActiveEditorTracker.sharedTracker.isLocked) GUI.color = new Color(0.44f, 0.44f, 0.44f, 0.8f); else GUI.color = new Color(0.95f, 0.95f, 0.99f, 0.9f);
+ if (GUILayout.Button(new GUIContent("Lock Inspector for Drag & Drop Colliders", "Drag & drop colliders to 'Included Colliders' List from the hierarchy"), FGUI_Resources.ButtonStyle, GUILayout.Height(18))) ActiveEditorTracker.sharedTracker.isLocked = !ActiveEditorTracker.sharedTracker.isLocked;
+ GUI.color = c;
+ GUILayout.EndVertical();
+
+ // Drag and drop box
+ El_DrawDragAndDropCollidersBox();
+
+ GUILayout.Space(3f);
+
+ EditorGUILayout.EndVertical();
+ }
+
+ }
+
+
+ void El_DrawCollidersDynamicInclusion()
+ {
+ if (Get.DynamicWorldCollidersInclusion)
+ {
+ if (!Application.isPlaying)
+ {
+ GUILayout.Space(5f);
+ EditorGUILayout.HelpBox("Using trigger colliders to automatically fill 'Collide With' list", MessageType.Info);
+ GUILayout.Space(3f);
+
+ EditorGUILayout.PropertyField(sp_InclusionRadius);
+ if (Get.CollisionMode == TailAnimator2.ECollisionMode.m_3DCollision) EditorGUILayout.PropertyField(sp_IgnoreMeshColliders);
+
+ EditorGUILayout.BeginHorizontal();
+ EditorGUILayout.PropertyField(sp_colSameLayer, new GUIContent("Trigger Layer", sp_colSameLayer.tooltip));
+ if (Get.CollidersSameLayer)
+ {
+ EditorGUILayout.LabelField(" ", GUILayout.Width(2));
+ GUI.enabled = false; EditorGUILayout.LayerField(Get.gameObject.layer); GUI.enabled = true; EditorGUIUtility.labelWidth = 0;
+ }
+ else
+ {
+ EditorGUILayout.LabelField(" ", GUILayout.Width(2));
+ EditorGUILayout.PropertyField(sp_colCustomLayer, new GUIContent(""));
+ }
+ EditorGUILayout.EndHorizontal();
+
+ }
+
+ GUILayout.Space(4f);
+ EditorGUI.indentLevel++;
+
+ if (Get.CollisionMode == TailAnimator2.ECollisionMode.m_3DCollision)
+ EditorGUILayout.PropertyField(sp_colIgnored, true);
+
+ EditorGUI.indentLevel--;
+ }
+ }
+
+ void El_DrawDragAndDropCollidersBox()
+ {
+ GUILayout.Space(3);
+
+ var drop = GUILayoutUtility.GetRect(0f, 38f, new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
+ GUI.color = new Color(0.5f, 1f, 0.5f, 0.9f);
+ GUI.Box(drop, "Drag & Drop New Colliders Here", new GUIStyle(EditorStyles.helpBox) { alignment = TextAnchor.MiddleCenter, fixedHeight = 38 });
+ GUI.color = c;
+ var dropEvent = Event.current;
+
+ switch (dropEvent.type)
+ {
+ case EventType.DragUpdated:
+ case EventType.DragPerform:
+ if (!drop.Contains(dropEvent.mousePosition)) break;
+
+ DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
+
+ if (dropEvent.type == EventType.DragPerform)
+ {
+ DragAndDrop.AcceptDrag();
+
+ var tails = GetSelectedTailAnimators();
+ if (tails.Contains(Get) == false) tails.Add(Get);
+
+ foreach (var dragged in DragAndDrop.objectReferences)
+ {
+ GameObject draggedObject = dragged as GameObject;
+
+ if (draggedObject)
+ {
+
+ for (int t = 0; t < tails.Count; t++)
+ {
+ var tail = tails[t];
+ if (tail.CollisionMode == TailAnimator2.ECollisionMode.m_3DCollision)
+ {
+ Collider[] coll = draggedObject.GetComponents();
+ for (int ci = 0; ci < coll.Length; ci++)
+ {
+ tail.AddCollider(coll[ci]);
+ }
+ }
+ else
+ {
+ Collider2D[] coll = draggedObject.GetComponents();
+ for (int ci = 0; ci < coll.Length; ci++)
+ {
+ //if (coll[ci] is CharacterController) continue;
+ tail.AddCollider(coll[ci]);
+ }
+ }
+
+ EditorUtility.SetDirty(tail);
+ }
+
+ }
+ }
+
+ }
+
+ Event.current.Use();
+ break;
+ }
+ }
+
+ }
+}
diff --git a/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/TailAnimator.Editor.Elements.cs.meta b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/TailAnimator.Editor.Elements.cs.meta
new file mode 100644
index 000000000..e50118bba
--- /dev/null
+++ b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/TailAnimator.Editor.Elements.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: bcf1a74f343e94f4d83b39f22572bd73
+timeCreated: 1532131583
+licenseType: Store
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/TailAnimator.Editor.Foldouts.cs b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/TailAnimator.Editor.Foldouts.cs
new file mode 100644
index 000000000..1b06132f5
--- /dev/null
+++ b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/TailAnimator.Editor.Foldouts.cs
@@ -0,0 +1,1274 @@
+using FIMSpace.FEditor;
+using UnityEditor;
+using UnityEngine;
+
+namespace FIMSpace.FTail
+{
+ public partial class FTailAnimator2_Editor
+ {
+
+ bool drawTailTransforms = false;
+ private void Fold_TailChainSetup()
+ {
+ EditorGUILayout.BeginHorizontal();
+
+ if (GUILayout.Button(new GUIContent(" " + FGUI_Resources.GetFoldSimbol(drawTailTransforms, 10, "►") + " " + Lang("Tail Chain") + " (" + (Get._TransformsGhostChain.Count) + ")", FGUI_Resources.Tex_Bone, "Adjust count of chain bones"), FGUI_Resources.FoldStyle, new GUILayoutOption[] { GUILayout.Height(24) })) drawTailTransforms = !drawTailTransforms;
+
+ bool refreshChain = Get._GhostChainInitCount != Get._TransformsGhostChain.Count;
+ //Debug.Log("_GhostChainInitCount " + Get._GhostChainInitCount + " Get._TransformsGhostChain.Count " + Get._TransformsGhostChain.Count);
+
+ //if (drawTailTransforms)
+ //{
+ if (refreshChain) if (GUILayout.Button(new GUIContent(FGUI_Resources.Tex_Refresh /*"Refresh"*/, "Chain Bones count changed you can reset it"), FGUI_Resources.ButtonStyle, new GUILayoutOption[2] { GUILayout.Width(24), GUILayout.Height(22) })) { Get.GetGhostChain(); serializedObject.ApplyModifiedProperties(); serializedObject.Update(); return; }
+ //}
+
+ EditorGUILayout.EndHorizontal();
+
+ if (drawTailTransforms)
+ {
+ GUILayout.Space(3);
+
+ if (Get._TransformsGhostChain.Count > 1)
+ {
+ GUI.enabled = false;
+
+ GUILayout.Space(1);
+
+ for (int i = 1; i < Get._TransformsGhostChain.Count - 1; i++)
+ {
+ EditorGUILayout.BeginHorizontal();
+ EditorGUILayout.ObjectField(new GUIContent(""), Get._TransformsGhostChain[i].transform, typeof(Transform), true);
+
+ if (!Application.isPlaying) GUI.enabled = true;
+ if (GUILayout.Button(new GUIContent("X", "Remove bone from chain with this button"), new GUILayoutOption[2] { GUILayout.Width(20), GUILayout.Height(14) }))
+ {
+ Get._TransformsGhostChain.RemoveAt(i);
+ EditorUtility.SetDirty(target);
+ break;
+ }
+ GUI.enabled = false;
+
+ EditorGUILayout.EndHorizontal();
+ GUILayout.Space(1);
+ }
+
+ GUILayout.Space(2);
+ GUI.enabled = true;
+
+ if (!Application.isPlaying) GUI.enabled = true; else GUI.enabled = false;
+
+ GUI.color = c;
+ }
+ else
+ {
+ GUILayout.Space(-4f);
+ EditorGUILayout.LabelField("No bones found in list", FGUI_Resources.HeaderStyle);
+ GUILayout.Space(5f);
+ }
+
+ DrawEndBoneInChainSetup();
+
+ GUILayout.Space(2f);
+ }
+ else
+ {
+ GUI.color = new Color(1f, 1f, 1f, 0.45f);
+ GUILayout.Space(-11f);
+ EditorGUILayout.LabelField("...", FGUI_Resources.HeaderStyleBig);
+ GUILayout.Space(5f);
+ GUI.color = c;
+
+ DrawEndBoneInChainSetup();
+ }
+
+ GUILayout.Space(9f);
+ }
+
+
+ void DrawEndBoneInChainSetup()
+ {
+ if (Get._TransformsGhostChain.Count == 0)
+ {
+ if (Get.StartBone) { Get.GetGhostChain(); }
+ return;
+ }
+
+ // End bone field -----------------
+ Transform endField = Get.EndBone; if (Get.EndBone == null) { endField = Get._TransformsGhostChain[Get._TransformsGhostChain.Count - 1]; GUI.color = new Color(1f, 1f, 1f, 0.7f); }
+ //EditorGUI.BeginChangeCheck();
+ EditorGUIUtility.labelWidth = Get.EndBone == null ? 100 : 74;
+
+ GUILayout.BeginHorizontal();
+ GUILayout.BeginHorizontal();
+
+ EditorGUI.BeginChangeCheck();
+ Transform endB = (Transform)EditorGUILayout.ObjectField(new GUIContent(Get.EndBone == null ? "End Bone (Auto)" : "End Bone"), endField, typeof(Transform), true);
+ if (EditorGUI.EndChangeCheck())
+ {
+ Get.EndBone = endB;
+ Get.GetGhostChain();
+ serializedObject.Update();
+ serializedObject.ApplyModifiedProperties();
+ }
+
+
+ GUILayout.Space(5);
+
+ if (Application.isPlaying) GUI.enabled = false;
+ EditorGUILayout.LabelField("Offset", GUILayout.Width(42));
+ bool preOff = FEngineering.VIsZero(Get.EndBoneJointOffset);
+ bool makeOff = EditorGUILayout.Toggle(!FEngineering.VIsZero(Get.EndBoneJointOffset), GUILayout.Width(18));
+ if (Application.isPlaying) GUI.enabled = true;
+
+ if (Application.isPlaying) GUI.enabled = true;
+
+ GUILayout.EndHorizontal();
+ EditorGUIUtility.labelWidth = 0;
+
+ Transform sBone = Get.StartBone; if (sBone == null) sBone = Get.transform;
+ if (endB == null) { endB = GetLastChild(Get._TransformsGhostChain[Get._TransformsGhostChain.Count - 1]); }
+ //if (EditorGUI.EndChangeCheck()) { Get.EndBone = endB; serializedObject.ApplyModifiedProperties(); serializedObject.Update(); if (IsChildOf(Get.EndBone, sBone)) Get.GetGhostChain(); serializedObject.Update(); }
+
+ GUILayout.Space(4);
+ if (sBone) if (Get.EndBone) if (!IsChildOf(Get.EndBone, sBone)) EditorGUILayout.LabelField(new GUIContent(FGUI_Resources.Tex_Warning, "'End Bone' is not child of 'Start Bone'\nStart Bones is: '" + sBone.name + "'"), new GUILayoutOption[] { GUILayout.Height(20), GUILayout.Width(22) });
+
+ GUILayout.EndHorizontal();
+
+
+ // Offset parameter changed
+ if (preOff == makeOff)
+ {
+ if (makeOff)
+ {
+ Vector3 autoOffset = new Vector3(0f, 0f, 0.25f);
+
+ #region Auto offset
+
+ if (Get._TransformsGhostChain.Count > 0)
+ {
+ Transform t = Get._TransformsGhostChain[Get._TransformsGhostChain.Count - 1];
+ Transform p = Get._TransformsGhostChain[Get._TransformsGhostChain.Count - 1].parent;
+
+ if (p) // Reference from parent
+ autoOffset = t.InverseTransformVector(t.position - p.position);
+ else // Reference to child
+ if (t.childCount > 0)
+ {
+ Transform ch = Get._TransformsGhostChain[0].GetChild(0);
+ autoOffset = t.InverseTransformVector(ch.position - t.position);
+ }
+ }
+
+ #endregion
+
+ // Auto position
+ Get.EndBoneJointOffset = autoOffset;
+
+ if (SceneView.lastActiveSceneView)
+ {
+ if (Get._TransformsGhostChain.Count < 3)
+ {
+ SceneView.lastActiveSceneView.FrameSelected();
+ }
+ else
+ {
+#if UNITY_2019_1_OR_NEWER
+ Vector3 size = endB.position - endB.parent.position;
+ Vector3 origin = endB.position + size;
+ size = new Vector3(size.magnitude * 2f, size.magnitude * 2f, size.magnitude * 2f);
+ Bounds lastBone = new Bounds(origin, size);
+ SceneView.lastActiveSceneView.Frame(lastBone, false);
+#endif
+ }
+ }
+ }
+ else
+ Get.EndBoneJointOffset = Vector3.zero;
+ }
+
+ GUI.color = c;
+ }
+
+
+
+ //bool drawCoreAnimRules = true;
+ void Fold_DrawCoreAnimatorSetup()
+ {
+ //FGUI_Inspector.FoldHeaderStart(ref drawCoreAnimRules, "Core Animation Rules", FGUI_Resources.BGInBoxStyle, FGUI_Resources.TexMotionIcon, 24);
+
+ //if (drawCoreAnimRules)
+ {
+ GUILayout.Space(5);
+
+ EditorGUILayout.BeginHorizontal();
+ EditorGUIUtility.labelWidth = 0;
+ if (Application.isPlaying) GUI.enabled = false;
+ if (Get.UpdateRate > 0) { Get.DetachChildren = false; GUI.enabled = false; }
+ EditorGUILayout.PropertyField(sp_Detach); GUI.enabled = true;
+ if (Get.DetachChildren) EditorGUILayout.LabelField(new GUIContent(FGUI_Resources.Tex_Warning, "Use it only on not animated models!"), GUILayout.Width(16));
+
+ GUILayout.FlexibleSpace();
+ if (Application.isPlaying) GUI.enabled = false;
+ EditorGUILayout.PropertyField(sp_StartAfterTPose);
+ if (Application.isPlaying) GUI.enabled = true;
+ EditorGUILayout.EndHorizontal();
+
+ GUILayout.Space(2);
+ EditorGUILayout.BeginHorizontal();
+ EditorGUIUtility.labelWidth = 100;
+
+ EditorGUILayout.EndHorizontal();
+
+ GUILayout.Space(4f);
+ }
+
+ GUI.color = c;
+ }
+
+
+ bool drawAdditionalSetup = true;
+ private void Fold_DrawAdditionalSetup()
+ {
+ FGUI_Inspector.FoldHeaderStart(ref drawAdditionalSetup, Lang("Optimization And More"), FGUI_Resources.BGInBoxStyle, FGUI_Resources.TexAddIcon, 24);
+
+ if (drawAdditionalSetup)
+ {
+
+ // Delta type, update rate
+ GUILayout.Space(5);
+ EditorGUILayout.BeginHorizontal();
+
+ EditorGUIUtility.labelWidth = 88; EditorGUIUtility.fieldWidth = 0;
+ EditorGUILayout.PropertyField(sp_DeltaType);
+ EditorGUILayout.LabelField("", GUILayout.Width(4));
+ EditorGUIUtility.labelWidth = 40;
+ EditorGUIUtility.fieldWidth = Get.UpdateRate == 0 ? 10 : 30;
+ EditorGUILayout.PropertyField(sp_UpdateRate, new GUIContent("Rate", sp_UpdateRate.tooltip), GUILayout.Width(Get.UpdateRate == 0 ? 60 : 70));
+
+ GUI.color = new Color(1f, 1f, 1f, 0.75f);
+ EditorGUILayout.LabelField(Get.UpdateRate == 0 ? "Unlimited" : "FPS", GUILayout.Width(Get.UpdateRate == 0 ? 60 : 28));
+ GUI.color = c;
+
+ EditorGUILayout.EndHorizontal();
+ EditorGUIUtility.labelWidth = 0; EditorGUIUtility.fieldWidth = 0;
+
+ GUILayout.Space(5);
+
+ // interp, prewarm
+ EditorGUILayout.BeginHorizontal();
+
+ EditorGUIUtility.labelWidth = 135;
+ EditorGUIUtility.fieldWidth = 32;
+ if (Get.UpdateRate <= Mathf.Epsilon) GUI.enabled = false;
+ EditorGUILayout.PropertyField(sp_Optim);
+ if (Get.UpdateRate <= Mathf.Epsilon) GUI.enabled = true;
+
+ GUILayout.FlexibleSpace();
+
+ EditorGUIUtility.labelWidth = 68;
+ if (Application.isPlaying) GUI.enabled = false;
+ EditorGUILayout.PropertyField(sp_Prewarm);
+ if (Application.isPlaying) GUI.enabled = true;
+ GUI.color = c;
+
+ EditorGUILayout.EndHorizontal();
+ EditorGUIUtility.labelWidth = 0; EditorGUIUtility.fieldWidth = 0;
+
+
+ // Animate physics etc.
+ GUILayout.Space(7);
+
+ EditorGUILayout.BeginHorizontal();
+
+ if (animator) if (animator.updateMode == AnimatorUpdateMode.Fixed) GUI.color = new Color(0.6f, 1f, 0.6f, 1f);
+ EditorGUIUtility.labelWidth = 135;
+ EditorGUILayout.PropertyField(sp_AnimatePhysics);
+ GUILayout.FlexibleSpace();
+ EditorGUIUtility.labelWidth = 105;
+ GUI.color = c;
+ if (Application.isPlaying) GUI.enabled = false;
+ EditorGUILayout.PropertyField(sp_UpdateAsLast);
+ if (Application.isPlaying) GUI.enabled = true;
+ EditorGUILayout.EndHorizontal();
+ GUILayout.Space(7);
+
+ // Detach option
+ EditorGUILayout.BeginHorizontal();
+ EditorGUIUtility.labelWidth = 135;
+ if (Application.isPlaying) GUI.enabled = false;
+ if (Get.UpdateRate > 0 || Get.UseIK) { Get.DetachChildren = false; GUI.enabled = false; }
+ EditorGUILayout.PropertyField(sp_Detach); GUI.enabled = true;
+ if (Get.DetachChildren) { EditorGUILayout.LabelField(new GUIContent(FGUI_Resources.Tex_Warning, "Use it only on not animated models!"), GUILayout.Width(16)); GUILayout.Space(5); }
+ //GUILayout.FlexibleSpace();
+ //EditorGUIUtility.labelWidth = 65;
+ //EditorGUILayout.PropertyField(sp_Boost);
+ //EditorGUIUtility.labelWidth = 0;
+ EditorGUILayout.EndHorizontal();
+
+
+ GUILayout.Space(7);
+ El_DrawOptimizeWithMesh();
+
+ GUILayout.Space(4f);
+
+ }
+
+ GUILayout.Space(5f);
+ GUILayout.EndVertical();
+ GUILayout.Space(-5);
+ }
+
+
+
+ bool drawWaving = true;
+ void Fold_ModuleWaving()
+ {
+ FGUI_Inspector.FoldSwitchableHeaderStart(ref Get.UseWaving, sp_useWav, ref drawWaving, Lang("Auto Waving"), null, _TexWavingIcon, 22, sp_useWav.tooltip, LangBig());
+
+ if (drawWaving && Get.UseWaving)
+ {
+ GUILayout.Space(5f);
+ EditorGUILayout.PropertyField(sp_wavType);
+
+ if (Get.WavingType == TailAnimator2.FEWavingType.Advanced)
+ EditorGUILayout.PropertyField(sp_altWave);
+
+ GUILayout.Space(5f);
+ EditorGUILayout.PropertyField(sp_wavSp);
+ EditorGUILayout.PropertyField(sp_wavRa);
+
+ GUILayout.Space(5f);
+
+ bool altWeak = false;
+ if (Get.WavingType == TailAnimator2.FEWavingType.Advanced)
+ {
+ int zeros = 0; if (Get.WavingAxis.x == 0) zeros++; if (Get.WavingAxis.y == 0) zeros++; if (Get.WavingAxis.z == 0) zeros++;
+ if (zeros > 1) { altWeak = true; GUI.color = new Color(1f, .95f, 0.65f, 0.9f); }
+ }
+
+ EditorGUILayout.BeginHorizontal();
+ EditorGUILayout.PropertyField(sp_wavAx);
+
+ if (altWeak)
+ EditorGUILayout.LabelField(new GUIContent(FGUI_Resources.Tex_Warning, "Advanced waving should use more than one axis to get better results"), GUILayout.Width(16));
+
+ GUI.color = c;
+ EditorGUILayout.EndHorizontal();
+ GUILayout.Space(5f);
+
+ if (Get.WavingType != TailAnimator2.FEWavingType.Advanced) EditorGUILayout.PropertyField(sp_cosAd);
+
+ if (!Application.isPlaying)
+ {
+ EditorGUILayout.BeginHorizontal();
+ if (Get.FixedCycle == 0f) GUI.color = new Color(1f, 1f, 1f, 0.7f);
+ EditorGUILayout.PropertyField(sp_FixedCycle);
+ if (Get.FixedCycle == 0f)
+ { EditorGUILayout.LabelField("", GUILayout.Width(6)); EditorGUILayout.LabelField("(random)", GUILayout.Width(70)); }
+ EditorGUILayout.EndHorizontal();
+ }
+
+ GUI.color = c;
+
+ GUILayout.Space(4f);
+ }
+ }
+
+ bool drawCollisions = true;
+ bool drawColSetup = true;
+ void Fold_ModuleCollisions()
+ {
+ //FGUI_Inspector.FoldSwitchableHeaderStart(ref Get.UseCollision, ref drawCollisions, Lang("Use Collisions"), null, FGUI_Resources.Tex_Collider, 22, sp_useCollision.tooltip, LangBig());
+ GUILayout.BeginHorizontal();
+
+ if (Get.UseCollision)
+ {
+ if (GUILayout.Button(new GUIContent(" " + FGUI_Resources.GetFoldSimbol(drawCollisions, 10, "►") + " " + Lang("Collisions"), FGUI_Resources.Tex_Collider, sp_useCollision.tooltip), LangBig() ? FGUI_Resources.FoldStyleBig : FGUI_Resources.FoldStyle, GUILayout.Height(22))) drawCollisions = !drawCollisions;
+
+ EditorGUILayout.PropertyField(sp_useCollision, GUIContent.none, GUILayout.Width(16));
+ }
+ else
+ {
+ if (GUILayout.Button(new GUIContent(" " + Lang("Collisions"), FGUI_Resources.Tex_Collider, sp_useCollision.tooltip), LangBig() ? FGUI_Resources.FoldStyleBig : FGUI_Resources.FoldStyle, GUILayout.Height(22))) { Get.UseCollision = true; }
+ EditorGUILayout.PropertyField(sp_useCollision, GUIContent.none, GUILayout.Width(16));
+ }
+
+ GUILayout.EndHorizontal();
+
+ if (drawCollisions && Get.UseCollision)
+ {
+ GUILayout.Space(4f);
+
+ // 3D Collision Menu
+ if (Get.CollisionMode == TailAnimator2.ECollisionMode.m_3DCollision)
+ {
+ EditorGUILayout.BeginHorizontal();
+ if (Application.isPlaying) GUI.enabled = false;
+ EditorGUILayout.PropertyField(sp_CollisionSpace);
+ if (Application.isPlaying) GUI.enabled = true;
+
+ if (Get.CollisionSpace == TailAnimator2.ECollisionSpace.World_Slow)
+ {
+ GUILayout.Space(4);
+ EditorGUILayout.LabelField(new GUIContent(FGUI_Resources.Tex_Warning, "World Space Collisions are still in experimental stage"), GUILayout.Width(16));
+ }
+
+ EditorGUILayout.EndHorizontal();
+
+ EditorGUILayout.PropertyField(sp_collMode);
+
+ FGUI_Inspector.DrawUILine(new Color(0.5f, 0.5f, 0.5f, 0.3f), 2, 8);
+
+ if (Get.CollisionSpace == TailAnimator2.ECollisionSpace.World_Slow)
+ {
+
+ //EditorGUILayout.PropertyField(sp_PushMode);
+ EditorGUILayout.PropertyField(sp_CollisionSlippery);
+ if (Get.Slithery < 0.1f) GUI.color = new Color(1f, 1f, 1f, defaultValC.a / 2f);
+ EditorGUILayout.PropertyField(sp_ReflectCollision);
+ GUI.color = c;
+
+ if (Application.isPlaying) GUI.enabled = false; EditorGUI.BeginChangeCheck();
+ Get.CollidersType = EditorGUILayout.IntPopup("Detection Shape", Get.CollidersType, col_wrldColTypesNames, col_wrldColTypes); GUI.enabled = true;
+
+ if (EditorGUI.EndChangeCheck())
+ { GetSelectedTailAnimators(); for (int i = 0; i < lastSelected.Count; i++) { lastSelected[i].CollidersType = Get.CollidersType; new SerializedObject(lastSelected[i]).ApplyModifiedProperties(); } }
+
+
+
+ if (Application.isPlaying) GUI.enabled = true;
+
+ if (Application.isPlaying) GUI.enabled = false; EditorGUI.BeginChangeCheck();
+ Get.CollideWithOtherTails = EditorGUILayout.IntPopup("Tail Collision", Get.CollideWithOtherTails ? 1 : 0, col_colObjectsNames, col_colObjects) == 1; GUI.enabled = true;
+
+ if (EditorGUI.EndChangeCheck())
+ { GetSelectedTailAnimators(); for (int i = 0; i < lastSelected.Count; i++) { lastSelected[i].CollideWithOtherTails = Get.CollideWithOtherTails; new SerializedObject(lastSelected[i]).ApplyModifiedProperties(); } }
+
+
+
+
+ GUILayout.Space(4f);
+
+ if (!Application.isPlaying)
+ {
+ EditorGUILayout.BeginHorizontal();
+ EditorGUILayout.PropertyField(sp_colAddRigs, new GUIContent("Add Rigidbodies", sp_colAddRigs.tooltip));
+ if (Get.CollidersAddRigidbody)
+ {
+ EditorGUILayout.LabelField(" ", GUILayout.Width(1)); EditorGUIUtility.labelWidth = 40;
+ EditorGUILayout.PropertyField(sp_RigidbodyMass, new GUIContent("Mass", sp_RigidbodyMass.tooltip)); EditorGUIUtility.labelWidth = 0;
+ }
+ EditorGUILayout.EndHorizontal();
+
+ EditorGUILayout.BeginHorizontal();
+ EditorGUILayout.PropertyField(sp_colSameLayer, new GUIContent("Colliders Layer", sp_colSameLayer.tooltip));
+ if (Get.CollidersSameLayer)
+ {
+ EditorGUILayout.LabelField(" ", GUILayout.Width(2));
+ GUI.enabled = false; EditorGUILayout.LayerField(Get.gameObject.layer); GUI.enabled = true; EditorGUIUtility.labelWidth = 0;
+ }
+ else
+ {
+ EditorGUILayout.LabelField(" ", GUILayout.Width(2));
+ EditorGUILayout.PropertyField(sp_colCustomLayer, new GUIContent(""));
+ }
+ EditorGUILayout.EndHorizontal();
+ }
+
+
+ GUILayout.Space(4f);
+ EditorGUI.indentLevel++; EditorGUILayout.PropertyField(sp_colIgnored); EditorGUI.indentLevel--;
+
+ //if ( Physics.IgnoreCollision() )
+ //EditorGUILayout.HelpBox("With 'World Collision' tail should have assigned 'Layer' which is not collising with self in Project 'Settings/Physics'", MessageType.None);
+
+ GUILayout.Space(2f);
+
+ //FEditor_Styles.DrawUILine(new Color(0.5f, 0.5f, 0.5f, 0.3f), 2, 8);
+ }
+ else // Selective collision space
+ {
+ El_DrawSelectiveCollisionBox();
+ GUILayout.Space(5f);
+
+ El_DrawSlippery();
+
+ if (Get.Slithery < 0.1f) GUI.color = new Color(1f, 1f, 1f, defaultValC.a / 2f);
+ EditorGUILayout.PropertyField(sp_ReflectCollision);
+ GUI.color = c;
+
+ EditorGUILayout.PropertyField(sp_DetailedCollision);
+
+ // Collide with disabled
+ //if (!Get.DynamicWorldCollidersInclusion)
+ {
+ //if (Application.isPlaying) GUI.enabled = false;
+ EditorGUIUtility.labelWidth = 190;
+ EditorGUILayout.BeginHorizontal();
+ EditorGUILayout.PropertyField(sp_CollideWithDisabledColliders); EditorGUIUtility.labelWidth = 0;
+ if (Get.DynamicWorldCollidersInclusion) EditorGUILayout.LabelField(new GUIContent(FGUI_Resources.Tex_Info, "[Working with 'Dynamic Inclusion'] Disabled colliders will not be detected by trigger collider but when colliders will be disabled after being caught in trigger detection then this feature will work"), GUILayout.Width(16));
+ EditorGUILayout.EndHorizontal();
+ //if (Application.isPlaying) GUI.enabled = true;
+ }
+
+ GUILayout.Space(7f);
+
+
+ // Dynamic inclusion with trigger colliders method
+
+ //EditorGUIUtility.labelWidth = 216;
+ //if (Application.isPlaying) GUI.enabled = false;
+ //EditorGUILayout.PropertyField(sp_DynamicWorldCollidersInclusion);
+ //if (Application.isPlaying) GUI.enabled = true;
+ //EditorGUIUtility.labelWidth = 0;
+
+ EditorGUILayout.BeginVertical(FGUI_Resources.BGInBoxStyle);
+
+ EditorGUILayout.BeginHorizontal();
+ if (GUILayout.Button(new GUIContent(" " + FGUI_Resources.GetFoldSimbol(Get.DynamicWorldCollidersInclusion, 10, "►") + " " + Lang("Dynamic World Colliders Inclusion"), FGUI_Resources.Tex_MiniMotion), FGUI_Resources.HeaderStyle, GUILayout.Height(22))) Get.DynamicWorldCollidersInclusion = !Get.DynamicWorldCollidersInclusion;
+ GUILayout.FlexibleSpace();
+ EditorGUILayout.LabelField(new GUIContent(FGUI_Resources.Tex_Info, "Dynamic inclusion feature is under developement stage"), GUILayout.Width(16));
+ GUILayout.Space(5);
+ EditorGUILayout.PropertyField(sp_DynamicWorldCollidersInclusion, GUIContent.none, GUILayout.Width(16));
+ EditorGUILayout.EndHorizontal();
+
+ El_DrawCollidersDynamicInclusion();
+
+ EditorGUILayout.EndVertical();
+ }
+
+
+ // Colliders Setup
+
+ GUILayout.Space(5f);
+
+ EditorGUILayout.BeginVertical(FGUI_Resources.BGInBoxStyle);
+ if (GUILayout.Button(new GUIContent(" " + FGUI_Resources.GetFoldSimbol(drawColSetup, 10, "►") + " " + Lang("Colliders Setup"), FGUI_Resources.Tex_MiniGear), FGUI_Resources.FoldStyle, GUILayout.Height(22))) drawColSetup = !drawColSetup;
+
+ if (drawColSetup)
+ {
+ GUILayout.Space(3f);
+ EditorGUILayout.PropertyField(sp_colScaleMul, new GUIContent("Scale Multiplier", sp_colScaleMul.tooltip));
+ EditorGUILayout.PropertyField(sp_colScale, new GUIContent("Scale Curve", sp_colScale.tooltip));
+ EditorGUILayout.PropertyField(sp_colDiffFact, new GUIContent("Auto Curve", sp_colDiffFact.tooltip));
+ }
+ EditorGUILayout.EndVertical();
+
+ GUILayout.Space(3f);
+
+ }
+ else // 2D Collision Menu
+ {
+ EditorGUILayout.PropertyField(sp_collMode);
+ if (Get.CollisionMode == TailAnimator2.ECollisionMode.m_2DCollision) Get.CollisionSpace = TailAnimator2.ECollisionSpace.Selective_Fast;
+
+ FGUI_Inspector.DrawUILine(new Color(0.5f, 0.5f, 0.5f, 0.3f), 2, 8);
+
+ El_DrawSelectiveCollisionBox2D();
+ GUILayout.Space(5f);
+
+ El_DrawSlippery();
+
+ if (Get.Slithery < 0.1f) GUI.color = new Color(1f, 1f, 1f, defaultValC.a / 2f);
+ EditorGUILayout.PropertyField(sp_ReflectCollision);
+ GUI.color = c;
+
+ EditorGUILayout.PropertyField(sp_DetailedCollision);
+
+ EditorGUIUtility.labelWidth = 190;
+ EditorGUILayout.BeginHorizontal();
+ EditorGUILayout.PropertyField(sp_CollideWithDisabledColliders); EditorGUIUtility.labelWidth = 0;
+ if (Get.DynamicWorldCollidersInclusion) EditorGUILayout.LabelField(new GUIContent(FGUI_Resources.Tex_Info, "[Working with 'Dynamic Inclusion'] Disabled colliders will not be detected by trigger collider but when colliders will be disabled after being caught in trigger detection then this feature will work"), GUILayout.Width(16));
+ EditorGUILayout.EndHorizontal();
+
+ GUILayout.Space(7f);
+
+ // Dynamic inclusion with trigger colliders method
+ EditorGUILayout.BeginVertical(FGUI_Resources.BGInBoxStyle);
+
+ EditorGUILayout.BeginHorizontal();
+ if (GUILayout.Button(new GUIContent(" " + FGUI_Resources.GetFoldSimbol(Get.DynamicWorldCollidersInclusion, 10, "►") + " " + Lang("Dynamic World Colliders Inclusion"), FGUI_Resources.Tex_MiniMotion), FGUI_Resources.HeaderStyle, GUILayout.Height(22))) Get.DynamicWorldCollidersInclusion = !Get.DynamicWorldCollidersInclusion;
+ GUILayout.FlexibleSpace();
+ EditorGUILayout.LabelField(new GUIContent(FGUI_Resources.Tex_Info, "Dynamic inclusion feature is under developement stage"), GUILayout.Width(16));
+ GUILayout.Space(5);
+ EditorGUILayout.PropertyField(sp_DynamicWorldCollidersInclusion, GUIContent.none, GUILayout.Width(16));
+ EditorGUILayout.EndHorizontal();
+
+ El_DrawCollidersDynamicInclusion();
+
+ EditorGUILayout.EndVertical();
+
+ // Colliders Setup
+
+ GUILayout.Space(5f);
+
+ EditorGUILayout.BeginVertical(FGUI_Resources.BGInBoxStyle);
+ if (GUILayout.Button(new GUIContent(" " + FGUI_Resources.GetFoldSimbol(drawColSetup, 10, "►") + " " + Lang("Colliders Setup"), FGUI_Resources.Tex_MiniGear), FGUI_Resources.FoldStyle, GUILayout.Height(22))) drawColSetup = !drawColSetup;
+
+ if (drawColSetup)
+ {
+ GUILayout.Space(3f);
+ EditorGUILayout.PropertyField(sp_colScaleMul, new GUIContent("Scale Multiplier", sp_colScaleMul.tooltip));
+ EditorGUILayout.PropertyField(sp_colScale, new GUIContent("Scale Curve", sp_colScale.tooltip));
+ EditorGUILayout.PropertyField(sp_colDiffFact, new GUIContent("Auto Curve", sp_colDiffFact.tooltip));
+ }
+ EditorGUILayout.EndVertical();
+
+ GUILayout.Space(3f);
+
+ EditorGUI.indentLevel++; EditorGUILayout.PropertyField(sp_colIgnored2D); EditorGUI.indentLevel--;
+
+ }
+
+
+ }
+ }
+
+
+ #region GUI Helpers
+
+ int[] col_wrldColTypes = new int[2] { 0, 1 };
+ string[] col_wrldColTypesNames = new string[2] { "Spheres", "Capsules" };
+ int[] col_colObjects = new int[2] { 0, 1 };
+ string[] col_colObjectsNames = new string[2] { "Exclude other tails", "Collide with other tails" };
+
+ #endregion
+
+
+ bool drawPartialBlend = true;
+ void Fold_ModulePartialBlend()
+ {
+ FGUI_Inspector.FoldSwitchableHeaderStart(ref Get.UsePartialBlend, sp_usePartialBlend, ref drawPartialBlend, Lang("Partial Blend"), null, _TexPartialBlendIcon, 22, sp_useCollision.tooltip, LangBig());
+
+ if (drawPartialBlend && Get.UsePartialBlend)
+ {
+
+ float sum = 0f;
+
+ if (Get._TransformsGhostChain.Count > 0)
+ {
+ GUILayout.Space(6f);
+ EditorGUILayout.HelpBox("Rectangles identifies tail bones, white color means it will be animated just with keyframe animation", MessageType.None);
+ GUILayout.Space(5f);
+
+ float height = 16f;
+ Rect rect = GUILayoutUtility.GetRect(GUILayoutUtility.GetLastRect().width, height, "TextField");
+
+ float step = rect.width / (float)Get._TransformsGhostChain.Count;
+
+ for (int i = 0; i < Get._TransformsGhostChain.Count; i++)
+ {
+ float y = 1 - Mathf.InverseLerp(Get._TransformsGhostChain.Count / 2, Get._TransformsGhostChain.Count + 1, i);
+
+ float blendValue = Get.GetValueFromCurve(i, Get.BlendCurve);
+ sum += blendValue;
+
+ EditorGUI.DrawRect(new Rect(rect.x + 2 + i * step, rect.y + (1 - y) * ((height - 1) / 2), step - 2f, height * y), new Color(0.45f, 0.45f, 0.45f, (1f - blendValue) * 0.5f));
+ EditorGUI.DrawRect(new Rect(rect.x + 2 + i * step, rect.y + (1 - y) * ((height - 1) / 2), step - 2f, height * y), new Color(0.2f, 0.5f, 0.9f, (blendValue) * 0.4f));
+ }
+
+ GUI.color = c;
+ }
+
+ GUILayout.Space(6f);
+
+ if (sum == (float)Get._TransformsGhostChain.Count) EditorGUILayout.LabelField("(Default tail animator motion)", FGUI_Resources.HeaderStyle);
+ else if (sum == 0f) EditorGUILayout.LabelField("(No tail animator motion)", FGUI_Resources.HeaderStyle);
+ else EditorGUILayout.LabelField("(White rects - animated with keyframe animation)", FGUI_Resources.HeaderStyle);
+ GUILayout.Space(4f);
+
+ EditorGUIUtility.labelWidth = 130;
+ EditorGUILayout.BeginHorizontal();
+ EditorGUI.BeginChangeCheck();
+ EditorGUILayout.PropertyField(sp_BlendCurve, new GUIContent("Partial Blend Curve", sp_BlendCurve.tooltip), GUILayout.Height(26));
+
+ if (EditorGUI.EndChangeCheck())
+ {
+ Get.BlendCurve = Get.ClampCurve(Get.BlendCurve, 0f, 1f, 0f, 1f);
+ serializedObject.ApplyModifiedProperties();
+ }
+
+ EditorGUILayout.LabelField("", GUILayout.Width(4));
+ if (GUILayout.Button(new GUIContent(FGUI_Resources.Tex_Refresh), FGUI_Resources.ButtonStyle, new GUILayoutOption[2] { GUILayout.Width(26), GUILayout.Height(22) })) { Get.BlendCurve = AnimationCurve.EaseInOut(0f, .95f, 1f, .45f); serializedObject.ApplyModifiedProperties(); /*UnityEditorInternal.InternalEditorUtility.RepaintAllViews();*/ }
+ EditorGUILayout.EndHorizontal();
+ EditorGUIUtility.labelWidth = 0;
+
+ GUILayout.Space(3f);
+ }
+
+ GUILayout.Space(3f);
+
+ }
+
+
+ bool drawIK = true;
+ void Fold_ModuleIK()
+ {
+ FGUI_Inspector.FoldSwitchableHeaderStart(ref Get.UseIK, sp_UseIK, ref drawIK, Lang("Inverse Kinematics"), null, _TexIKIcon, 22, "Using CCD IK for tail chain to controll end position of tail limb", LangBig());
+
+ if (drawIK && Get.UseIK)
+ {
+ GUILayout.Space(3f);
+
+ #region IK Target field
+
+ Transform lastBoneKnown = null;
+ if (Get._TransformsGhostChain != null)
+ if (Get._TransformsGhostChain.Count > 0)
+ lastBoneKnown = Get._TransformsGhostChain[Get._TransformsGhostChain.Count - 1];
+
+ if (Get.IKTarget == null && lastBoneKnown)
+ {
+ GUI.color = new Color(1f, 1f, 1f, 0.3f);
+ EditorGUI.BeginChangeCheck();
+ Get.IKTarget = (Transform)EditorGUILayout.ObjectField(new GUIContent(sp_IKTarget.displayName, sp_IKTarget.tooltip), lastBoneKnown, typeof(Transform), true);
+ if (EditorGUI.EndChangeCheck()) { serializedObject.ApplyModifiedProperties(); }
+ GUI.color = c;
+ }
+ else
+ EditorGUILayout.PropertyField(sp_IKTarget);
+
+ var spc = sp_IKTarget.Copy();
+ spc.NextVisible(false);
+ EditorGUILayout.PropertyField(spc);
+
+ GUILayout.Space(3f);
+
+ #endregion
+
+ EditorGUILayout.PropertyField(sp_IKBlend);
+ EditorGUILayout.PropertyField(sp_IKAnimatorBlend);
+
+ GUILayout.Space(7f);
+ EditorGUILayout.PropertyField(sp_IKReactionQuality);
+ EditorGUILayout.PropertyField(sp_IKSmoothing);
+
+ EditorGUILayout.BeginHorizontal();
+ EditorGUILayout.PropertyField(sp_IKContinous);
+ spc = sp_IKContinous.Copy();
+ spc.Next(false);
+ GUILayout.FlexibleSpace();
+ EditorGUIUtility.labelWidth = 110;
+ EditorGUILayout.PropertyField(spc);
+ EditorGUIUtility.labelWidth = 0;
+ EditorGUILayout.EndHorizontal();
+
+
+ if (sp_IKMaxStretching.floatValue > 1f)
+ sp_IKMaxStretching.floatValue = EditorGUILayout.FloatField(new GUIContent(sp_IKMaxStretching.displayName, sp_IKMaxStretching.tooltip), sp_IKMaxStretching.floatValue);
+ else
+ EditorGUILayout.PropertyField(sp_IKMaxStretching);
+
+ if (Get._TransformsGhostChain.Count > 9)
+ {
+ GUILayout.Space(7f);
+ EditorGUILayout.HelpBox("When your tail chain have many bones you need to focus on weights and rotation limits to tweak desired behaviour", MessageType.None);
+ GUILayout.Space(-3f);
+ }
+
+ GUILayout.Space(7f);
+ EditorGUILayout.BeginHorizontal();
+ EditorGUIUtility.fieldWidth = 22; EditorGUILayout.PropertyField(sp_IKAutoWeights);
+ GUILayout.Space(5f); EditorGUIUtility.fieldWidth = 0;
+ if (Get.IKAutoWeights) EditorGUILayout.PropertyField(sp_IKBaseReactionWeight, new GUIContent(""));
+ else
+ {
+ EditorGUIUtility.labelWidth = 88;
+ EditorGUILayout.PropertyField(sp_IKweightCurve, new GUIContent("Weight Curve", "Reaction speed weight curve")); EditorGUIUtility.labelWidth = 0;
+ }
+
+ EditorGUILayout.EndHorizontal();
+
+
+ GUILayout.Space(7f);
+
+ EditorGUILayout.BeginHorizontal();
+ EditorGUIUtility.fieldWidth = 22; EditorGUILayout.PropertyField(sp_IKAutoAngleLimits);
+ GUILayout.Space(5f); EditorGUIUtility.fieldWidth = 0;
+ if (Get.IKAutoAngleLimits) EditorGUILayout.PropertyField(sp_IKAutoAngleLimit, new GUIContent(""));
+ EditorGUILayout.EndHorizontal();
+
+
+ if (!Get.IKAutoAngleLimits)
+ {
+ if (Get.IKLimitSettings.Count != Get._TransformsGhostChain.Count)
+ Get.IK_RefreshLimitSettingsContainer();
+
+ FGUI_Inspector.DrawUILine(new Color(1f, 1f, 1f, 0.15f), 1, 7);
+
+ for (int i = 0; i < Get.IKLimitSettings.Count; i++)
+ {
+ EditorGUILayout.ObjectField(Get._TransformsGhostChain[i], typeof(Transform), true);
+
+ if (!Get.IKAutoAngleLimits) // Angle limit fields
+ {
+ EditorGUIUtility.labelWidth = 70;
+ if (Get.IKLimitSettings == null) Get.IK_RefreshLimitSettingsContainer();
+ EditorGUILayout.BeginHorizontal();
+ EditorGUILayout.PropertyField(sp_IKLimitSettings.GetArrayElementAtIndex(i).FindPropertyRelative("AngleLimit"));
+ GUILayout.Space(5f);
+ EditorGUILayout.PropertyField(sp_IKLimitSettings.GetArrayElementAtIndex(i).FindPropertyRelative("TwistAngleLimit"));
+ EditorGUILayout.EndHorizontal();
+ FGUI_Inspector.DrawUILine(new Color(1f, 1f, 1f, 0.15f), 1, 7);
+ }
+
+ EditorGUIUtility.labelWidth = 0;
+ }
+
+ }
+
+
+ GUILayout.Space(5f);
+
+
+ FGUI_Inspector.FoldSwitchableHeaderStart(ref Get.IKSelectiveChain, ref drawSelIKChain, "Selective IK Bones Chain", FGUI_Resources.BGBoxStyle, null);
+ if (Get.IKSelectiveChain && drawSelIKChain)
+ {
+ if (Get.IKLimitSettings.Count != Get._TransformsGhostChain.Count)
+ {
+ Get.IK_RefreshLimitSettingsContainer();
+ }
+
+ EditorGUI.BeginChangeCheck();
+
+ Color trCol = new Color(1f, 1f, 1f, 0.5f);
+ if (Application.isPlaying) GUI.enabled = false;
+ for (int l = 0; l < Get.IKLimitSettings.Count; l++)
+ {
+ GUILayout.BeginHorizontal();
+ Get.IKLimitSettings[l].UseInChain = EditorGUILayout.Toggle(Get.IKLimitSettings[l].UseInChain, GUILayout.Width(22));
+ GUI.color = trCol;
+ EditorGUILayout.ObjectField(Get._TransformsGhostChain[l], typeof(Transform), true);
+ GUI.color = Color.white;
+ GUILayout.EndHorizontal();
+ }
+ GUI.enabled = true;
+
+ if (EditorGUI.EndChangeCheck()) EditorUtility.SetDirty(Get);
+ }
+
+ GUILayout.EndVertical();
+ GUILayout.Space(3f);
+
+ GUILayout.Space(5f);
+ }
+ }
+
+ bool drawSelIKChain = false;
+ bool drawDefl = false;
+ void Fold_ModuleDeflection()
+ {
+ EditorGUILayout.BeginHorizontal();
+ FGUI_Inspector.FoldHeaderStart(ref drawDefl, new GUIContent(Lang("Deflection"), "Making collision (or also swing) deflection smoothed creating effect of stiffness connection over all tail segments"), FGUI_Resources.FoldStyle, null, _TexDeflIcon, 22); //"Adding deflection translation when tail have big flexion", LangBig()
+
+ if (Get.Deflection > 0.05f)
+ if (Get.MaxStretching > 0.1f)
+ {
+ EditorGUILayout.LabelField("Max Stretching (Tweaking Tab) should be set to zero when using deflection and 'Slithery' about zero", FGUI_Resources.BGInBoxStyle);
+ //EditorGUILayout.HelpBox("Max Stretching (Tweaking Tab) should be set to zero when using deflection and 'Slithery' about zero", MessageType.None);
+ GUILayout.Space(3f);
+ }
+
+ GUILayout.FlexibleSpace();
+ EditorGUILayout.LabelField(new GUIContent(FGUI_Resources.Tex_Info, "Deflection feature is under developement stage"), GUILayout.Width(16));
+ EditorGUILayout.EndHorizontal();
+
+ if (drawDefl)
+ {
+ GUILayout.Space(3f);
+ EditorGUILayout.PropertyField(sp_Deflection);
+ GUILayout.Space(2f);
+ EditorGUILayout.PropertyField(sp_DeflectOnlyCollisions);
+ GUILayout.Space(5f);
+ EditorGUILayout.PropertyField(sp_DeflectionStartAngle);
+ GUILayout.Space(2f);
+ EditorGUILayout.PropertyField(sp_DeflectionSmooth);
+ GUILayout.Space(4f);
+ EditorGUILayout.PropertyField(sp_DeflectionFalloff);
+ GUILayout.Space(5f);
+ }
+ }
+
+ bool drawPhysEffectors = false;
+ bool drawWindSettings = true;
+ void Fold_ModulePhysEffectors()
+ {
+ FGUI_Inspector.FoldHeaderStart(ref drawPhysEffectors, new GUIContent(Lang("Physical Effectors"), "Simulating physical effects like gravity, wind"), FGUI_Resources.FoldStyle, null, _TexWindIcon, 22); //"Adding deflection translation when tail have big flexion", LangBig()
+
+
+ if (drawPhysEffectors)
+ {
+
+ // Gravity
+ GUILayout.Space(5f);
+ if (FEngineering.VIsZero(Get.Gravity) && !Get.UseGravityCurve) GUI.color = defaultValC; else GUI.color = c;
+
+ EditorGUILayout.BeginHorizontal();
+ EditorGUILayout.PropertyField(sp_gravity);
+
+ if (Get.UseGravityCurve)
+ {
+ EditorGUILayout.LabelField(new GUIContent("*", "Gravity value weight for tail segments multiplied by curve"), GUILayout.Width(9));
+ EditorGUILayout.PropertyField(sp_GravityCurve, new GUIContent("", sp_GravityCurve.tooltip), GUILayout.MaxWidth(32));
+ }
+ else
+ GUILayout.Space(4f);
+
+ EditorGUI.BeginChangeCheck();
+ SwitchButton(ref Get.UseGravityCurve, "Spread gravity weight over tail segments", curveIcon);
+ if (EditorGUI.EndChangeCheck()) { GetSelectedTailAnimators(); for (int i = 0; i < lastSelected.Count; i++) { lastSelected[i].UseGravityCurve = Get.UseGravityCurve; new SerializedObject(lastSelected[i]).ApplyModifiedProperties(); } }
+ EditorGUILayout.EndHorizontal();
+
+
+ // Wind Effector
+ GUILayout.Space(5f);
+
+ if (Get.UseWind) // When wind enabled foldable
+ {
+ EditorGUILayout.BeginHorizontal();
+ if (GUILayout.Button(new GUIContent(" " + FGUI_Resources.GetFoldSimbol(drawWindSettings, 10, "►") + " " + Lang("Wind"), _windIcon), FGUI_Resources.HeaderStyle, GUILayout.Height(22))) drawWindSettings = !drawWindSettings;
+ GUILayout.Space(8);
+
+ if (GUILayout.Button("Use TailAnimator Wind component for more settings", FGUI_Resources.BGInBoxStyle))
+ {
+ if (TailAnimatorWind.Instance != null) Selection.activeObject = TailAnimatorWind.Instance.gameObject;
+ }
+
+ GUILayout.FlexibleSpace();
+ EditorGUILayout.LabelField(new GUIContent(FGUI_Resources.Tex_Info, "Wind feature is under developement stage"), GUILayout.Width(16));
+ GUILayout.Space(5);
+ EditorGUILayout.PropertyField(sp_UseWind, GUIContent.none, GUILayout.Width(16));
+ EditorGUILayout.EndHorizontal();
+ }
+ else
+ {
+ EditorGUILayout.BeginHorizontal();
+ if (GUILayout.Button(new GUIContent(" " + Lang("Wind"), _windIcon), FGUI_Resources.HeaderStyle, GUILayout.Height(22))) { Get.UseWind = true; }
+ GUILayout.FlexibleSpace();
+ EditorGUILayout.PropertyField(sp_UseWind, GUIContent.none, GUILayout.Width(16));
+ EditorGUILayout.EndHorizontal();
+ }
+
+ if (Get.UseWind && drawWindSettings)
+ {
+ GUILayout.Space(5f);
+ EditorGUILayout.PropertyField(sp_WindEffectPower, new GUIContent("Effect Power", sp_WindEffectPower.tooltip));
+ GUILayout.Space(2f);
+ EditorGUILayout.PropertyField(sp_WindTurbulencePower, new GUIContent("Turbulence Power", sp_WindTurbulencePower.tooltip));
+ GUILayout.Space(5f);
+ EditorGUILayout.PropertyField(sp_WindWorldNoisePower, new GUIContent("World Noise Power", sp_WindWorldNoisePower.tooltip));
+
+ if (Application.isPlaying == false)
+ {
+ if (TailAnimatorWind.Instance == null)
+ {
+ if (GUILayout.Button("Add TailAnimatorWind to the Scene"))
+ {
+#if UNITY_2023_1_OR_NEWER
+ TailAnimatorWind wind = FindFirstObjectByType();
+#else
+ TailAnimatorWind wind = FindObjectOfType();
+#endif
+ if (wind)
+ {
+ UnityEngine.Debug.Log("Tail Animator Wind already on scene!");
+ wind.OnValidate();
+ }
+ else
+ {
+ wind = new GameObject("Tail Animator Wind").AddComponent();
+ wind.transform.SetAsFirstSibling();
+ wind.OnValidate();
+ }
+
+ }
+ }
+ }
+ }
+
+ GUILayout.Space(1f);
+ //EditorGUILayout.EndVertical();
+
+ }
+ }
+
+
+
+ bool drawMaxDistance = true;
+ void Fold_ModuleMaxDistance()
+ {
+ FGUI_Inspector.FoldSwitchableHeaderStart(ref Get.UseMaxDistance, sp_UseMaxDistance, ref drawMaxDistance, Lang("Disable when Far"), null, FGUI_Resources.Tex_Distance, 22, "Measuring distance to camera or other object and smoothly disabling tail animator if tail object is far", LangBig());
+ if (drawMaxDistance && Get.UseMaxDistance)
+ {
+ GUILayout.Space(6f);
+
+ if (Get.DistanceFrom == null)
+ {
+ Transform t = null;
+ if (Camera.main) t = Camera.main.transform;
+ else
+ {
+#if UNITY_2023_1_OR_NEWER
+ Camera c = FindFirstObjectByType();
+#else
+ Camera c = FindObjectOfType();
+#endif
+ if (c) t = c.transform;
+ }
+
+ if (!Application.isPlaying) Get._distanceFrom_Auto = t;
+
+ EditorGUI.BeginChangeCheck();
+ GUI.color = new Color(1f, 1f, 1f, 0.5f);
+ Transform tt = (Transform)EditorGUILayout.ObjectField(new GUIContent(sp_DistanceFrom.displayName + " (Auto)", sp_DistanceFrom.tooltip), t, typeof(Transform), true);
+ GUI.color = c;
+ if (EditorGUI.EndChangeCheck()) { Get.DistanceFrom = tt; serializedObject.ApplyModifiedProperties(); }
+ }
+ else // Distance from defined
+ {
+ EditorGUILayout.PropertyField(sp_DistanceFrom);
+ }
+
+ GUILayout.Space(4f);
+ EditorGUILayout.PropertyField(sp_DistanceMeasurePoint);
+ GUILayout.Space(2f);
+ EditorGUILayout.PropertyField(sp_MaximumDistance);
+ GUILayout.Space(5f);
+ EditorGUILayout.PropertyField(sp_MaxOutDistanceFactor);
+ GUILayout.Space(2f);
+ EditorGUILayout.PropertyField(sp_DistanceWithoutY);
+ GUILayout.Space(2f);
+ EditorGUILayout.PropertyField(sp_FadeDuration);
+
+ GUILayout.Space(5f);
+ }
+ }
+
+ bool drawSmoothing = true;
+ void Fold_TweakingSmoothing()
+ {
+ if (Get.Slithery < 0.5f)
+ if (Get.ReactionSpeed < 0.95f)
+ if (Get.Springiness > 0.2f)
+ drawSmoothing = true;
+
+ FGUI_Inspector.FoldHeaderStart(ref drawSmoothing, Lang("Smoothing Motion"), FGUI_Resources.BGInBoxStyle, FGUI_Resources.TexSmallOptimizeIcon, 21);
+
+ if (drawSmoothing)
+ {
+ GUI.color = new Color(1f, 1f, 1f, 0.7f);
+ EditorGUIUtility.labelWidth = 125;
+ EditorGUILayout.BeginHorizontal();
+ if (Get.UsePosSpeedCurve)
+ GUILayout.Label(" " + Lang("Tail Start"), smallStyle);
+ else
+ GUILayout.Label(" " + Lang("Slow"), smallStyle);
+
+ GUILayout.FlexibleSpace();
+
+ if (Get.UsePosSpeedCurve)
+ GUILayout.Label(Lang("Tail End") + " ", smallStyle);
+ else
+ GUILayout.Label(Lang("Rapid") + " ", smallStyle);
+
+ EditorGUILayout.EndHorizontal();
+ GUI.color = c;
+ if (Get.UsePosSpeedCurve) GUILayout.Space(-0f); else GUILayout.Space(-2f);
+
+
+ // Position Speed
+ if (Get.UsePosSpeedCurve)
+ {
+ EditorGUILayout.BeginHorizontal();
+ EditorGUILayout.PropertyField(sp_PosCurve, new GUIContent(sp_ReactSpeed.displayName, sp_ReactSpeed.tooltip), GUILayout.MaxHeight(18)); GUILayout.Space(3f);
+ SwitchButton(ref Get.UsePosSpeedCurve, "Spread position speed parameter weight over tail segments", curveIcon);
+ EditorGUILayout.EndHorizontal();
+ }
+ else
+ {
+ if (Get.ReactionSpeed >= 1f) GUI.color = defaultValC; else GUI.color = c;
+
+ EditorGUILayout.BeginHorizontal();
+ if (Get.Slithery < 0.5f)
+ if (Get.ReactionSpeed < 0.95f)
+ if (Get.Springiness > 0.2f)
+ {
+ GUI.color = new Color(1f, 1f, 0.6f, 1f);
+ EditorGUILayout.LabelField(new GUIContent(FGUI_Resources.Tex_Info, "To make springiness noticeable then reaction speed should be higher!"), GUILayout.Width(16));
+ }
+
+ EditorGUIUtility.fieldWidth = 38;
+ EditorGUILayout.PropertyField(sp_ReactSpeed); EditorGUIUtility.fieldWidth = 0;
+ SwitchButton(ref Get.UsePosSpeedCurve, "Spread position speed parameter weight over tail segments", curveIcon);
+ EditorGUILayout.EndHorizontal();
+ }
+
+ GUI.color = c;
+
+ if (Get.Slithery < 0.4f)
+ {
+ GUILayout.Space(5f);
+ EditorGUILayout.HelpBox("Rotation relevancy works only with Slithery blend", MessageType.None);
+ }
+
+ // Rotation Speed
+ if (Get.UseRotSpeedCurve)
+ {
+ EditorGUILayout.BeginHorizontal();
+ EditorGUILayout.PropertyField(sp_RotCurve, new GUIContent(sp_RotRelev.displayName, sp_RotRelev.tooltip), GUILayout.MaxHeight(18)); GUILayout.Space(3f);
+ SwitchButton(ref Get.UseRotSpeedCurve, "Spread rotation speed parameter weight over tail segments", curveIcon);
+ EditorGUILayout.EndHorizontal();
+ }
+ else
+ {
+ if (Get.RotationRelevancy >= 1f) GUI.color = defaultValC; else GUI.color = c;
+ EditorGUILayout.BeginHorizontal(); EditorGUIUtility.fieldWidth = 38;
+ EditorGUILayout.PropertyField(sp_RotRelev); EditorGUIUtility.fieldWidth = 0;
+ SwitchButton(ref Get.UseRotSpeedCurve, "Spread rotation speed parameter weight over tail segments", curveIcon);
+ EditorGUILayout.EndHorizontal();
+ }
+
+ EditorGUIUtility.labelWidth = 0;
+ GUI.color = c;
+ GUILayout.Space(5f);
+ EditorGUILayout.PropertyField(sp_SmoothingStyle);
+ //var spc = sp_SmoothingStyle.Copy();
+ //spc.Next(false);
+ //EditorGUILayout.PropertyField(spc);
+
+ //GUILayout.Space(4f);
+ //if (Get.ClassicSlithery == 0f) GUI.color = defaultValC;
+ //EditorGUILayout.PropertyField(sp_ClassicSlithery); GUI.color = c;
+
+ GUILayout.Space(4f);
+ }
+
+ GUILayout.Space(2f);
+ GUILayout.EndVertical();
+
+ }
+
+
+ #region GUI Helpers
+
+ GUIContent[] axis2D_Names = new GUIContent[4] { new GUIContent("3D Movement (no limit)"), new GUIContent("X is Depth"), new GUIContent("Y is Depth"), new GUIContent("Z is Depth") };
+ int[] axis2D_int = new int[4] { 0, 1, 2, 3 };
+
+ #endregion
+
+
+ bool drawTweakAdditional = false;
+ void Fold_TweakingAdditional()
+ {
+ EditorGUILayout.BeginVertical(FGUI_Resources.BGInBoxLightStyle);
+
+ EditorGUILayout.BeginHorizontal();
+ FGUI_Inspector.FoldHeaderStart(ref drawTweakAdditional, Lang("Additional Parameters"), null, FGUI_Resources.TexMotionIcon, 21);
+ GUILayout.FlexibleSpace();
+
+ if ((Get._TransformsGhostChain.Count > 0 && Get._TransformsGhostChain.Count < 22))
+ EditorGUILayout.LabelField(new GUIContent(FGUI_Resources.Tex_Info, "If your chain is not bending enough you can try increasing 'Unify Bendiness' down below in this tab and then lowering 'Curling' to adjust it more"), GUILayout.Width(16));
+ EditorGUILayout.EndHorizontal();
+
+ if (drawTweakAdditional)
+ {
+ GUI.color = c;
+ GUILayout.Space(5f);
+
+ // Sustain
+ if (Get.Sustain == 0f) GUI.color = defaultValC;
+ else
+ {
+ if (Get.Sustain > 0.1f)
+ if (Get.Springiness > 0.45f)
+ EditorGUILayout.HelpBox("When you set 'Spriginess' high then 'Sustain' can react too much!", MessageType.None);
+ else
+ EditorGUILayout.HelpBox("Set 'Spriginess' around 0.25 and 0.45 to notice sustain effect", MessageType.None);
+ }
+
+ EditorGUILayout.PropertyField(sp_Sustain); GUI.color = c;
+ GUILayout.Space(3f);
+ EditorGUILayout.PropertyField(sp_Unify);
+ GUILayout.Space(3f);
+ EditorGUILayout.PropertyField(sp_Boost, new GUIContent("Tangle (Experimental)", sp_Boost.tooltip));
+ GUILayout.Space(3f);
+ GUIContent pname = new GUIContent("Limit Axis for 2D", "If tail movement should not move in depth you can use this parameter");
+ EditorGUI.BeginChangeCheck();
+ Get.Axis2D = EditorGUILayout.IntPopup(pname, Get.Axis2D, axis2D_Names, axis2D_int);
+ if (EditorGUI.EndChangeCheck()) { GetSelectedTailAnimators(); for (int i = 0; i < lastSelected.Count; i++) { lastSelected[i].Axis2D = Get.Axis2D; new SerializedObject(lastSelected[i]).ApplyModifiedProperties(); } }
+
+ GUILayout.Space(3);
+ EditorGUILayout.BeginHorizontal();
+ EditorGUILayout.PropertyField(sp_AnimateRoll);
+
+ if (Get.AnimateRoll)
+ {
+ float val = EditorGUILayout.Slider(GUIContent.none, 1f - Get.RotationRelevancy, 0f, 1f);
+ Get.RotationRelevancy = 1f - val;
+ }
+
+ EditorGUILayout.EndHorizontal();
+
+ if (Get.AnimateRoll)
+ if (Get.RotationRelevancy > 0.5f) EditorGUILayout.HelpBox("Set Roll higher than 0.6 to see results more clearly", MessageType.None);
+
+
+ GUILayout.Space(2f);
+ }
+
+ //EditorGUILayout.BeginVertical();
+ GUILayout.Space(2f);
+ GUILayout.EndVertical();
+
+ }
+
+
+ void Fold_TweakingBending()
+ {
+ EditorGUILayout.BeginVertical(FGUI_Resources.BGInBoxBlankStyle);
+
+ //if (drawBending)
+ {
+ EditorGUIUtility.labelWidth = 115;
+ El_DrawSlithery();
+ GUILayout.Space(2f);
+ El_DrawCurling();
+ GUILayout.Space(2f);
+ El_DrawSpringiness();
+ GUILayout.Space(5f);
+ //EditorGUILayout.PropertyField(sp_Deflection);
+ //GUILayout.Space(5f);
+ EditorGUIUtility.labelWidth = 0;
+
+ EditorGUILayout.EndVertical();
+ }
+
+ GUILayout.Space(2f);
+ GUILayout.EndVertical();
+ }
+
+
+ bool drawLimiting = true;
+ void Fold_TweakingLimiting()
+ {
+ FGUI_Inspector.FoldHeaderStart(ref drawLimiting, Lang("Limiting Motion"), FGUI_Resources.BGInBoxLightStyle, FGUI_Resources.Tex_Knob, 21);
+
+ if (drawLimiting)
+ {
+ GUILayout.Space(4f);
+ if (Get.MaxStretching >= 1f) GUI.color = defaultValC;
+ EditorGUILayout.PropertyField(sp_MaxStretching); GUI.color = c;
+ GUILayout.Space(5f);
+ El_DrawLimitingAngle();
+ GUILayout.Space(6f);
+ if (Get.MotionInfluence == 1f) GUI.color = defaultValC;
+ EditorGUILayout.PropertyField(sp_MotionInfluence); GUI.color = c;
+ if (Get.MotionInfluence != 1f) { var spp = sp_MotionInfluence.Copy(); spp.NextVisible(false); EditorGUILayout.PropertyField(spp); }
+ GUILayout.Space(1f);
+ }
+
+ GUILayout.Space(4f);
+ GUILayout.EndVertical();
+ }
+ }
+}
diff --git a/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/TailAnimator.Editor.Foldouts.cs.meta b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/TailAnimator.Editor.Foldouts.cs.meta
new file mode 100644
index 000000000..b7378b914
--- /dev/null
+++ b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/TailAnimator.Editor.Foldouts.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 25475a529738d084d8d042e096cb2fe1
+timeCreated: 1532131583
+licenseType: Store
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/TailAnimator.Editor.Helpers.cs b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/TailAnimator.Editor.Helpers.cs
new file mode 100644
index 000000000..4924e7beb
--- /dev/null
+++ b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/TailAnimator.Editor.Helpers.cs
@@ -0,0 +1,156 @@
+using FIMSpace.FEditor;
+using System.Collections.Generic;
+using UnityEditor;
+using UnityEngine;
+
+namespace FIMSpace.FTail
+{
+ public partial class FTailAnimator2_Editor
+ {
+ // RESOURCES ----------------------------------------
+
+ public static Texture2D _TexTailAnimIcon { get { if (__texTailAnimIcon != null) return __texTailAnimIcon; __texTailAnimIcon = Resources.Load("Tail Animator/Tail Animator Icon Small"); return __texTailAnimIcon; } }
+ private static Texture2D __texTailAnimIcon = null;
+ public static Texture2D _TexWavingIcon { get { if (__texWaving != null) return __texWaving; __texWaving = Resources.Load("Tail Animator/WavingIcon"); return __texWaving; } }
+ private static Texture2D __texWaving = null;
+ public static Texture2D _TexPartialBlendIcon { get { if (__texPartBlendIcon != null) return __texPartBlendIcon; __texPartBlendIcon = Resources.Load("Tail Animator/PartialBlendIcon"); return __texPartBlendIcon; } }
+ private static Texture2D __texPartBlendIcon = null;
+ public static Texture2D _TexIKIcon { get { if (__texIKIcon != null) return __texIKIcon; __texIKIcon = Resources.Load("Tail Animator/IKIcon"); return __texIKIcon; } }
+ private static Texture2D __texIKIcon = null;
+ public static Texture2D _TexDeflIcon { get { if (__texDeflIcon != null) return __texDeflIcon; __texDeflIcon = Resources.Load("Tail Animator/Deflection"); return __texDeflIcon; } }
+ private static Texture2D __texDeflIcon = null;
+ private static Texture curveIcon { get { if (_curveIcon == null) _curveIcon = FGUI_Resources.Tex_Curve; /*EditorGUIUtility.IconContent("AudioLowPassFilter Icon").image;*/ return _curveIcon; } }
+ private static Texture _curveIcon;
+ private static Texture _TexWindIcon { get { if (_windIcon == null) _windIcon = Resources.Load("Tail Animator/Wind"); return _windIcon; } }
+ private static Texture _windIcon;
+
+ private static UnityEngine.Object _manualFile;
+
+ private static GUIStyle smallStyle { get { if (_smallStyle == null) _smallStyle = new GUIStyle(EditorStyles.miniLabel) { fontStyle = FontStyle.Italic }; return _smallStyle; } }
+ private static GUIStyle _smallStyle;
+
+ // HELPER VARIABLES ----------------------------------------
+
+ private TailAnimator2 Get { get { if (_get == null) _get = target as TailAnimator2; return _get; } }
+ private TailAnimator2 _get;
+
+ private string topWarning = "";
+ private float topWarningAlpha = 0f;
+
+ static bool drawDefaultInspector = false;
+ //private Color limitsC = new Color(1f, 1f, 1f, 0.88f);
+ private Color c;
+ private Color bc;
+ private Color defaultValC = new Color(1f, 1f, 1f, 0.825f);
+
+
+ public List skins;
+ SkinnedMeshRenderer largestSkin;
+ Animator animator;
+ Animation animation;
+
+
+ ///
+ /// Trying to deep find skinned mesh renderer
+ ///
+ private void FindComponents()
+ {
+ if (skins == null) skins = new List();
+
+ foreach (var t in Get.transform.GetComponentsInChildren())
+ {
+ SkinnedMeshRenderer s = t.GetComponent(); if (s) skins.Add(s);
+ if (!animator) animator = t.GetComponent();
+ if (!animator) if (!animation) animation = t.GetComponent();
+ }
+
+ if ((skins != null && largestSkin != null) && (animator != null || animation != null)) return;
+
+ if (Get.transform != Get.transform)
+ {
+ foreach (var t in Get.transform.GetComponentsInChildren())
+ {
+ SkinnedMeshRenderer s = t.GetComponent(); if (!skins.Contains(s)) if (s) skins.Add(s);
+ if (!animator) animator = t.GetComponent();
+ if (!animator) if (!animation) animation = t.GetComponent();
+ }
+ }
+
+ // Searching in parent
+ if (skins.Count == 0)
+ {
+ Transform lastParent = Get.transform;
+
+ while (lastParent != null)
+ {
+ if (lastParent.parent == null) break;
+ lastParent = lastParent.parent;
+ }
+
+ foreach (var t in lastParent.GetComponentsInChildren())
+ {
+ SkinnedMeshRenderer s = t.GetComponent(); if (!skins.Contains(s)) if (s) skins.Add(s);
+ if (!animator) animator = t.GetComponent();
+ if (!animator) if (!animation) animation = t.GetComponent();
+ }
+ }
+
+ if (skins.Count > 1)
+ {
+ largestSkin = skins[0];
+ for (int i = 1; i < skins.Count; i++)
+ if (skins[i].bones.Length > largestSkin.bones.Length)
+ largestSkin = skins[i];
+ }
+ else
+ if (skins.Count > 0) largestSkin = skins[0];
+
+ }
+
+
+ ///
+ /// Checking if transform is child of choosed root bone parent transform
+ ///
+ bool IsChildOf(Transform child, Transform rootParent)
+ {
+ Transform tParent = child;
+ while (tParent != null && tParent != rootParent)
+ {
+ tParent = tParent.parent;
+ }
+
+ if (tParent == null) return false; else return true;
+ }
+
+
+ ///
+ /// Checking if transform is child of choosed root bone parent transform
+ ///
+ Transform GetLastChild(Transform rootParent)
+ {
+ Transform tChild = rootParent;
+ while (tChild.childCount > 0) tChild = tChild.GetChild(0);
+ return tChild;
+ }
+
+
+ ///
+ /// Getting editor selected objects with tail animators to apply changes to multiple tail animator objects
+ ///
+ private List GetSelectedTailAnimators()
+ {
+ List anims = new List();
+
+ for (int i = 0; i < Selection.gameObjects.Length; i++)
+ {
+ TailAnimator2 t = Selection.gameObjects[i].GetComponent();
+ if (t) if (!anims.Contains(t)) anims.Add(t);
+ }
+
+ lastSelected = anims;
+ return anims;
+ }
+ List lastSelected;
+
+ }
+}
diff --git a/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/TailAnimator.Editor.Helpers.cs.meta b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/TailAnimator.Editor.Helpers.cs.meta
new file mode 100644
index 000000000..db6012619
--- /dev/null
+++ b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/TailAnimator.Editor.Helpers.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 0e79d23b98435d54d93ae9b83395b629
+timeCreated: 1532131583
+licenseType: Store
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/TailAnimator.Editor.Lang.cs b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/TailAnimator.Editor.Lang.cs
new file mode 100644
index 000000000..6bf0633f8
--- /dev/null
+++ b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/TailAnimator.Editor.Lang.cs
@@ -0,0 +1,85 @@
+using System.Collections;
+using System.Xml;
+using UnityEngine;
+
+namespace FIMSpace.FTail
+{
+ public partial class FTailAnimator2_Editor
+ {
+ private TextAsset langFile { get { if (_langFile == null) _langFile = Resources.Load("Tail Animator/TailAnimator_Langs") as TextAsset; return _langFile; } }
+ private TextAsset _langFile;
+
+ /// Readed langs from file
+ private Hashtable langTexts;
+
+ public enum ELangs { English, Polski, русский, 中文, 日本語, 한국어 }
+ private static ELangs choosedLang = 0;
+
+
+ // Setup langs ----------------------------------------
+ private void SetupLangs()
+ {
+ // Checking if lang was setted through player prefs
+ choosedLang = (ELangs)PlayerPrefs.GetInt("FimposLang", 0);
+
+ if (langFile == null)
+ {
+ Debug.LogError("No lang file! You moved it from Editor/Resources/Tail Animator/ ???");
+ return;
+ }
+
+ #region Generating lang hashtable
+
+ var xml = new XmlDocument();
+ xml.LoadXml(langFile.text);
+
+
+ langTexts = new Hashtable();
+ var element = xml.DocumentElement[choosedLang.ToString()];
+ if (element != null)
+ {
+
+ var elemEnum = element.GetEnumerator();
+ while (elemEnum.MoveNext())
+ {
+ var xmlItem = (XmlElement)elemEnum.Current;
+ langTexts.Add(xmlItem.GetAttribute("name"), xmlItem.InnerText);
+ }
+ }
+ else
+ {
+ Debug.LogError("The specified language does not exist: " + choosedLang.ToString());
+ }
+
+ #endregion
+ }
+
+
+ private string Lang(string title)
+ {
+ if (langTexts == null)
+ {
+ //Debug.Log("No Lang: [" + title + "]");
+ return title;
+ }
+
+ if (!langTexts.ContainsKey(title))
+ {
+ return title;
+ }
+
+ string target = (string)langTexts[title];
+
+ if (string.IsNullOrEmpty(target)) return title;
+
+ return target;
+ }
+
+
+ private bool LangBig()
+ {
+ if (choosedLang == ELangs.中文 || choosedLang == ELangs.日本語) return true;
+ return false;
+ }
+ }
+}
diff --git a/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/TailAnimator.Editor.Lang.cs.meta b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/TailAnimator.Editor.Lang.cs.meta
new file mode 100644
index 000000000..d2a561b80
--- /dev/null
+++ b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/TailAnimator.Editor.Lang.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 9b613e7438d9e79458f122cd8fa5236b
+timeCreated: 1532131583
+licenseType: Store
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/TailAnimator.Editor.SceneGUI.cs b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/TailAnimator.Editor.SceneGUI.cs
new file mode 100644
index 000000000..55f760830
--- /dev/null
+++ b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/TailAnimator.Editor.SceneGUI.cs
@@ -0,0 +1,39 @@
+using UnityEditor;
+using UnityEngine;
+
+namespace FIMSpace.FTail
+{
+ public partial class FTailAnimator2_Editor
+ {
+ protected virtual void OnSceneGUI()
+ {
+ if (Application.isPlaying) return;
+ if (!Get.DrawGizmos) return;
+
+ if (Get._Editor_Category == TailAnimator2.ETailCategory.Setup)
+ if (Get.BaseTransform)
+ if (!FEngineering.VIsZero(Get.EndBoneJointOffset))
+ {
+ Get.RefreshTransformsList();
+
+ if (Get._TransformsGhostChain.Count > 0)
+ {
+ Undo.RecordObject(Get, "Changing position of tail joint offset");
+ Transform root = Get._TransformsGhostChain[Get._TransformsGhostChain.Count - 1];
+
+ Vector3 off = root.TransformVector(Get.EndBoneJointOffset);
+ Vector3 pos = root.position + off;
+ Vector3 transformed = FEditor_TransformHandles.PositionHandle(pos, Get.BaseTransform.rotation, .3f, true, false);
+
+ if (Vector3.Distance(transformed, pos) > 0.00001f)
+ {
+ Vector3 diff = transformed - pos;
+ Get.EndBoneJointOffset = root.InverseTransformVector(off + diff);
+ SerializedObject obj = new SerializedObject(Get);
+ if (obj != null) { obj.ApplyModifiedProperties(); obj.Update(); }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/TailAnimator.Editor.SceneGUI.cs.meta b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/TailAnimator.Editor.SceneGUI.cs.meta
new file mode 100644
index 000000000..74021b4b4
--- /dev/null
+++ b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/TailAnimator.Editor.SceneGUI.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: a05f6e8e06329674a85c95a70ca37780
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/TailAnimator.Editor.Tabs.cs b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/TailAnimator.Editor.Tabs.cs
new file mode 100644
index 000000000..02fe7bce9
--- /dev/null
+++ b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/TailAnimator.Editor.Tabs.cs
@@ -0,0 +1,339 @@
+using FIMSpace.FEditor;
+using UnityEditor;
+using UnityEngine;
+
+namespace FIMSpace.FTail
+{
+ public partial class FTailAnimator2_Editor
+ {
+
+ #region GUI Helpers
+
+ int[] setp_includeParent = new int[2] { 0, 1 };
+ GUIContent[] setp_includeParentNames = new GUIContent[2] { new GUIContent("Exclude", "Excluding first bone from tail animator motion - it will be anchor for rest of the bones"), new GUIContent("Include", "Including first bone for tail animator motion - ghost point will be generated to simulate parent of this bone") };
+
+ #endregion
+
+
+ private void Tab_DrawSetup()
+ {
+
+ FGUI_Inspector.VSpace(-2, -4);
+ GUILayout.BeginVertical(FGUI_Resources.ViewBoxStyle);
+ GUILayout.BeginVertical(FGUI_Resources.BGInBoxBlankStyle);
+ GUILayout.Space(7f);
+
+ Transform startField = Get.StartBone;
+ if (Get.StartBone == null) { startField = Get.transform; GUI.color = new Color(1f, 1f, 1f, 0.7f); }
+
+
+ if (topWarningAlpha > 0f)
+ if (topWarning != "")
+ {
+ GUI.color = new Color(c.r, c.g, c.b, c.a * Mathf.Min(1f, topWarningAlpha));
+ //EditorGUILayout.HelpBox(topWarning, MessageType.Info);
+ if (GUILayout.Button(topWarning, FGUI_Inspector.Style(new Color(0.8f, 0.8f, 0f, 0.1f), 0), GUILayout.ExpandWidth(true))) { topWarningAlpha = 0f; }
+ GUI.color = c;
+ topWarningAlpha -= 0.05f;
+ }
+
+
+ EditorGUI.BeginChangeCheck();
+ EditorGUIUtility.labelWidth = 82;
+
+ Transform preStart = Get.StartBone;
+
+ if (Application.isPlaying) GUI.enabled = false;
+
+ try
+ {
+ GUILayout.BeginHorizontal();
+ }
+ catch (System.Exception)
+ {
+ GUILayout.BeginHorizontal();
+ }
+
+ Transform startB = (Transform)EditorGUILayout.ObjectField(new GUIContent(sp_StartBone.displayName), startField, typeof(Transform), true);
+
+ if (startB != preStart)
+ {
+ Get.EndBone = null;
+ serializedObject.ApplyModifiedProperties();
+ }
+
+ if (Application.isPlaying) GUI.enabled = true;
+
+ //bool canInclude = false;
+ //if (startB) if (startB.parent) canInclude = true;
+
+ bool boneInSkin = true; if (skins.Count != 0) { boneInSkin = false; for (int s = 0; s < skins.Count; s++) { if (boneInSkin) break; for (int i = 0; i < skins[s].bones.Length; i++) { if (startB == skins[s].bones[i]) { boneInSkin = true; break; } } } }
+
+ if (!boneInSkin)
+ {
+ GUILayout.Space(4);
+ EditorGUILayout.LabelField(new GUIContent(FGUI_Resources.Tex_Warning, "'Start Bone' was not found in mesh renderer of this object, are you sure you assigned correct 'Start Bone'?"), new GUILayoutOption[] { GUILayout.Height(18), GUILayout.Width(20) });
+ }
+
+ {
+ EditorGUI.BeginChangeCheck();
+ Get.IncludeParent = EditorGUILayout.IntPopup(new GUIContent("", "If start bone should be included in tail motion or just be anchor for rest of the bones"), Get.IncludeParent ? 1 : 0, setp_includeParentNames, setp_includeParent, GUILayout.Width(64)) == 1;
+
+ if (EditorGUI.EndChangeCheck())
+ {
+ GetSelectedTailAnimators();
+ for (int i = 0; i < lastSelected.Count; i++) { lastSelected[i].IncludeParent = Get.IncludeParent; new SerializedObject(lastSelected[i]).ApplyModifiedProperties(); }
+ }
+
+ //if (Get.IncludeParent)
+ // if (!canInclude)
+ // {
+ // GUILayout.Space(4);
+ // EditorGUILayout.LabelField(new GUIContent(FGUI_Resources.Tex_Info, "Start bone need to have parent in order to be included in chain.\nAfter entering playmode this parameter will be set to 'Excluded'"), new GUILayoutOption[] { GUILayout.Height(18), GUILayout.Width(20) });
+ // }
+ }
+
+ GUILayout.EndHorizontal();
+
+
+ EditorGUIUtility.labelWidth = 0;
+ if (EditorGUI.EndChangeCheck()) { Get.StartBone = startB; serializedObject.ApplyModifiedProperties(); Get.GetGhostChain(); serializedObject.Update(); }
+
+ GUI.color = c;
+
+ GUILayout.Space(4f);
+ GUILayout.EndVertical();
+
+ GUILayout.BeginVertical(FGUI_Resources.BGInBoxStyle);
+ Fold_TailChainSetup();
+
+ GUILayout.Space(-5f);
+
+ GUILayout.EndVertical();
+
+ //Fold_DrawCoreAnimatorSetup();
+ Fold_DrawAdditionalSetup();
+
+ GUILayout.EndVertical();
+ }
+
+
+
+ private void Tab_DrawTweaking()
+ {
+ FGUI_Inspector.VSpace(-2, -4);
+ GUILayout.BeginVertical(FGUI_Resources.ViewBoxStyle);
+
+ GUILayout.Space(4);
+ EditorGUIUtility.labelWidth = 160f;
+ EditorGUILayout.BeginVertical(FGUI_Resources.BGInBoxBlankStyle);
+ EditorGUILayout.PropertyField(sp_TailAnimatorAmount); EditorGUIUtility.labelWidth = 0f;
+ EditorGUILayout.EndVertical();
+ GUI.color = c;
+ GUILayout.Space(-1f);
+
+ Fold_TweakingBending();
+ Fold_TweakingLimiting();
+ Fold_TweakingSmoothing();
+ Fold_TweakingAdditional();
+
+ GUILayout.Space(-5f);
+
+ GUILayout.EndVertical();
+ }
+
+
+ private void Tab_DrawAdditionalFeatures()
+ {
+ FGUI_Inspector.VSpace(-2, -3);
+ EditorGUILayout.BeginHorizontal(FGUI_Resources.HeaderBoxStyle);
+
+ DrawCategoryButton(TailAnimator2.ETailFeaturesCategory.Main, FGUI_Resources.Tex_Movement, "Main");
+ DrawCategoryButton(TailAnimator2.ETailFeaturesCategory.Collisions, FGUI_Resources.Tex_Collider, "Collisions");
+ DrawCategoryButton(TailAnimator2.ETailFeaturesCategory.IK, _TexIKIcon, "IK");
+ DrawCategoryButton(TailAnimator2.ETailFeaturesCategory.Experimental, _TexDeflIcon, "Experimental");
+
+ EditorGUILayout.EndHorizontal();
+ GUILayout.Space(3);
+
+ GUILayout.BeginVertical(FGUI_Resources.ViewBoxStyle);
+
+ if (Get._Editor_FeaturesCategory == TailAnimator2.ETailFeaturesCategory.Main)
+ {
+ // Waving
+ GUILayout.BeginVertical(FGUI_Resources.BGInBoxLightStyle); GUILayout.Space(5f);
+ Fold_ModuleWaving();
+
+ GUILayout.Space(3f);
+ GUILayout.EndVertical();
+
+ // Partial Blend
+ GUILayout.BeginVertical(FGUI_Resources.BGInBoxLightStyle); GUILayout.Space(2f);
+ Fold_ModulePartialBlend();
+
+ GUILayout.Space(2f);
+ GUILayout.EndVertical();
+
+ // Max Distance
+ GUILayout.BeginVertical(FGUI_Resources.BGInBoxStyle); GUILayout.Space(2f);
+ Fold_ModuleMaxDistance();
+
+ GUILayout.Space(2f);
+ GUILayout.EndVertical();
+ }
+ else if (Get._Editor_FeaturesCategory == TailAnimator2.ETailFeaturesCategory.Collisions)
+ {
+ // Module Collision
+ GUILayout.BeginVertical(FGUI_Resources.BGInBoxStyle); GUILayout.Space(2f);
+ Fold_ModuleCollisions();
+
+ GUILayout.Space(2f);
+ GUILayout.EndVertical();
+ }
+ else if (Get._Editor_FeaturesCategory == TailAnimator2.ETailFeaturesCategory.IK)
+ {
+ // IK
+ GUILayout.BeginVertical(FGUI_Resources.BGInBoxStyle); GUILayout.Space(2f);
+ Fold_ModuleIK();
+
+ GUILayout.Space(2f);
+ GUILayout.EndVertical();
+ }
+ else if (Get._Editor_FeaturesCategory == TailAnimator2.ETailFeaturesCategory.Experimental)
+ {
+ // Deflection Module
+ GUILayout.BeginVertical(FGUI_Resources.BGInBoxLightStyle); GUILayout.Space(2f);
+ Fold_ModuleDeflection();
+
+ GUILayout.Space(2f);
+ GUILayout.EndVertical();
+
+ // Physical effectors
+ GUILayout.BeginVertical(FGUI_Resources.BGInBoxLightStyle); GUILayout.Space(2f);
+ Fold_ModulePhysEffectors();
+
+ GUILayout.Space(2f);
+ GUILayout.EndVertical();
+ }
+
+ GUILayout.Space(-5f);
+
+ GUILayout.EndVertical();
+ }
+
+
+
+
+ private void Tab_DrawShaping()
+ {
+ FGUI_Inspector.VSpace(-2, -4);
+ GUILayout.BeginVertical(FGUI_Resources.ViewBoxStyle);
+ GUILayout.BeginVertical(FGUI_Resources.BGInBoxBlankStyle);
+
+ GUILayout.Space(2f);
+ EditorGUIUtility.labelWidth = 120;
+
+ if (FEngineering.QIsZero(Get.RotationOffset)) GUI.color = defaultValC; else GUI.color = c;
+
+ EditorGUI.BeginChangeCheck();
+ Get.RotationOffset = Quaternion.Euler(EditorGUILayout.Vector3Field(new GUIContent(sp_tailRotOff.displayName, sp_tailRotOff.tooltip), FEngineering.WrapVector(Get.RotationOffset.eulerAngles)));
+ if (EditorGUI.EndChangeCheck())
+ {
+ serializedObject.ApplyModifiedProperties();
+ GetSelectedTailAnimators();
+ for (int i = 0; i < lastSelected.Count; i++) { lastSelected[i].RotationOffset = Get.RotationOffset; new SerializedObject(lastSelected[i]).ApplyModifiedProperties(); }
+ }
+
+ // Curving Tail
+ GUILayout.Space(2f);
+ if (FEngineering.QIsZero(Get.Curving) && !Get.UseCurlingCurve) GUI.color = defaultValC; else GUI.color = c;
+
+ EditorGUILayout.BeginHorizontal();
+
+ EditorGUI.BeginChangeCheck();
+ Get.Curving = Quaternion.Euler(EditorGUILayout.Vector3Field(new GUIContent(sp_curving.displayName, sp_curving.tooltip), FEngineering.WrapVector(Get.Curving.eulerAngles)));
+ if (EditorGUI.EndChangeCheck())
+ {
+ serializedObject.ApplyModifiedProperties();
+ GetSelectedTailAnimators();
+ for (int i = 0; i < lastSelected.Count; i++) { lastSelected[i].Curving = Get.Curving; new SerializedObject(lastSelected[i]).ApplyModifiedProperties(); }
+ }
+
+ if (Get.UseCurvingCurve)
+ {
+ EditorGUILayout.LabelField(new GUIContent("*", "Curving offset value weight for tail segments multiplied by curve"), GUILayout.Width(9));
+ EditorGUILayout.PropertyField(sp_CurvCurve, new GUIContent("", sp_curving.tooltip), GUILayout.MaxWidth(32));
+ }
+ else
+ GUILayout.Space(4f);
+
+ EditorGUI.BeginChangeCheck();
+ SwitchButton(ref Get.UseCurvingCurve, "Spread curving rotation offset weight over tail segments", curveIcon);
+ if (EditorGUI.EndChangeCheck()) { GetSelectedTailAnimators(); for (int i = 0; i < lastSelected.Count; i++) { lastSelected[i].UseCurvingCurve = Get.UseCurvingCurve; new SerializedObject(lastSelected[i]).ApplyModifiedProperties(); } }
+ EditorGUILayout.EndHorizontal();
+
+ GUILayout.Space(3f);
+
+ // Length Stretch
+ if (Get.LengthMultiplier == 1f && !Get.UseLengthMulCurve) GUI.color = defaultValC; else GUI.color = c;
+
+ EditorGUILayout.BeginHorizontal();
+
+ if (!Get.UseLengthMulCurve)
+ {
+ EditorGUILayout.PropertyField(sp_LengthMultiplier);
+ GUILayout.Space(4f); EditorGUI.BeginChangeCheck();
+ SwitchButton(ref Get.UseLengthMulCurve, "Spread length multiplier weight over tail segments", curveIcon);
+ if (EditorGUI.EndChangeCheck()) { GetSelectedTailAnimators(); for (int i = 0; i < lastSelected.Count; i++) { lastSelected[i].UseLengthMulCurve = Get.UseLengthMulCurve; new SerializedObject(lastSelected[i]).ApplyModifiedProperties(); } }
+ }
+ else
+ {
+ EditorGUILayout.PropertyField(sp_LengthMulCurve, new GUIContent(sp_LengthMultiplier.displayName, sp_LengthMultiplier.tooltip));
+ GUILayout.Space(4f); EditorGUI.BeginChangeCheck();
+ SwitchButton(ref Get.UseLengthMulCurve, "Spread length multiplier weight over tail segments", curveIcon);
+ if (EditorGUI.EndChangeCheck()) { GetSelectedTailAnimators(); for (int i = 0; i < lastSelected.Count; i++) { lastSelected[i].UseLengthMulCurve = Get.UseLengthMulCurve; new SerializedObject(lastSelected[i]).ApplyModifiedProperties(); } }
+ }
+
+ EditorGUILayout.EndHorizontal();
+
+ GUILayout.Space(4);
+ if (Get.OverrideKeyframeAnimation > 0f)
+ {
+ EditorGUILayout.BeginHorizontal();
+ EditorGUIUtility.labelWidth = 180;
+ EditorGUILayout.PropertyField(sp_OverrideKeyframeAnimation);
+ EditorGUIUtility.labelWidth = 0;
+ EditorGUILayout.LabelField(new GUIContent(FGUI_Resources.Tex_Info, "You must know what you're doing with this parameter! You making bones being not affected by keyframed animation"), GUILayout.Width(16), GUILayout.Height(16));
+ EditorGUILayout.EndHorizontal();
+ }
+ else
+ {
+ GUI.color = new Color(1f, 1f, 1f, 0.7f);
+ EditorGUIUtility.labelWidth = 210;
+ EditorGUILayout.PropertyField(sp_OverrideKeyframeAnimation, new GUIContent(sp_OverrideKeyframeAnimation.displayName+ " (Off)", sp_OverrideKeyframeAnimation.tooltip));
+ EditorGUIUtility.labelWidth = 0;
+ GUI.color = c;
+ }
+
+ GUILayout.Space(1);
+
+ EditorGUIUtility.labelWidth = 0;
+ GUILayout.EndVertical();
+ GUILayout.EndVertical();
+ }
+
+
+ private void SwitchButton(ref bool enable, string tooltip, Texture icon)
+ {
+ EditorGUI.BeginChangeCheck();
+ GUI.color = enable ? new Color(0.9f, 0.9f, 0.9f, 1f) : c;
+
+ if (GUILayout.Button(new GUIContent(icon, tooltip), EditorStyles.miniButtonRight, new GUILayoutOption[2] { GUILayout.Width(20), GUILayout.Height(16) })) enable = !enable;
+
+ GUI.color = c;
+ if (EditorGUI.EndChangeCheck()) { serializedObject.ApplyModifiedProperties(); }
+ }
+
+
+ }
+}
diff --git a/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/TailAnimator.Editor.Tabs.cs.meta b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/TailAnimator.Editor.Tabs.cs.meta
new file mode 100644
index 000000000..a0e4da266
--- /dev/null
+++ b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/TailAnimator.Editor.Tabs.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 34cebb73f9f145b4b90276859fe48429
+timeCreated: 1532131583
+licenseType: Store
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/TailAnimator.Editor.Variables.cs b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/TailAnimator.Editor.Variables.cs
new file mode 100644
index 000000000..5d117b579
--- /dev/null
+++ b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/TailAnimator.Editor.Variables.cs
@@ -0,0 +1,381 @@
+using FIMSpace.FEditor;
+using UnityEditor;
+using UnityEngine;
+
+namespace FIMSpace.FTail
+{
+ public partial class FTailAnimator2_Editor
+ {
+ Transform startBone { get { return Get.StartBone; } set { Get.StartBone = value; } }
+
+
+ protected SerializedProperty sp_SmoothingStyle;
+ protected SerializedProperty sp_ReactSpeed;
+ protected SerializedProperty sp_RotRelev;
+ protected SerializedProperty sp_MaxStretching;
+ protected SerializedProperty sp_Springiness;
+ protected SerializedProperty sp_SpringinessCurling;
+ protected SerializedProperty sp_Slithery;
+ protected SerializedProperty sp_UpdateRate;
+ protected SerializedProperty sp_StartBone;
+ protected SerializedProperty sp_Sustain;
+ protected SerializedProperty sp_UseWind;
+ protected SerializedProperty sp_WindEffectPower;
+ protected SerializedProperty sp_WindTurbulencePower;
+ protected SerializedProperty sp_WindWorldNoisePower;
+ protected SerializedProperty sp_Boost;
+
+ protected SerializedProperty sp_UpdateAsLast;
+ protected SerializedProperty sp_SyncWithAnimator;
+ protected SerializedProperty sp_DetectZeroKeyframes;
+ protected SerializedProperty sp_StartAfterTPose;
+ protected SerializedProperty sp_EndBoneJointOffset;
+
+ protected SerializedProperty sp_LengthMultiplier;
+ protected SerializedProperty sp_Unify;
+ protected SerializedProperty sp_AnimateRoll;
+ protected SerializedProperty sp_Axis2D;
+ protected SerializedProperty sp_smoothdelta;
+ protected SerializedProperty sp_useCollision;
+ protected SerializedProperty sp_collMode;
+ protected SerializedProperty sp_curving;
+ protected SerializedProperty sp_DynamicWorldCollidersInclusion;
+ protected SerializedProperty sp_gravity;
+ protected SerializedProperty sp_colScale;
+ protected SerializedProperty sp_colScaleMul;
+ protected SerializedProperty sp_colBoxDim;
+ protected SerializedProperty sp_colDiffFact;
+ protected SerializedProperty sp_colWithOther;
+ protected SerializedProperty sp_colIgnored;
+ protected SerializedProperty sp_colIgnored2D;
+ protected SerializedProperty sp_colSameLayer;
+ protected SerializedProperty sp_colCustomLayer;
+ protected SerializedProperty sp_colAddRigs;
+ protected SerializedProperty sp_RootRotationOffset;
+ protected SerializedProperty sp_RootPositionOffset;
+ protected SerializedProperty sp_CollisionSpace;
+ protected SerializedProperty sp_ReflectCollision;
+ protected SerializedProperty sp_DetailedCollision;
+ protected SerializedProperty sp_IncludedColliders;
+ protected SerializedProperty sp_RigidbodyMass;
+
+ protected SerializedProperty sp_AngleLimit;
+ protected SerializedProperty sp_TailAnimatorAmount;
+ protected SerializedProperty sp_AngleLimitAxis;
+ protected SerializedProperty sp_LimitSmoothing;
+ protected SerializedProperty sp_MotionInfluence;
+ protected SerializedProperty sp_CollidersType;
+ protected SerializedProperty sp_OptimizeWithMesh;
+
+ protected SerializedProperty sp_wavType;
+ protected SerializedProperty sp_useWav;
+ protected SerializedProperty sp_cosAd;
+ protected SerializedProperty sp_wavSp;
+ protected SerializedProperty sp_wavRa;
+ protected SerializedProperty sp_wavAx;
+ protected SerializedProperty sp_tailRotOff;
+ protected SerializedProperty sp_altWave;
+ protected SerializedProperty sp_AnimatePhysics;
+ protected SerializedProperty sp_FixedCycle;
+ protected SerializedProperty sp_CollisionSlippery;
+
+ protected SerializedProperty sp_UsePosSpeedCurve;
+ protected SerializedProperty sp_UseRotSpeedCurve;
+ protected SerializedProperty sp_UseSlitCurve;
+ protected SerializedProperty sp_UseCurvingCurve;
+ protected SerializedProperty sp_UseLengthMulCurve;
+ protected SerializedProperty sp_UseGravCurv;
+ protected SerializedProperty sp_PosCurve;
+ protected SerializedProperty sp_RotCurve;
+ protected SerializedProperty sp_SlitCurve;
+ protected SerializedProperty sp_CurvCurve;
+ protected SerializedProperty sp_LengthMulCurve;
+ protected SerializedProperty sp_GravityCurve;
+ protected SerializedProperty sp_InclusionRadius;
+ protected SerializedProperty sp_SpringCurve;
+ protected SerializedProperty sp_UseSpringCurve;
+ protected SerializedProperty sp_SlipperyCurve;
+ protected SerializedProperty sp_UseSlipperyCurve;
+ protected SerializedProperty sp_Curling;
+ protected SerializedProperty sp_CurlingCurve;
+ protected SerializedProperty sp_UseCurlingCurve;
+ protected SerializedProperty sp_IgnoreMeshColliders;
+ protected SerializedProperty sp_CollideWithDisabledColliders;
+
+ protected SerializedProperty sp_BlendCurve;
+ private SerializedProperty sp_DeltaType;
+
+ //private SerializedProperty sp_SimulationSpeed;
+ private SerializedProperty sp_Optim;
+ private SerializedProperty sp_Prewarm;
+
+
+ private SerializedProperty sp_IKTarget;
+ private SerializedProperty sp_IKBlend;
+ private SerializedProperty sp_IKAnimatorBlend;
+ private SerializedProperty sp_IKAutoWeights;
+ private SerializedProperty sp_IKweightCurve;
+ private SerializedProperty sp_IKAutoAngleLimit;
+ private SerializedProperty sp_IKAutoAngleLimits;
+ private SerializedProperty sp_IKReactionQuality;
+ private SerializedProperty sp_IKSmoothing;
+ private SerializedProperty sp_IKBaseReactionWeight;
+ private SerializedProperty sp_IKContinous;
+ private SerializedProperty sp_IKLimitSettings;
+ private SerializedProperty sp_IKMaxStretching;
+ private SerializedProperty sp_UseIK;
+ private SerializedProperty sp_usePartialBlend;
+ private SerializedProperty sp_Detach;
+
+ private SerializedProperty sp_Deflection;
+ private SerializedProperty sp_DeflectionStartAngle;
+ private SerializedProperty sp_DeflectOnlyCollisions;
+ private SerializedProperty sp_DeflectionSmooth;
+ private SerializedProperty sp_DeflectionFalloff;
+
+ private SerializedProperty sp_UseMaxDistance;
+ private SerializedProperty sp_DistanceFrom;
+ private SerializedProperty sp_MaximumDistance;
+ private SerializedProperty sp_MaxOutDistanceFactor;
+ private SerializedProperty sp_DistanceWithoutY;
+ private SerializedProperty sp_DistanceMeasurePoint;
+ private SerializedProperty sp_FadeDuration;
+ private SerializedProperty sp_OverrideKeyframeAnimation;
+
+
+ //private SerializedProperty sp_IKMaxStretching;
+ //private SerializedProperty sp_IKStretchCurve;
+
+ protected virtual void OnEnable()
+ {
+ FGUI_Finders.ResetFinders();
+
+ sp_StartBone = serializedObject.FindProperty("StartBone");
+ sp_SmoothingStyle = serializedObject.FindProperty("SmoothingStyle");
+ sp_ReactSpeed = serializedObject.FindProperty("ReactionSpeed");
+ sp_RotRelev = serializedObject.FindProperty("RotationRelevancy");
+ sp_Sustain = serializedObject.FindProperty("Sustain");
+ sp_MaxStretching = serializedObject.FindProperty("MaxStretching");
+ sp_Springiness = serializedObject.FindProperty("Springiness");
+ sp_SpringinessCurling = serializedObject.FindProperty("SpringyCurling");
+ sp_Slithery = serializedObject.FindProperty("Slithery");
+ sp_UpdateRate = serializedObject.FindProperty("UpdateRate");
+ sp_DeltaType = serializedObject.FindProperty("DeltaType");
+ sp_TailAnimatorAmount = serializedObject.FindProperty("TailAnimatorAmount");
+ sp_DetectZeroKeyframes = serializedObject.FindProperty("DetectZeroKeyframes");
+ sp_UpdateAsLast = serializedObject.FindProperty("UpdateAsLast");
+ sp_SyncWithAnimator = serializedObject.FindProperty("SyncWithAnimator");
+ sp_StartAfterTPose = serializedObject.FindProperty("StartAfterTPose");
+ sp_EndBoneJointOffset = serializedObject.FindProperty("EndBoneJointOffset");
+ sp_Boost = serializedObject.FindProperty("Tangle");
+ sp_collMode = serializedObject.FindProperty("CollisionMode");
+
+ sp_AnimatePhysics = serializedObject.FindProperty("AnimatePhysics");
+ sp_FixedCycle = serializedObject.FindProperty("FixedCycle");
+ sp_LengthMultiplier = serializedObject.FindProperty("LengthMultiplier");
+ sp_smoothdelta = serializedObject.FindProperty("SafeDeltaTime");
+ sp_useCollision = serializedObject.FindProperty("UseCollision");
+ sp_curving = serializedObject.FindProperty("Curving");
+ sp_DynamicWorldCollidersInclusion = serializedObject.FindProperty("DynamicWorldCollidersInclusion");
+ sp_gravity = serializedObject.FindProperty("Gravity");
+ sp_InclusionRadius = serializedObject.FindProperty("InclusionRadius");
+ sp_colScale = serializedObject.FindProperty("CollidersScaleCurve");
+ sp_colScaleMul = serializedObject.FindProperty("CollidersScaleMul");
+ sp_colBoxDim = serializedObject.FindProperty("BoxesDimensionsMul");
+ sp_colDiffFact = serializedObject.FindProperty("CollisionsAutoCurve");
+ sp_colWithOther = serializedObject.FindProperty("CollideWithOtherTails");
+ sp_RigidbodyMass = serializedObject.FindProperty("RigidbodyMass");
+ sp_Detach = serializedObject.FindProperty("DetachChildren");
+
+
+ sp_colIgnored = serializedObject.FindProperty("IgnoredColliders");
+ sp_colIgnored2D = serializedObject.FindProperty("IgnoredColliders2D");
+ sp_Unify = serializedObject.FindProperty("UnifyBendiness");
+ sp_AnimateRoll = serializedObject.FindProperty("AnimateRoll");
+ sp_Axis2D = serializedObject.FindProperty("Axis2D");
+ sp_colSameLayer = serializedObject.FindProperty("CollidersSameLayer");
+ sp_colCustomLayer = serializedObject.FindProperty("CollidersLayer");
+ sp_colAddRigs = serializedObject.FindProperty("CollidersAddRigidbody");
+ sp_RootRotationOffset = serializedObject.FindProperty("RootRotationOffset");
+ sp_RootPositionOffset = serializedObject.FindProperty("RootPositionOffset");
+ sp_CollisionSpace = serializedObject.FindProperty("CollisionSpace");
+ sp_ReflectCollision = serializedObject.FindProperty("ReflectCollision");
+ sp_IncludedColliders = serializedObject.FindProperty("IncludedColliders");
+ sp_DetailedCollision = serializedObject.FindProperty("CheapCollision");
+ sp_IncludedColliders = serializedObject.FindProperty("IncludedColliders");
+
+ sp_AngleLimit = serializedObject.FindProperty("AngleLimit");
+ sp_AngleLimitAxis = serializedObject.FindProperty("AngleLimitAxis");
+ //sp_AngleLimitAxisTo = serializedObject.FindProperty("LimitAxisRange");
+ sp_LimitSmoothing = serializedObject.FindProperty("LimitSmoothing");
+ sp_MotionInfluence = serializedObject.FindProperty("MotionInfluence");
+ sp_CollidersType = serializedObject.FindProperty("CollidersType");
+ sp_OptimizeWithMesh = serializedObject.FindProperty("OptimizeWithMesh");
+
+ sp_altWave = serializedObject.FindProperty("AlternateWave");
+ sp_wavType = serializedObject.FindProperty("WavingType");
+ sp_useWav = serializedObject.FindProperty("UseWaving");
+ sp_cosAd = serializedObject.FindProperty("CosinusAdd");
+ sp_wavSp = serializedObject.FindProperty("WavingSpeed");
+ sp_wavRa = serializedObject.FindProperty("WavingRange");
+ sp_wavAx = serializedObject.FindProperty("WavingAxis");
+ sp_tailRotOff = serializedObject.FindProperty("RotationOffset");
+ sp_BlendCurve = serializedObject.FindProperty("BlendCurve");
+ sp_CollisionSlippery = serializedObject.FindProperty("CollisionSlippery");
+ //sp_BlendChainValue = serializedObject.FindProperty("BlendChainValue");
+ //sp_BlendChainFaloff = serializedObject.FindProperty("BlendChainFaloff");
+
+ sp_UsePosSpeedCurve = serializedObject.FindProperty("UsePosSpeedCurve");
+ sp_UseRotSpeedCurve = serializedObject.FindProperty("UseRotSpeedCurve");
+ sp_UseSlitCurve = serializedObject.FindProperty("UseSlitheryCurve");
+ sp_UseCurvingCurve = serializedObject.FindProperty("UseCurvingCurve");
+ sp_UseLengthMulCurve = serializedObject.FindProperty("UseLengthMulCurve");
+ sp_UseGravCurv = serializedObject.FindProperty("UseGravityCurve");
+ sp_PosCurve = serializedObject.FindProperty("PosCurve");
+ sp_RotCurve = serializedObject.FindProperty("RotCurve");
+ sp_SlitCurve = serializedObject.FindProperty("SlitheryCurve");
+ sp_CurvCurve = serializedObject.FindProperty("CurvCurve");
+ sp_LengthMulCurve = serializedObject.FindProperty("LengthMulCurve");
+ sp_InclusionRadius = serializedObject.FindProperty("InclusionRadius");
+ sp_GravityCurve = serializedObject.FindProperty("GravityCurve");
+ sp_SpringCurve = serializedObject.FindProperty("SpringCurve");
+ sp_UseSpringCurve = serializedObject.FindProperty("UseSpringCurve");
+ sp_UseSlipperyCurve = serializedObject.FindProperty("UseSlipperyCurve");
+ sp_SlipperyCurve = serializedObject.FindProperty("SlipperyCurve");
+ sp_UseCurlingCurve = serializedObject.FindProperty("UseCurlingCurve");
+ sp_IgnoreMeshColliders = serializedObject.FindProperty("IgnoreMeshColliders");
+ sp_CollideWithDisabledColliders = serializedObject.FindProperty("CollideWithDisabledColliders");
+ sp_Curling = serializedObject.FindProperty("Curling");
+ sp_CurlingCurve = serializedObject.FindProperty("CurlingCurve");
+ sp_UseWind = serializedObject.FindProperty("UseWind");
+ sp_WindEffectPower = serializedObject.FindProperty("WindEffectPower");
+ sp_WindTurbulencePower = serializedObject.FindProperty("WindTurbulencePower");
+ sp_WindWorldNoisePower = serializedObject.FindProperty("WindWorldNoisePower");
+ //sp_SimulationSpeed = serializedObject.FindProperty("SimulationSpeed");
+ sp_Optim = serializedObject.FindProperty("InterpolateRate");
+ sp_Prewarm = serializedObject.FindProperty("Prewarm");
+
+ sp_UseIK = serializedObject.FindProperty("UseIK");
+ sp_usePartialBlend = serializedObject.FindProperty("UsePartialBlend");
+ sp_IKTarget = serializedObject.FindProperty("IKTarget");
+ sp_IKAutoWeights = serializedObject.FindProperty("IKAutoWeights");
+ sp_IKweightCurve = serializedObject.FindProperty("IKReactionWeightCurve");
+ sp_IKAutoAngleLimit = serializedObject.FindProperty("IKAutoAngleLimit");
+ sp_IKAutoAngleLimits = serializedObject.FindProperty("IKAutoAngleLimits");
+ sp_IKReactionQuality = serializedObject.FindProperty("IKReactionQuality");
+ sp_IKSmoothing = serializedObject.FindProperty("IKSmoothing");
+ sp_IKMaxStretching = serializedObject.FindProperty("IKStretchToTarget");
+ sp_IKBaseReactionWeight = serializedObject.FindProperty("IKBaseReactionWeight");
+ sp_IKContinous = serializedObject.FindProperty("IKContinousSolve");
+ //sp_IKMaxStretching = serializedObject.FindProperty("IKMaxStretching");
+ //sp_IKStretchCurve = serializedObject.FindProperty("IKStretchCurve");
+ sp_IKLimitSettings = serializedObject.FindProperty("IKLimitSettings");
+ sp_IKBlend = serializedObject.FindProperty("IKBlend");
+ sp_IKAnimatorBlend = serializedObject.FindProperty("IKAnimatorBlend");
+
+ sp_Deflection = serializedObject.FindProperty("Deflection");
+ sp_DeflectionFalloff = serializedObject.FindProperty("DeflectionFalloff");
+ sp_DeflectionSmooth = serializedObject.FindProperty("DeflectionSmooth");
+ sp_DeflectionStartAngle = serializedObject.FindProperty("DeflectionStartAngle");
+ sp_DeflectOnlyCollisions = serializedObject.FindProperty("DeflectOnlyCollisions");
+
+ sp_UseMaxDistance = serializedObject.FindProperty("UseMaxDistance");
+ sp_DistanceFrom = serializedObject.FindProperty("DistanceFrom");
+ sp_MaximumDistance = serializedObject.FindProperty("MaximumDistance");
+ sp_MaxOutDistanceFactor = serializedObject.FindProperty("MaxOutDistanceFactor");
+ sp_DistanceWithoutY = serializedObject.FindProperty("DistanceWithoutY");
+ sp_DistanceMeasurePoint = serializedObject.FindProperty("DistanceMeasurePoint");
+ sp_FadeDuration = serializedObject.FindProperty("FadeDuration");
+ sp_OverrideKeyframeAnimation = serializedObject.FindProperty("OverrideKeyframeAnimation");
+
+
+ FindComponents();
+ Get.CheckForNullsInGhostChain();
+
+ // First assignment
+ if (!startBone)
+ {
+ if (skins.Count != 0)
+ {
+ // If skins found ad this transform is part of any skeleton then this transform will be start bone
+ bool contains = false;
+
+ for (int i = 0; i < skins.Count; i++)
+ {
+ if (contains) break;
+
+ for (int b = 0; b < skins[i].bones.Length; b++)
+ if (skins[i].bones[b] == Get.transform)
+ { contains = true; break; }
+ }
+
+ if (contains)
+ {
+ startBone = Get.transform;
+ Get.GetGhostChain();
+ }
+ else
+ {
+ // If skins are found, we assigning first bone from it
+ startBone = largestSkin.bones[0];
+ Get.GetGhostChain();
+ }
+ }
+
+ }
+
+
+ if (Get._TransformsGhostChain == null)
+ {
+ Get._TransformsGhostChain = new System.Collections.Generic.List();
+ serializedObject.ApplyModifiedProperties();
+ serializedObject.Update();
+ }
+
+
+ if (Get.UseIK || Get.UseWaving)
+ {
+ if (Get.UseWaving) drawWaving = true; else drawWaving = false;
+ }
+
+ if (Get.UnifyBendiness > 0f || Get.Sustain > 0f)
+ drawTweakAdditional = true;
+
+ if (((Get.ReactionSpeed >= 1f || Get.ReactionSpeed >= 0.99f) && !Get.UseRotSpeedCurve) && (Get.RotationRelevancy >= 1f && !Get.UseRotSpeedCurve))
+ drawSmoothing = false;
+ else
+ if (Get.UseRotSpeedCurve || Get.UsePosSpeedCurve) drawSmoothing = true;
+
+ if (Get.UseCollision) drawCollisions = true;
+
+ if (Get.Deflection > Mathf.Epsilon) drawDefl = true;
+
+ if (Get._editor_animatorViewedCounter < 1)
+ {
+ Get._editor_animatorViewedCounter++;
+
+ if (startBone == null)
+ {
+ topWarning = "No skinned bones found - assign 'Start Bone'";
+ topWarningAlpha = 1.5f;
+ }
+ else
+ {
+ topWarning = "Automatically found start bone - please check if it is correct one";
+ topWarningAlpha = 1.85f;
+ }
+ }
+
+ SetupLangs();
+ }
+
+ void OnDisable()
+ {
+ if (hideSkin) for (int i = 0; i < skins.Count; i++)
+ {
+ skins[i].shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.On;
+ }
+ }
+
+ }
+}
diff --git a/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/TailAnimator.Editor.Variables.cs.meta b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/TailAnimator.Editor.Variables.cs.meta
new file mode 100644
index 000000000..eaca4af18
--- /dev/null
+++ b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/TailAnimator.Editor.Variables.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 4353b07ef84cbd14faeef2a48497adf6
+timeCreated: 1532131583
+licenseType: Store
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/TailAnimator.Editor.cs b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/TailAnimator.Editor.cs
new file mode 100644
index 000000000..98ea51540
--- /dev/null
+++ b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/TailAnimator.Editor.cs
@@ -0,0 +1,148 @@
+using FIMSpace.FEditor;
+using UnityEditor;
+using UnityEngine;
+
+namespace FIMSpace.FTail
+{
+ [CustomEditor(typeof(TailAnimator2))]
+ [CanEditMultipleObjects]
+ public partial class FTailAnimator2_Editor : Editor
+ {
+ [MenuItem("CONTEXT/TailAnimator2/Switch displaying header bar")]
+ private static void HideFImpossibleHeader(MenuCommand menuCommand)
+ {
+ int current = EditorPrefs.GetInt("FTailHeader", 1);
+ if (current == 1) current = 0; else current = 1;
+ EditorPrefs.SetInt("FTailHeader", current);
+ }
+
+ public override void OnInspectorGUI()
+ {
+ //Undo.RecordObject(target, "Spine Animator Inspector");
+
+ serializedObject.Update();
+
+ TailAnimator2 Get = (TailAnimator2)target;
+ string title = drawDefaultInspector ? " Default Inspector" : (" " + Get._editor_Title);
+
+ if (EditorPrefs.GetInt("FTailHeader", 1) == 1)
+ {
+ HeaderBoxMain(title, ref Get.DrawGizmos, ref drawDefaultInspector, _TexTailAnimIcon, Get, 27);
+ }
+ else
+ GUILayout.Space(4);
+
+ if (drawDefaultInspector)
+ DrawDefaultInspector();
+ else
+ DrawNewGUI();
+
+ serializedObject.ApplyModifiedProperties();
+ }
+
+ void DrawCategoryButton(TailAnimator2.ETailCategory target, Texture icon, string lang)
+ {
+ if (Get._Editor_Category == target) GUI.backgroundColor = new Color(0.1f, 1f, 0.2f, 1f);
+
+ int height = 28;
+ int lim = 360;
+ if (choosedLang == ELangs.русский) lim = 390;
+
+ if (EditorGUIUtility.currentViewWidth > lim)
+ {
+ if (GUILayout.Button(new GUIContent(" " + Lang(lang), icon), FGUI_Resources.ButtonStyle, GUILayout.Height(height))) Get._Editor_Category = target;
+ }
+ else
+ if (GUILayout.Button(new GUIContent(icon, Lang(lang)), FGUI_Resources.ButtonStyle, GUILayout.Height(height))) Get._Editor_Category = target;
+
+ GUI.backgroundColor = bc;
+ }
+
+ void DrawCategoryButton(TailAnimator2.ETailFeaturesCategory target, Texture icon, string lang)
+ {
+ if (Get._Editor_FeaturesCategory == target) GUI.backgroundColor = new Color(0.1f, 1f, 0.2f, 1f);
+
+ int height = 24;
+ int lim = 360;
+ if (choosedLang == ELangs.русский) lim = 390;
+
+ if (EditorGUIUtility.currentViewWidth > lim)
+ {
+ if (GUILayout.Button(new GUIContent(" " + Lang(lang), icon), FGUI_Resources.ButtonStyle, GUILayout.Height(height))) Get._Editor_FeaturesCategory = target;
+ }
+ else
+ if (GUILayout.Button(new GUIContent(icon, Lang(lang)), FGUI_Resources.ButtonStyle, GUILayout.Height(height))) Get._Editor_FeaturesCategory = target;
+
+ GUI.backgroundColor = bc;
+ }
+
+
+ void DrawNewGUI()
+ {
+ #region Preparations for unity versions and skin
+
+ c = Color.Lerp(GUI.color * new Color(0.8f, 0.8f, 0.8f, 0.7f), GUI.color, Mathf.InverseLerp(0f, 0.15f, Get.TailAnimatorAmount));
+ bc = GUI.backgroundColor;
+
+ RectOffset zeroOff = new RectOffset(0, 0, 0, 0);
+ float substr = .18f; float bgAlpha = 0.08f; if (EditorGUIUtility.isProSkin) { bgAlpha = 0.1f; substr = 0f; }
+
+#if UNITY_2019_3_OR_NEWER
+ int headerHeight = 22;
+#else
+ int headerHeight = 25;
+#endif
+
+ Get._editor_IsInspectorViewingColliders = Get._Editor_FeaturesCategory == TailAnimator2.ETailFeaturesCategory.Collisions;
+ Get._editor_IsInspectorViewingIncludedColliders = drawInclud && Get._editor_IsInspectorViewingColliders;
+
+ Get.RefreshTransformsList();
+
+ #endregion
+
+
+ GUILayout.Space(2);
+ EditorGUILayout.BeginHorizontal();
+ DrawCategoryButton(TailAnimator2.ETailCategory.Setup, FGUI_Resources.Tex_GearSetup, "Setup");
+ DrawCategoryButton(TailAnimator2.ETailCategory.Tweak, FGUI_Resources.Tex_Sliders, "Tweak");
+ DrawCategoryButton(TailAnimator2.ETailCategory.Features, FGUI_Resources.Tex_Module, "Features");
+ DrawCategoryButton(TailAnimator2.ETailCategory.Shaping, FGUI_Resources.Tex_Repair, "Shaping");
+ EditorGUILayout.EndHorizontal();
+ GUILayout.Space(4);
+
+ switch (Get._Editor_Category)
+ {
+ case TailAnimator2.ETailCategory.Setup:
+ GUILayout.BeginVertical(FGUI_Inspector.Style(zeroOff, zeroOff, new Color(.7f - substr, .7f - substr, 0.7f - substr, bgAlpha), Vector4.one * 3, 3));
+ FGUI_Inspector.HeaderBox(Lang("Main Setup"), true, FGUI_Resources.Tex_GearSetup, headerHeight, headerHeight - 1, LangBig());
+ Tab_DrawSetup();
+ GUILayout.EndVertical();
+ break;
+
+ case TailAnimator2.ETailCategory.Tweak:
+ GUILayout.BeginVertical(FGUI_Inspector.Style(zeroOff, zeroOff, new Color(.3f - substr, .4f - substr, 1f - substr, bgAlpha), Vector4.one * 3, 3));
+ FGUI_Inspector.HeaderBox(Lang("Tweak Animation"), true, FGUI_Resources.Tex_Sliders, headerHeight, headerHeight - 1, LangBig());
+ Tab_DrawTweaking();
+ GUILayout.EndVertical();
+ break;
+
+ case TailAnimator2.ETailCategory.Features:
+ GUILayout.BeginVertical(FGUI_Inspector.Style(zeroOff, zeroOff, new Color(.4f - substr, 1f - substr, .8f - substr, bgAlpha * 0.6f), Vector4.one * 3, 3));
+ //FGUI_Inspector.HeaderBox(Lang("Additional Modules"), true, FGUI_Resources.Tex_Module, headerHeight, headerHeight - 1, LangBig());
+ Tab_DrawAdditionalFeatures();
+ GUILayout.EndVertical();
+ break;
+
+ case TailAnimator2.ETailCategory.Shaping:
+ GUILayout.BeginVertical(FGUI_Inspector.Style(zeroOff, zeroOff, new Color(1f - substr, .55f - substr, .55f - substr, bgAlpha * 0.5f), Vector4.one * 3, 3));
+ FGUI_Inspector.HeaderBox(Lang("Additional Shaping"), true, FGUI_Resources.Tex_Repair, headerHeight, headerHeight - 1, LangBig());
+ Tab_DrawShaping();
+ GUILayout.EndVertical();
+ break;
+ }
+
+ GUILayout.Space(2f);
+ }
+
+ }
+}
diff --git a/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/TailAnimator.Editor.cs.meta b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/TailAnimator.Editor.cs.meta
new file mode 100644
index 000000000..a08921b7d
--- /dev/null
+++ b/Assets/FImpossible Creations/Editor/Plugins - Editor - Animating/Tail Animator/TailAnimator.Editor.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 96a57e14ee3d2d546828fba97946e597
+timeCreated: 1532131583
+licenseType: Store
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator.meta b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator.meta
new file mode 100644
index 000000000..0b8930000
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 202e9deb41375844daf2c8a489b596d5
+folderAsset: yes
+timeCreated: 1532283218
+licenseType: Store
+DefaultImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code.meta b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code.meta
new file mode 100644
index 000000000..0e08c0b98
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 6e3d55ec0583b8f458db21ee51c4ead3
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Class.TailSegment.cs b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Class.TailSegment.cs
new file mode 100644
index 000000000..048b694e1
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Class.TailSegment.cs
@@ -0,0 +1,463 @@
+using System;
+using UnityEngine;
+
+namespace FIMSpace.FTail
+{
+ public partial class TailAnimator2
+ {
+ ///
+ /// FM: Helper class to animate tail bones freely
+ ///
+ [System.Serializable]
+ public class TailSegment
+ {
+ public TailSegment ParentBone { get; private set; }
+ public TailSegment ChildBone { get; private set; }
+
+ /// All references must have transform reference except GhostChild bone, GhostParent can have same transform as first bone in chain
+ public Transform transform { get; private set; }
+
+ /// Index of bone in Tail Animator list
+ public int Index { get; private set; }
+
+ /// For quicker value getting from curves
+ public float IndexOverlLength { get; private set; }
+
+ /// Procedural position for tail motion without weight blending etc.
+ public Vector3 ProceduralPosition = Vector3.zero;
+ /// Final procedural position for tail transforms so weight blended
+ public Vector3 ProceduralPositionWeightBlended = Vector3.zero;
+
+ /// Final rotation for tail transform so rotated towards blended position
+ public Quaternion TrueTargetRotation = Quaternion.identity;
+ /// Reference rotation for position offset in parent orientation used in rotation smoothing
+ public Quaternion PosRefRotation = Quaternion.identity;
+ /// Memory for slithery motion
+ public Quaternion PreviousPosReferenceRotation = Quaternion.identity;
+
+ /// Memory for velocity (PreviousProceduralPosition)
+ public Vector3 PreviousPosition;
+
+ /// Blend with tail animator motion value used in partial blending
+ public float BlendValue = 1f;
+
+ /// Length of the bone in initial world space - distance to next bone transform
+ public float BoneLength { get; private set; }
+ /// Length of bone basing on intial positions / keyframe positions scaled with transform scale and length multiplier
+ public Vector3 BoneDimensionsScaled;
+ public float BoneLengthScaled;
+
+ public Vector3 InitialLocalPosition = Vector3.zero;
+ public Vector3 InitialLocalPositionInRoot = Vector3.zero;
+ public Quaternion InitialLocalRotationInRoot = Quaternion.identity;
+ public Vector3 LocalOffset = Vector3.zero;
+ public Quaternion InitialLocalRotation = Quaternion.identity;
+
+ // Collision related variables
+ public float ColliderRadius = 1f;
+
+
+ public bool CollisionContactFlag = false;
+ public float CollisionContactRelevancy = -1f;
+ public Collision collisionContacts = null;
+
+ // Animation styles helper variables
+ public Vector3 VelocityHelper = Vector3.zero;
+ public Quaternion QVelocityHelper = Quaternion.identity;
+
+ /// Helper variable for 'Sustain' parameter
+ public Vector3 PreviousPush = Vector3.zero;
+
+ // Shaping
+ public Quaternion Curving = Quaternion.identity;
+ public Vector3 Gravity = Vector3.zero;
+ public Vector3 GravityLookOffset = Vector3.zero;
+ public float LengthMultiplier = 1f;
+
+ // Expert
+ public float PositionSpeed = 1f;
+ public float RotationSpeed = 1f;
+ public float Springiness = 0f;
+ public float Slithery = 1f;
+ public float Curling = 0.5f;
+ public float Slippery = 1f;
+
+ public TailCollisionHelper CollisionHelper { get; internal set; }
+
+
+ #region Constructors
+
+ public TailSegment() { Index = -1; Curving = Quaternion.identity; Gravity = Vector3.zero; LengthMultiplier = 1f; Deflection = Vector3.zero; DeflectionFactor = 0f; DeflectionRelevancy = -1; deflectionSmoothVelo = 0f; }
+ public TailSegment(Transform transform) : this()
+ {
+ if (transform == null) return;
+
+ this.transform = transform;
+
+ // Init position setup
+ ProceduralPosition = transform.position;
+ PreviousPosition = transform.position;
+ PosRefRotation = transform.rotation;
+ PreviousPosReferenceRotation = PosRefRotation;
+ TrueTargetRotation = PosRefRotation;
+ ReInitializeLocalPosRot(transform.localPosition, transform.localRotation);
+ BoneLength = 0.1f;
+ //ReInitializeLocalPosRot(transform.localPosition, transform.localRotation);
+ }
+
+ public TailSegment(TailSegment copyFrom) : this(copyFrom.transform)
+ {
+ this.transform = copyFrom.transform;
+
+ // Init position setup
+ Index = copyFrom.Index;
+ IndexOverlLength = copyFrom.IndexOverlLength;
+
+ ProceduralPosition = copyFrom.ProceduralPosition;
+ PreviousPosition = copyFrom.PreviousPosition;
+ ProceduralPositionWeightBlended = copyFrom.ProceduralPosition;
+ PosRefRotation = copyFrom.PosRefRotation;
+ PreviousPosReferenceRotation = PosRefRotation;
+ TrueTargetRotation = copyFrom.TrueTargetRotation;
+
+ ReInitializeLocalPosRot(copyFrom.InitialLocalPosition, copyFrom.InitialLocalRotation);
+ }
+
+
+ public void ReInitializeLocalPosRot(Vector3 initLocalPos, Quaternion initLocalRot)
+ {
+ InitialLocalPosition = initLocalPos;
+ InitialLocalRotation = initLocalRot;
+ }
+
+
+ #endregion
+
+
+ public void SetIndex(int i, int tailSegments)
+ {
+ Index = i;
+ if (i < 0) IndexOverlLength = 0f;
+ else IndexOverlLength = (float)i / (float)tailSegments;
+ }
+
+ public void SetParentRef(TailSegment parent)
+ { ParentBone = parent; BoneLength = (ProceduralPosition - ParentBone.ProceduralPosition).magnitude; }
+
+ public void SetChildRef(TailSegment child)
+ { ChildBone = child; }
+
+ public float GetRadiusScaled()
+ { return ColliderRadius * transform.lossyScale.x; }
+
+
+ public bool IsDetachable { get; private set; }
+ public void AssignDetachedRootCoords(Transform root)
+ {
+ InitialLocalPositionInRoot = root.InverseTransformPoint(transform.position);
+ InitialLocalRotationInRoot = FEngineering.QToLocal(root.rotation, transform.rotation);
+ IsDetachable = true;
+ }
+
+ //public static Vector3 CalculateLocalLook(Transform parent, Transform child)
+ //{ return -(parent.InverseTransformPoint(child.position) - parent.InverseTransformPoint(parent.position)).normalized; }
+
+
+ ///
+ /// Blend toward target position
+ ///
+ internal Vector3 BlendMotionWeight(Vector3 newPosition)
+ {
+ return Vector3.LerpUnclamped
+ (
+ // Blending from default pose to new position
+ ParentBone.ProceduralPosition + FEngineering.TransformVector(ParentBone.LastKeyframeLocalRotation, ParentBone.transform.lossyScale, LastKeyframeLocalPosition),
+ newPosition,
+ BlendValue
+ );
+ }
+
+ internal void PreCalibrate()
+ {
+ transform.localPosition = InitialLocalPosition;
+ transform.localRotation = InitialLocalRotation;
+ }
+
+ internal void Validate()
+ {
+ if (BoneLength == 0f) BoneLength = 0.001f;
+ }
+
+
+ #region Zero keyframe detection
+
+ public void RefreshKeyLocalPosition()
+ {
+ if (transform)
+ LastKeyframeLocalRotation =(transform.localRotation);
+ else
+ LastKeyframeLocalRotation = (InitialLocalRotation);
+ }
+
+
+ public void RefreshKeyLocalPositionAndRotation()
+ {
+ if ( transform)
+ RefreshKeyLocalPositionAndRotation(transform.localPosition, transform.localRotation);
+ else
+ RefreshKeyLocalPositionAndRotation(InitialLocalPosition, InitialLocalRotation);
+ }
+
+ public void RefreshKeyLocalPositionAndRotation(Vector3 p, Quaternion r)
+ {
+ LastKeyframeLocalPosition = p;
+ LastKeyframeLocalRotation = r;
+ }
+
+ /// Initial local rotation or keyframe local rotation
+ public Quaternion LastKeyframeLocalRotation;// { get { if (transform) return transform.localRotation; else return InitialLocalRotation; } }
+ /// Initial local position or keyframe local position
+ public Vector3 LastKeyframeLocalPosition;// { get { if (transform) return transform.localPosition; else return InitialLocalPosition; } }
+
+ public Vector3 LastFinalPosition { get; private set; }
+ public Quaternion LastFinalRotation { get; private set; }
+
+
+ ///
+ /// Offsset to default segment position from parent relation
+ ///
+ internal Vector3 ParentToFrontOffset()
+ {
+ return FEngineering.TransformVector
+ (
+ ParentBone.LastKeyframeLocalRotation,
+ ParentBone.transform.lossyScale,
+ LastKeyframeLocalPosition
+ );
+ }
+
+
+ public void RefreshFinalPos(Vector3 pos)
+ { LastFinalPosition = pos; }
+
+ public void RefreshFinalRot(Quaternion rot)
+ { LastFinalRotation = rot; }
+
+ #endregion
+
+
+ #region Deflection feature support
+
+ /// Dot product of deflection angle for segment
+ public float DeflectionFactor { get; private set; }
+ /// Deflection direction
+ public Vector3 Deflection { get; private set; }
+ public float DeflectionSmooth { get; private set; }
+ private float deflectionSmoothVelo; // Helper variable for smooth damp
+
+ /// Deflection world position
+ public Vector3 DeflectionWorldPosition { get; private set; }
+ /// Relevancy of deflection in list used for optimization
+ public int DeflectionRelevancy { get; private set; }
+ public FImp_ColliderData_Base LatestSelectiveCollision { get; internal set; }
+
+
+ ///
+ /// Checking relation between reference position to define deflection
+ ///
+ public bool CheckDeflectionState(float zeroWhenLower, float smoothTime, float delta)
+ {
+ Vector3 deflection = LastKeyframeLocalPosition - ParentBone.transform.InverseTransformVector(ProceduralPosition - ParentBone.ProceduralPosition);
+
+ #region Debugging
+ //deflection = LastKeyframeLocalPosition - FEngineering.TransformVector(ParentBone.ParentBone.ProceduralRotation, ParentBone.transform.lossyScale, ProceduralPosition - ParentBone.ProceduralPosition);
+ //Debug.DrawRay(ParentBone.transform.position + Vector3.up * 1.1f, ParentBone.transform.TransformVector(ProceduralPosition - ParentBone.ProceduralPosition), Color.red);
+ //Debug.DrawRay(ParentBone.ProceduralPosition + Vector3.up * 1.1f, FEngineering.TransformVector(ParentBone.ParentBone.ProceduralRotation, ParentBone.transform.lossyScale, ProceduralPosition - ParentBone.ProceduralPosition), new Color(1f, 0.5f, 0f, 1f) );
+ #endregion
+
+ DeflectionFactor = Vector3.Dot(LastKeyframeLocalPosition.normalized, deflection.normalized); // Calculating factor in local space
+
+#if UNITY_EDITOR // Debugging
+ deflection = ChildBone.ParentBone.transform.TransformVector(deflection); // Transforming into world space offset for segments calculations
+#endif
+
+ // Reseting when too small angle
+ if (DeflectionFactor < zeroWhenLower)
+ {
+ if (smoothTime <= Mathf.Epsilon)
+ {
+#if UNITY_EDITOR
+ Deflection = Vector3.zero;
+#endif
+ DeflectionSmooth = 0f;
+ }
+ else
+ {
+#if UNITY_EDITOR
+ Deflection = Vector3.zero;
+#endif
+
+ DeflectionSmooth = Mathf.SmoothDamp(DeflectionSmooth, -Mathf.Epsilon, ref deflectionSmoothVelo, smoothTime / 1.5f, Mathf.Infinity, delta);
+ }
+ }
+ else // Enabling or translating with smooth time
+ {
+ if (smoothTime <= Mathf.Epsilon)
+ {
+#if UNITY_EDITOR
+ Deflection = deflection;
+#endif
+ DeflectionSmooth = 1f;
+ }
+ else
+ {
+#if UNITY_EDITOR
+ Deflection = deflection;
+#endif
+
+ DeflectionSmooth = Mathf.SmoothDamp(DeflectionSmooth, 1f, ref deflectionSmoothVelo, smoothTime, Mathf.Infinity, delta);
+ }
+ }
+
+ if (DeflectionSmooth <= Mathf.Epsilon) return true;
+ else
+ {
+ if (ChildBone.ChildBone != null)
+ DeflectionWorldPosition = ChildBone.ChildBone.ProceduralPosition;
+ else
+ DeflectionWorldPosition = ChildBone.ProceduralPosition;
+
+ return false;
+ }
+ }
+
+
+
+ ///
+ /// Signing bone as deflection point relevant
+ ///
+ /// True when deflection just detrected
+ public bool DeflectionRelevant()
+ {
+ if (DeflectionRelevancy == -1)
+ {
+ DeflectionRelevancy = 3;
+ return true;
+ }
+
+ DeflectionRelevancy = 3;
+ return false;
+ }
+
+
+ /// True when relevancy is high null when it's remove point relevancy false when it's unrelevant
+ public bool? DeflectionRestoreState()
+ {
+ if (DeflectionRelevancy > 0)
+ {
+ DeflectionRelevancy--;
+
+ if (DeflectionRelevancy == 0) // When relevancy hit 0 then remove callback and set to -1
+ {
+ DeflectionRelevancy = -1;
+ return null;
+ }
+ else return true; // True when relevancy > 0
+ }
+ else
+ return false; // Unrelevant deflection state
+ }
+
+
+
+ #endregion
+
+
+ #region Post Processing and others
+
+ ///
+ /// Copying animation parameters from other segment
+ ///
+ internal void ParamsFrom(TailSegment other)
+ {
+ BlendValue = other.BlendValue;
+ ColliderRadius = other.ColliderRadius;
+ Gravity = other.Gravity;
+ LengthMultiplier = other.LengthMultiplier;
+ BoneLength = other.BoneLength;
+ BoneLengthScaled = other.BoneLengthScaled;
+ BoneDimensionsScaled = other.BoneDimensionsScaled;
+ collisionContacts = other.collisionContacts;
+ CollisionHelper = other.CollisionHelper;
+
+ PositionSpeed = other.PositionSpeed;
+ RotationSpeed = other.RotationSpeed;
+ Springiness = other.Springiness;
+ Slithery = other.Slithery;
+ Curling = other.Curling;
+ Slippery = other.Slippery;
+ }
+
+ ///
+ /// Copying all available parameters from other segment
+ ///
+ internal void ParamsFromAll(TailSegment other)
+ {
+ ParamsFrom(other);
+ InitialLocalPosition = other.InitialLocalPosition;
+ InitialLocalRotation = other.InitialLocalRotation;
+ LastFinalPosition = other.LastFinalPosition;
+ LastFinalRotation = other.LastFinalRotation;
+ ProceduralPosition = other.ProceduralPosition;
+ ProceduralPositionWeightBlended = other.ProceduralPositionWeightBlended;
+ TrueTargetRotation = other.TrueTargetRotation;
+ PosRefRotation = other.PosRefRotation;
+ PreviousPosReferenceRotation = other.PreviousPosReferenceRotation;
+ PreviousPosition = other.PreviousPosition;
+ BoneLength = other.BoneLength;
+ BoneDimensionsScaled = other.BoneDimensionsScaled;
+ BoneLengthScaled = other.BoneLengthScaled;
+ LocalOffset = other.LocalOffset;
+ ColliderRadius = other.ColliderRadius;
+ VelocityHelper = other.VelocityHelper;
+ QVelocityHelper = other.QVelocityHelper;
+ PreviousPush = other.PreviousPush;
+ }
+
+ internal void User_ReassignTransform(Transform t)
+ {
+ transform = t;
+ }
+
+ #endregion
+
+
+ #region Resetting
+
+ public void Reset()
+ {
+ PreviousPush = Vector3.zero;
+ VelocityHelper = Vector3.zero;
+ QVelocityHelper = Quaternion.identity;
+
+ if (transform)
+ {
+ ProceduralPosition = transform.position;
+ PosRefRotation = transform.rotation;
+ PreviousPosReferenceRotation = transform.rotation;
+ }
+ else
+ {
+ if (ParentBone.transform)
+ ProceduralPosition = ParentBone.transform.position + ParentToFrontOffset();
+ }
+
+ PreviousPosition = ProceduralPosition;
+ ProceduralPositionWeightBlended = ProceduralPosition;
+ }
+
+ #endregion
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Class.TailSegment.cs.meta b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Class.TailSegment.cs.meta
new file mode 100644
index 000000000..d8f044fac
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Class.TailSegment.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 4c0f1ecbfe3d7aa458e3e48da5898b29
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Extensions.Collision.cs b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Extensions.Collision.cs
new file mode 100644
index 000000000..909768083
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Extensions.Collision.cs
@@ -0,0 +1,576 @@
+using System.Collections.Generic;
+using System.Linq;
+using UnityEngine;
+
+namespace FIMSpace.FTail
+{
+ public partial class TailAnimator2
+ {
+ public enum ECollisionSpace { World_Slow, Selective_Fast }
+ public enum ECollisionMode { m_3DCollision, m_2DCollision }
+
+ [Tooltip("Using some simple calculations to make tail bend on colliders")]
+ public bool UseCollision = false;
+
+ [Tooltip("How collision should be detected, world gives you collision on all world colliders but with more use of cpu (using unity's rigidbodies), 'Selective' gives you possibility to detect collision on selected colliders without using Rigidbodies, it also gives smoother motion (deactivated colliders will still detect collision, unless its game object is disabled)")]
+ public ECollisionSpace CollisionSpace = ECollisionSpace.Selective_Fast;
+ public ECollisionMode CollisionMode = ECollisionMode.m_3DCollision;
+
+ /// Available only when using dynamic world collisions inclusion mode
+ public SphereCollider GeneratedDynamicInclusionCollider { get; private set; }
+ /// Available only when using dynamic world collisions inclusion 2D mode
+ public CircleCollider2D GeneratedDynamicInclusionCollider2D { get; private set; }
+
+ #region Selective Variables
+
+
+ [Tooltip("If you want to stop checking collision if segment collides with one collider\n\nSegment collision with two or more colliders in the same time with this option enabled can result in stuttery motion")]
+ public bool CheapCollision = false;
+
+ [Tooltip("Using trigger collider to include encountered colliders into collide with list")]
+ public bool DynamicWorldCollidersInclusion = false;
+
+ [Tooltip("Radius of trigger collider for dynamic inclusion of colliders")]
+ public float InclusionRadius = 1f;
+ public bool IgnoreMeshColliders = true;
+
+ public List IncludedColliders;
+ public List IncludedColliders2D;
+ /// Colliders always included with 'Dynamic World Colliders Inclusion' mode
+ public List DynamicAlwaysInclude { get; private set; }
+ protected List IncludedCollidersData;
+
+ /// List of collider datas to be checked by every tail segment
+ protected List CollidersDataToCheck;
+
+
+ #endregion
+
+
+ #region World Collision Variables
+
+
+ [Tooltip("Capsules can give much more precise collision detection")]
+ public int CollidersType = 0;
+ public bool CollideWithOtherTails = false;
+ [Tooltip("Collision with colliders even if they're disabled (but game object must be enabled)\nHelpful to setup character limbs collisions without need to create new Layer")]
+ public bool CollideWithDisabledColliders = true;
+
+
+ [Range(0f, 1f)]
+ public float CollisionSlippery = 1f;
+ [Tooltip("If tail colliding objects should fit to colliders (0) or be reflect from them (Reflecting Only with 'Slithery' parameter greater than ~0.2)")]
+ [Range(0f, 1f)]
+ public float ReflectCollision = 0f;
+
+ public AnimationCurve CollidersScaleCurve = AnimationCurve.Linear(0, 1, 1, 1);
+ public float CollidersScaleMul = 6.5f;
+ [Range(0f, 1f)]
+ public float CollisionsAutoCurve = 0.5f;
+
+ public List IgnoredColliders;
+ public List IgnoredColliders2D;
+ public bool CollidersSameLayer = true;
+ [Tooltip("If you add rigidbodies to each tail segment's collider, collision will work on everything but it will be less optimal, you don't have to add here rigidbodies but then you must have not kinematic rigidbodies on objects segments can collide")]
+ public bool CollidersAddRigidbody = true;
+ public float RigidbodyMass = 1f;
+
+ [FPD_Layers]
+ public int CollidersLayer = 0;
+
+
+ #endregion
+
+ void RefreshSegmentsColliders()
+ {
+ if (CollisionSpace == ECollisionSpace.Selective_Fast)
+ {
+ if (TailSegments != null)
+ if (TailSegments.Count > 1)
+ for (int i = 0; i < TailSegments.Count; i++)
+ TailSegments[i].ColliderRadius = GetColliderSphereRadiusFor(i);
+ }
+ }
+
+
+ void BeginCollisionsUpdate()
+ {
+ if (CollisionSpace == ECollisionSpace.Selective_Fast)
+ {
+ RefreshIncludedCollidersDataList();
+
+ // Letting every tail segment check only enabled colliders by game object
+ CollidersDataToCheck.Clear();
+
+ for (int i = 0; i < IncludedCollidersData.Count; i++)
+ {
+ if (IncludedCollidersData[i].Transform == null) { forceRefreshCollidersData = true; break; }
+
+ if (IncludedCollidersData[i].Transform.gameObject.activeInHierarchy)
+ {
+
+ // Collisions with all even disabled colliders
+ if (CollideWithDisabledColliders)
+ {
+ IncludedCollidersData[i].RefreshColliderData();
+ CollidersDataToCheck.Add(IncludedCollidersData[i]);
+ }
+ else
+ {
+ if (CollisionMode == ECollisionMode.m_3DCollision)
+ {
+ if (IncludedCollidersData[i].Collider == null)
+ {
+ forceRefreshCollidersData = true;
+ break;
+ }
+
+ // If we want to collide even with disabled colliders
+ if (IncludedCollidersData[i].Collider.enabled)
+ {
+ IncludedCollidersData[i].RefreshColliderData();
+ CollidersDataToCheck.Add(IncludedCollidersData[i]);
+ }
+ }
+ else
+ {
+ if ( IncludedCollidersData[i].Collider2D == null)
+ {
+ forceRefreshCollidersData = true;
+ break;
+ }
+
+ if (IncludedCollidersData[i].Collider2D.enabled)
+ {
+ IncludedCollidersData[i].RefreshColliderData();
+ CollidersDataToCheck.Add(IncludedCollidersData[i]);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ ///
+ /// Generating colliders on tail with provided settings
+ /// If collision space is world then rigidbody colliders are added, if selective no additional components are needed
+ ///
+ void SetupSphereColliders()
+ {
+ if (CollisionSpace == ECollisionSpace.World_Slow)
+ {
+ for (int i = 1; i < _TransformsGhostChain.Count; i++)
+ {
+ if (CollidersSameLayer) _TransformsGhostChain[i].gameObject.layer = gameObject.layer; else _TransformsGhostChain[i].gameObject.layer = CollidersLayer;
+ }
+
+ if (CollidersType != 0)
+ {
+ for (int i = 1; i < _TransformsGhostChain.Count - 1; i++)
+ {
+ CapsuleCollider caps = _TransformsGhostChain[i].gameObject.AddComponent();
+
+ TailCollisionHelper tcol = _TransformsGhostChain[i].gameObject.AddComponent().Init(CollidersAddRigidbody, RigidbodyMass);
+ tcol.TailCollider = caps;
+ tcol.Index = i;
+ tcol.ParentTail = this;
+
+ caps.radius = GetColliderSphereRadiusFor(_TransformsGhostChain, i);
+ caps.direction = 2;
+ caps.height = (_TransformsGhostChain[i].position - _TransformsGhostChain[i + 1].position).magnitude * 2f - caps.radius;
+ caps.center = _TransformsGhostChain[i].InverseTransformPoint(Vector3.Lerp(_TransformsGhostChain[i].position, _TransformsGhostChain[i + 1].position, 0.5f));
+
+ TailSegments[i].ColliderRadius = caps.radius;
+ TailSegments[i].CollisionHelper = tcol;
+ }
+ }
+ else
+ {
+ for (int i = 1; i < _TransformsGhostChain.Count; i++)
+ {
+ SphereCollider s = _TransformsGhostChain[i].gameObject.AddComponent();
+ TailCollisionHelper tcol = _TransformsGhostChain[i].gameObject.AddComponent().Init(CollidersAddRigidbody, RigidbodyMass);
+ tcol.TailCollider = s;
+ tcol.Index = i;
+ tcol.ParentTail = this;
+ s.radius = GetColliderSphereRadiusFor(_TransformsGhostChain, i);
+ TailSegments[i].ColliderRadius = s.radius;
+ TailSegments[i].CollisionHelper = tcol;
+ }
+ }
+ }
+ else
+ {
+ for (int i = 0; i < _TransformsGhostChain.Count; i++)
+ TailSegments[i].ColliderRadius = GetColliderSphereRadiusFor(i);
+
+ IncludedCollidersData = new List();
+ CollidersDataToCheck = new List();
+
+ #region Dynamic inclusion preparations
+
+ if (DynamicWorldCollidersInclusion)
+ {
+ if (CollisionMode == ECollisionMode.m_3DCollision)
+ for (int i = 0; i < IncludedColliders.Count; i++) DynamicAlwaysInclude.Add(IncludedColliders[i]);
+ else
+ for (int i = 0; i < IncludedColliders2D.Count; i++) DynamicAlwaysInclude.Add(IncludedColliders2D[i]);
+
+ Transform middleSegm = TailSegments[TailSegments.Count / 2].transform;
+ float scaleRef = Vector3.Distance(_TransformsGhostChain[0].position, _TransformsGhostChain[_TransformsGhostChain.Count - 1].position);
+
+ TailCollisionHelper cHelper = middleSegm.gameObject.AddComponent();
+ cHelper.ParentTail = this;
+ SphereCollider triggerC = null;
+ CircleCollider2D triggerC2D = null;
+
+ if (CollisionMode == ECollisionMode.m_3DCollision)
+ {
+ triggerC = middleSegm.gameObject.AddComponent();
+ triggerC.isTrigger = true;
+ cHelper.TailCollider = triggerC;
+ GeneratedDynamicInclusionCollider = triggerC;
+ }
+ else
+ {
+ triggerC2D = middleSegm.gameObject.AddComponent();
+ triggerC2D.isTrigger = true;
+ cHelper.TailCollider2D = triggerC2D;
+ GeneratedDynamicInclusionCollider2D = triggerC2D;
+ }
+
+ cHelper.Init(true, 1f, true);
+
+ float scale = Mathf.Abs(middleSegm.transform.lossyScale.z);
+ if (scale == 0f) scale = 1f;
+ if (triggerC != null) triggerC.radius = (scaleRef / scale) * InclusionRadius;
+ else triggerC2D.radius = (scaleRef / scale) * InclusionRadius;
+
+ if (CollidersSameLayer)
+ middleSegm.gameObject.layer = gameObject.layer;
+ else
+ middleSegm.gameObject.layer = CollidersLayer;
+ }
+
+ #endregion
+
+ RefreshIncludedCollidersDataList();
+ }
+
+ collisionInitialized = true;
+ }
+
+
+ ///
+ /// Collision data sent by single tail segment
+ ///
+ internal void CollisionDetection(int index, Collision collision)
+ {
+ TailSegments[index].collisionContacts = collision;
+ }
+
+
+ ///
+ /// Exitting collision
+ ///
+ internal void ExitCollision(int index)
+ {
+ TailSegments[index].collisionContacts = null;
+ }
+
+
+ ///
+ /// Use saved collision contact in right moment when uxecuting update methods
+ ///
+ protected bool UseCollisionContact(int index, ref Vector3 pos)
+ {
+ if (TailSegments[index].collisionContacts == null) return false;
+ if (TailSegments[index].collisionContacts.contacts.Length == 0) return false; // In newest Unity 2018 versions 'Collision' class is generated even there are no collision contacts
+
+ Collision collision = TailSegments[index].collisionContacts;
+ float thisCollRadius = FImp_ColliderData_Sphere.CalculateTrueRadiusOfSphereCollider(TailSegments[index].transform, TailSegments[index].ColliderRadius) * 0.95f;
+
+ if (collision.collider)
+ {
+ SphereCollider collidedSphere = collision.collider as SphereCollider;
+
+ // If we collide sphere we can calculate precise segment offset for it
+ if (collidedSphere)
+ {
+ FImp_ColliderData_Sphere.PushOutFromSphereCollider(collidedSphere, thisCollRadius, ref pos, Vector3.zero);
+ }
+ else
+ {
+ CapsuleCollider collidedCapsule = collision.collider as CapsuleCollider;
+
+ // If we collide capsule we can calculate precise segment offset for it
+ if (collidedCapsule)
+ {
+ FImp_ColliderData_Capsule.PushOutFromCapsuleCollider(collidedCapsule, thisCollRadius, ref pos, Vector3.zero);
+ }
+ else
+ {
+ BoxCollider collidedBox = collision.collider as BoxCollider;
+
+ // If we collide box we can calculate precise segment offset for it
+ if (collidedBox)
+ {
+ if (TailSegments[index].CollisionHelper.RigBody)
+ {
+ if (collidedBox.attachedRigidbody)
+ {
+ if (TailSegments[index].CollisionHelper.RigBody.mass > 1f)
+ {
+ FImp_ColliderData_Box.PushOutFromBoxCollider(collidedBox, collision, thisCollRadius, ref pos);
+ Vector3 pusherPos = pos;
+ FImp_ColliderData_Box.PushOutFromBoxCollider(collidedBox, thisCollRadius, ref pos);
+
+ pos = Vector3.Lerp(pos, pusherPos, TailSegments[index].CollisionHelper.RigBody.mass / 5f);
+ }
+ else
+ FImp_ColliderData_Box.PushOutFromBoxCollider(collidedBox, thisCollRadius, ref pos);
+ }
+ else
+ FImp_ColliderData_Box.PushOutFromBoxCollider(collidedBox, thisCollRadius, ref pos);
+ }
+ else
+ FImp_ColliderData_Box.PushOutFromBoxCollider(collidedBox, thisCollRadius, ref pos);
+ }
+ else // If we collide mesh we can't calculate very precise segment offset but we can support it in some way
+ {
+ MeshCollider collidedMesh = collision.collider as MeshCollider;
+ if (collidedMesh)
+ {
+ FImp_ColliderData_Mesh.PushOutFromMeshCollider(collidedMesh, collision, thisCollRadius, ref pos);
+ }
+ else // If we collide terrain we can calculate very precise segment offset because terrain not rotates
+ {
+ TerrainCollider terrain = collision.collider as TerrainCollider;
+ FImp_ColliderData_Terrain.PushOutFromTerrain(terrain, thisCollRadius, ref pos);
+ }
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+
+
+ ///
+ /// Refreshing colliders data for included colliders when it's needed
+ ///
+ public void RefreshIncludedCollidersDataList()
+ {
+ bool refr = false;
+
+ if (CollisionMode == ECollisionMode.m_3DCollision)
+ {
+ if (IncludedColliders.Count != IncludedCollidersData.Count || forceRefreshCollidersData)
+ {
+ IncludedCollidersData.Clear();
+
+ for (int i = IncludedColliders.Count - 1; i >= 0; i--)
+ {
+ if (IncludedColliders[i] == null) { IncludedColliders.RemoveAt(i); continue; }
+ FImp_ColliderData_Base colData = FImp_ColliderData_Base.GetColliderDataFor(IncludedColliders[i]);
+ IncludedCollidersData.Add(colData);
+ }
+
+ refr = true;
+ }
+ }
+ else
+ {
+ if (IncludedColliders2D.Count != IncludedCollidersData.Count || forceRefreshCollidersData)
+ {
+ IncludedCollidersData.Clear();
+
+ for (int i = IncludedColliders2D.Count - 1; i >= 0; i--)
+ {
+ if (IncludedColliders2D[i] == null) { IncludedColliders2D.RemoveAt(i); continue; }
+ FImp_ColliderData_Base colData = FImp_ColliderData_Base.GetColliderDataFor(IncludedColliders2D[i]);
+ IncludedCollidersData.Add(colData);
+ }
+
+ refr = true;
+ }
+ }
+
+ if (refr) forceRefreshCollidersData = false;
+ }
+
+
+ ///
+ /// Pushing tail segment from detected collider
+ ///
+ public bool PushIfSegmentInsideCollider(TailSegment bone, ref Vector3 targetPoint)
+ {
+ bool pushed = false;
+
+ if (!CheapCollision) // Detailed Collision
+ {
+ for (int i = 0; i < CollidersDataToCheck.Count; i++)
+ {
+ bool push = CollidersDataToCheck[i].PushIfInside(ref targetPoint, bone.GetRadiusScaled(), Vector3.zero);
+ if (!pushed) if (push)
+ {
+ pushed = true;
+ bone.LatestSelectiveCollision = CollidersDataToCheck[i];
+ }
+ }
+ }
+ else
+ {
+ for (int i = 0; i < CollidersDataToCheck.Count; i++)
+ {
+ if (CollidersDataToCheck[i].PushIfInside(ref targetPoint, bone.GetRadiusScaled(), Vector3.zero))
+ {
+ bone.LatestSelectiveCollision = CollidersDataToCheck[i];
+ return true;
+ }
+ }
+ }
+
+ return pushed;
+ }
+
+
+ ///
+ /// Calculating automatically scale for colliders on tail, which will be automatically assigned after initialization
+ ///
+ protected float GetColliderSphereRadiusFor(int i)
+ {
+ TailSegment tailPoint = TailSegments[i];
+ float refDistance = 1f;
+
+ if (i >= _TransformsGhostChain.Count) return refDistance;
+
+ if (_TransformsGhostChain.Count > 1)
+ {
+ refDistance = Vector3.Distance(_TransformsGhostChain[1].position, _TransformsGhostChain[0].position);
+ }
+
+ float singleScale = refDistance;
+ if (i != 0) singleScale = Mathf.Lerp(refDistance, Vector3.Distance(_TransformsGhostChain[i - 1].position, _TransformsGhostChain[i].position) * 0.5f, CollisionsAutoCurve);
+
+ float div = _TransformsGhostChain.Count - 1;
+ if (div <= 0f) div = 1f;
+ float step = 1f / div;
+
+ return 0.5f * singleScale * CollidersScaleMul * CollidersScaleCurve.Evaluate(step * (float)i);
+ }
+
+
+ ///
+ /// Calculating automatically scale for colliders on tail, which will be automatically assigned after initialization
+ ///
+ protected float GetColliderSphereRadiusFor(List transforms, int i)
+ {
+ float refDistance = 1f;
+ if (transforms.Count > 1) refDistance = Vector3.Distance(_TransformsGhostChain[1].position, _TransformsGhostChain[0].position);
+
+ float nextDistance = refDistance;
+ if (i != 0) nextDistance = Vector3.Distance(_TransformsGhostChain[i - 1].position, _TransformsGhostChain[i].position);
+
+ float singleScale = Mathf.Lerp(refDistance, nextDistance * 0.5f, CollisionsAutoCurve);
+ float step = 1f / (float)(transforms.Count - 1);
+ return 0.5f * singleScale * CollidersScaleMul * CollidersScaleCurve.Evaluate(step * (float)i);
+ }
+
+
+ ///
+ /// Adding collider to included colliders list
+ ///
+ public void AddCollider(Collider collider)
+ {
+ if (IncludedColliders.Contains(collider)) return;
+ IncludedColliders.Add(collider);
+ }
+
+ ///
+ /// Adding collider to included colliders list
+ ///
+ public void AddCollider(Collider2D collider)
+ {
+ if (IncludedColliders2D.Contains(collider)) return;
+ IncludedColliders2D.Add(collider);
+ }
+
+ ///
+ /// Checking if colliders list don't have duplicates
+ ///
+ public void CheckForColliderDuplicatesAndNulls()
+ {
+ for (int i = 0; i < IncludedColliders.Count; i++)
+ {
+ Collider col = IncludedColliders[i];
+ int count = IncludedColliders.Count(o => o == col);
+
+ if (count > 1)
+ {
+ IncludedColliders.RemoveAll(o => o == col);
+ IncludedColliders.Add(col);
+ }
+ }
+
+
+ for (int i = IncludedColliders.Count - 1; i >= 0; i--)
+ {
+ if (IncludedColliders[i] == null) IncludedColliders.RemoveAt(i);
+ }
+ }
+
+ public void CheckForColliderDuplicatesAndNulls2D()
+ {
+ for (int i = 0; i < IncludedColliders2D.Count; i++)
+ {
+ Collider2D col = IncludedColliders2D[i];
+ int count = IncludedColliders2D.Count(o => o == col);
+
+ if (count > 1)
+ {
+ IncludedColliders2D.RemoveAll(o => o == col);
+ IncludedColliders2D.Add(col);
+ }
+ }
+ }
+
+
+ void TailCalculations_ComputeSegmentCollisions(TailSegment bone, ref Vector3 position)
+ {
+ // Computing collision contact timer
+ if (bone.CollisionContactFlag) bone.CollisionContactFlag = false;
+ else if (bone.CollisionContactRelevancy > 0f) bone.CollisionContactRelevancy -= justDelta;
+
+ if (CollisionSpace == ECollisionSpace.Selective_Fast)
+ {
+ // Setting collision contact flag
+ if (PushIfSegmentInsideCollider(bone, ref position))
+ {
+ bone.CollisionContactFlag = true;
+ bone.CollisionContactRelevancy = justDelta * 7f;
+ bone.ChildBone.CollisionContactRelevancy = Mathf.Max(bone.ChildBone.CollisionContactRelevancy, justDelta * 3.5f);
+ if (bone.ChildBone.ChildBone != null) bone.ChildBone.ChildBone.CollisionContactRelevancy = Mathf.Max(bone.ChildBone.CollisionContactRelevancy, justDelta * 3f);
+ //bone.ParentBone.CollisionContactRelevancy = Mathf.Max(bone.ParentBone.CollisionContactRelevancy, delta * 3f);
+ }
+ }
+ else
+ {
+ // Setting collision contact flag
+ if (UseCollisionContact(bone.Index, ref position))
+ {
+ bone.CollisionContactFlag = true;
+ bone.CollisionContactRelevancy = justDelta * 7f;
+ bone.ChildBone.CollisionContactRelevancy = Mathf.Max(bone.ChildBone.CollisionContactRelevancy, justDelta * 3.5f);
+ if (bone.ChildBone.ChildBone != null) bone.ChildBone.ChildBone.CollisionContactRelevancy = Mathf.Max(bone.ChildBone.CollisionContactRelevancy, justDelta * 3f);
+ //bone.ParentBone.CollisionContactRelevancy = Mathf.Max(bone.ParentBone.CollisionContactRelevancy, delta * 2f);
+ }
+ }
+ }
+
+
+ }
+}
\ No newline at end of file
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Extensions.Collision.cs.meta b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Extensions.Collision.cs.meta
new file mode 100644
index 000000000..7fa9a8474
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Extensions.Collision.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: d17f10109a8683944b551359096896ac
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Extensions.Expert.cs b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Extensions.Expert.cs
new file mode 100644
index 000000000..856498550
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Extensions.Expert.cs
@@ -0,0 +1,195 @@
+using UnityEngine;
+
+namespace FIMSpace.FTail
+{
+ public partial class TailAnimator2
+ {
+ public bool UseSlitheryCurve = false;
+ [FPD_FixedCurveWindow(0, 0f, 1f, 1.2f, .1f, 0.8f, 1f, 0.9f)]
+ public AnimationCurve SlitheryCurve = AnimationCurve.EaseInOut(0f, .75f, 1f, 1f);
+ float lastSlithery = -1f;
+ Keyframe[] lastSlitheryCurvKeys;
+
+ public bool UseCurlingCurve = false;
+ [FPD_FixedCurveWindow(0, 0f, 1f, 1f, .65f, 0.4f, 1f, 0.9f)]
+ public AnimationCurve CurlingCurve = AnimationCurve.EaseInOut(0f, .7f, 1f, 0.3f);
+ float lastCurling = -1f;
+ Keyframe[] lastCurlingCurvKeys;
+
+ public bool UseSpringCurve = false;
+ [FPD_FixedCurveWindow(0, 0, 1f, 1f, 0.9f, 0.7f, 0.2f, 0.9f)]
+ public AnimationCurve SpringCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 0f);
+ float lastSpringiness = -1f;
+ Keyframe[] lastSpringCurvKeys;
+
+ public bool UseSlipperyCurve = false;
+ [FPD_FixedCurveWindow(0, 0, 1f, 1f, 0.2f, 0.9f, 0.6f, 0.9f)]
+ public AnimationCurve SlipperyCurve = AnimationCurve.EaseInOut(0f, .7f, 1f, 1f);
+ float lastSlippery = -1f;
+ Keyframe[] lastSlipperyCurvKeys;
+
+ public bool UsePosSpeedCurve = false;
+ [FPD_FixedCurveWindow(0, 0, 1f, 1f, .2f, 1f, 0.3f, .9f)]
+ public AnimationCurve PosCurve = AnimationCurve.EaseInOut(0f, .7f, 1f, 1f);
+ float lastPosSpeeds = -1f;
+ Keyframe[] lastPosCurvKeys;
+
+ public bool UseRotSpeedCurve = false;
+ [FPD_FixedCurveWindow(0, 0, 1f, 1f, 0.7f, 0.7f, 0.7f, 0.9f)]
+ public AnimationCurve RotCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0.9f);
+ float lastRotSpeeds = -1f;
+ Keyframe[] lastRotCurvKeys;
+
+
+ [Tooltip("Spreading Tail Animator motion weight over bones")]
+ public bool UsePartialBlend = false;
+ [FPD_FixedCurveWindow(0, 0, 1f, 1f, 0.2f, .5f, 0.85f)]
+ public AnimationCurve BlendCurve = AnimationCurve.EaseInOut(0f, .95f, 1f, .45f);
+ float lastTailAnimatorAmount = -1f;
+ Keyframe[] lastBlendCurvKeys;
+ TailSegment _ex_bone;
+
+
+ void ExpertParamsUpdate()
+ {
+ Expert_UpdatePosSpeed();
+ Expert_UpdateRotSpeed();
+ Expert_UpdateSpringiness();
+ Expert_UpdateSlithery();
+ Expert_UpdateCurling();
+ Expert_UpdateSlippery();
+ Expert_UpdateBlending();
+ }
+
+
+ void ExpertCurvesEndUpdate()
+ {
+ lastPosSpeeds = ReactionSpeed;
+ if (!UsePosSpeedCurve) if (lastPosCurvKeys != null) { lastPosCurvKeys = null; lastPosSpeeds += 0.001f; }
+
+ lastRotSpeeds = RotationRelevancy;
+ if (!UseRotSpeedCurve) if (lastRotCurvKeys != null) { lastRotCurvKeys = null; lastRotSpeeds += 0.001f; }
+
+ lastSpringiness = Springiness;
+ if (!UseSpringCurve) if (lastSpringCurvKeys != null) { lastSpringCurvKeys = null; lastSpringiness += 0.001f; }
+
+ lastSlithery = Slithery;
+ if (!UseSlitheryCurve) if (lastSlitheryCurvKeys != null) { lastSlitheryCurvKeys = null; lastSlithery += 0.001f; }
+
+ lastCurling = Curling;
+ if (!UseCurlingCurve) if (lastCurlingCurvKeys != null) { lastCurlingCurvKeys = null; lastCurling += 0.001f; }
+
+ lastSlippery = CollisionSlippery;
+ if (!UseSlipperyCurve) if (lastSlipperyCurvKeys != null) { lastSlipperyCurvKeys = null; lastSlippery += 0.001f; }
+
+ lastTailAnimatorAmount = TailAnimatorAmount;
+ if (!UsePartialBlend) if (lastBlendCurvKeys != null) { lastBlendCurvKeys = null; lastTailAnimatorAmount += 0.001f; }
+ }
+
+
+ void Expert_UpdatePosSpeed()
+ {
+ if (UsePosSpeedCurve)
+ {
+ //if (KeysChanged(PosCurve.keys, lastPosCurvKeys)) // for (int i = 0; i < TailBones.Count; i++) TailBones[i].PositionSpeed = GetValueFromCurve(i, PosCurve);
+ { _ex_bone = TailSegments[0]; while (_ex_bone != null) { _ex_bone.PositionSpeed = PosCurve.Evaluate(_ex_bone.IndexOverlLength); _ex_bone = _ex_bone.ChildBone; } }
+ }
+ else
+ {
+ if (lastPosSpeeds != ReactionSpeed) // for (int i = 0; i < TailBones.Count; i++) TailBones[i].PositionSpeed = ReactionSpeed;
+ { _ex_bone = TailSegments[0]; while (_ex_bone != null) { _ex_bone.PositionSpeed = ReactionSpeed; _ex_bone = _ex_bone.ChildBone; } }
+ }
+ }
+
+
+ void Expert_UpdateRotSpeed()
+ {
+ if (UseRotSpeedCurve)
+ {
+ //if (KeysChanged(RotCurve.keys, lastRotCurvKeys)) //for (int i = 0; i < TailBones.Count; i++) TailBones[i].RotationSpeed = GetValueFromCurve(i, RotCurve);
+ { _ex_bone = TailSegments[0]; while (_ex_bone != null) { _ex_bone.RotationSpeed = RotCurve.Evaluate(_ex_bone.IndexOverlLength); _ex_bone = _ex_bone.ChildBone; } }
+ }
+ else
+ {
+ if (lastRotSpeeds != RotationRelevancy) //for (int i = 0; i < TailBones.Count; i++) TailBones[i].RotationSpeed = RotationRelevancy;
+ { _ex_bone = TailSegments[0]; while (_ex_bone != null) { _ex_bone.RotationSpeed = RotationRelevancy; _ex_bone = _ex_bone.ChildBone; } }
+ }
+ }
+
+
+ void Expert_UpdateSpringiness()
+ {
+ if (UseSpringCurve)
+ {
+ //if (KeysChanged(SpringCurve.keys, lastSpringCurvKeys)) //for (int i = 0; i < TailBones.Count; i++) TailBones[i].Springiness = GetValueFromCurve(i, SpringCurve);
+ { _ex_bone = TailSegments[0]; while (_ex_bone != null) { _ex_bone.Springiness = SpringCurve.Evaluate(_ex_bone.IndexOverlLength); _ex_bone = _ex_bone.ChildBone; } }
+ }
+ else
+ {
+ if (lastSpringiness != Springiness) //for (int i = 0; i < TailBones.Count; i++) TailBones[i].Springiness = Springiness;
+ { _ex_bone = TailSegments[0]; while (_ex_bone != null) { _ex_bone.Springiness = Springiness; _ex_bone = _ex_bone.ChildBone; } }
+ }
+ }
+
+
+ void Expert_UpdateSlithery()
+ {
+ if (UseSlitheryCurve)
+ {
+ //if (KeysChanged(SlitheryCurve, lastSlitheryCurvKeys)) //for (int i = 0; i < TailBones.Count; i++) TailBones[i].Slithery = GetValueFromCurve(i, SlitheryCurve);
+ { _ex_bone = TailSegments[0]; while (_ex_bone != null) { _ex_bone.Slithery = SlitheryCurve.Evaluate(_ex_bone.IndexOverlLength); _ex_bone = _ex_bone.ChildBone; } }
+ }
+ else
+ {
+ if (lastSlithery != Slithery)
+ { _ex_bone = TailSegments[0]; while (_ex_bone != null) { _ex_bone.Slithery = Slithery; _ex_bone = _ex_bone.ChildBone; } }
+ }
+ }
+
+
+ void Expert_UpdateCurling()
+ {
+ if (UseCurlingCurve)
+ {
+ //if (KeysChanged(CurlingCurve.keys, lastCurlingCurvKeys)) //for (int i = 0; i < TailBones.Count; i++) TailBones[i].Curling = GetValueFromCurve(i, CurlingCurve);
+ { _ex_bone = TailSegments[0]; while (_ex_bone != null) { _ex_bone.Curling = CurlingCurve.Evaluate(_ex_bone.IndexOverlLength); _ex_bone = _ex_bone.ChildBone; } }
+ }
+ else
+ {
+ if (lastCurling != Curling)
+ { _ex_bone = TailSegments[0]; while (_ex_bone != null) { _ex_bone.Curling = Curling; _ex_bone = _ex_bone.ChildBone; } }
+ }
+ }
+
+
+ void Expert_UpdateSlippery()
+ {
+ if (UseSlipperyCurve)
+ {
+ //if (KeysChanged(SlipperyCurve.keys, lastSlipperyCurvKeys)) //for (int i = 0; i < TailBones.Count; i++) TailBones[i].Slippery = GetValueFromCurve(i, SlipperyCurve);
+ { _ex_bone = TailSegments[0]; while (_ex_bone != null) { _ex_bone.Slippery = SlipperyCurve.Evaluate(_ex_bone.IndexOverlLength); _ex_bone = _ex_bone.ChildBone; } }
+ }
+ else
+ {
+ if (lastSlippery != CollisionSlippery) //for (int i = 0; i < TailBones.Count; i++) TailBones[i].Slippery = CollisionSlippery;
+ { _ex_bone = TailSegments[0]; while (_ex_bone != null) { _ex_bone.Slippery = CollisionSlippery; _ex_bone = _ex_bone.ChildBone; } }
+ }
+ }
+
+
+ void Expert_UpdateBlending()
+ {
+ if (UsePartialBlend)
+ {
+ //if (KeysChanged(BlendCurve.keys, lastBlendCurvKeys)) // for (int i = 0; i < TailBones.Count; i++) TailBones[i].BlendValue = GetValueFromCurve(i, BlendCurve);//Mathf.Clamp(Mathf.Pow(GetValueFromCurve(i, BlendCurve), .3f /*3*/), 0f, 1.5f);
+ { _ex_bone = TailSegments[0]; while (_ex_bone != null) { _ex_bone.BlendValue = BlendCurve.Evaluate(_ex_bone.IndexOverlLength); _ex_bone = _ex_bone.ChildBone; } }
+ }
+ else
+ {
+ if (lastTailAnimatorAmount != TailAnimatorAmount)
+ { _ex_bone = TailSegments[0]; while (_ex_bone != null) { _ex_bone.BlendValue = TailAnimatorAmount; _ex_bone = _ex_bone.ChildBone; } }
+ }
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Extensions.Expert.cs.meta b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Extensions.Expert.cs.meta
new file mode 100644
index 000000000..2159cd688
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Extensions.Expert.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 18157dba56a9a3f42a851b679615af5d
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Extensions.IK.cs b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Extensions.IK.cs
new file mode 100644
index 000000000..691c355c4
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Extensions.IK.cs
@@ -0,0 +1,236 @@
+using FIMSpace.FTools;
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace FIMSpace.FTail
+{
+ public partial class TailAnimator2
+ {
+ // IK Definition
+ public bool UseIK = false;
+ bool ikInitialized = false;
+ [SerializeField] FIK_CCDProcessor IK;
+
+ // IK Parameters
+ [Tooltip("Target object to follow by IK")]
+ public Transform IKTarget;
+ [Tooltip("Making end bone be rotated as IK target object")]
+ [Range(0f, 1f)] public float IKAlignEndWithTarget = 0f;
+
+ public bool IKAutoWeights = true;
+ [Range(0f, 1f)]
+ public float IKBaseReactionWeight = .65f;
+ [FPD_FixedCurveWindow(0, 0, 1f, 1f, 0.2f, .5f, 0.85f)]
+ public AnimationCurve IKReactionWeightCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, .25f);
+
+ public bool IKAutoAngleLimits = true;
+ //[Range(0f, 181f)]
+ [FPD_Suffix(0, 181, FPD_SuffixAttribute.SuffixMode.FromMinToMaxRounded, "°")]
+ public float IKAutoAngleLimit = 40f;
+ [Tooltip("If ik process should work referencing to previously computed CCDIK pose (can be more precise but need more adjusting in weights and angle limits)")]
+ public bool IKContinousSolve = false;
+ [Tooltip("Inverting ik iteration order to generate different pose results - more straight towards target")]
+ public bool IkInvertOrder = false;
+
+ [FPD_Suffix(0f, 1f)]
+ [Tooltip("How much IK motion sohuld be used in tail animator motion -> 0: turned off")]
+ public float IKBlend = 1f;
+ [FPD_Suffix(0f, 1f)]
+ [Tooltip("If syncing with animator then applying motion of keyframe animation for IK")]
+ public float IKAnimatorBlend = 0.5f;
+
+ [Range(1, 32)]
+ [Tooltip("How much iterations should do CCDIK algorithm in one frame")]
+ public int IKReactionQuality = 2;
+ [Range(0f, 1f)]
+ [Tooltip("Smoothing reactions in CCD IK algorithm")]
+ public float IKSmoothing = .0f;
+ [Range(0f, 1.5f)]
+ public float IKStretchToTarget = 0f;
+ [FPD_FixedCurveWindow(0, 0, 1f, 1f, 0.9f, .4f, 0.5f)]
+ public AnimationCurve IKStretchCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f);
+
+ public List IKLimitSettings;
+ public bool IKSelectiveChain = false;
+
+ void InitIK()
+ {
+ if (IKSelectiveChain == false)
+ IK = new FIK_CCDProcessor(_TransformsGhostChain.ToArray());
+ else
+ {
+ List ikChain = new List();
+ if (IKLimitSettings.Count != _TransformsGhostChain.Count) ikChain = _TransformsGhostChain;
+ else
+ {
+ for (int i = 0; i < _TransformsGhostChain.Count; i++)
+ {
+ if (IKLimitSettings[i].UseInChain)
+ ikChain.Add(_TransformsGhostChain[i]);
+ }
+ }
+
+ IK = new FIK_CCDProcessor(ikChain.ToArray());
+ }
+
+ if (IKAutoWeights) IK.AutoWeightBones(IKBaseReactionWeight); else IK.AutoWeightBones(IKReactionWeightCurve);
+ if (IKAutoAngleLimits) IK.AutoLimitAngle(IKAutoAngleLimit, 4f + IKAutoAngleLimit / 15f);
+
+ if (IKSelectiveChain == false)
+ IK.Init(_TransformsGhostChain[0]);
+ else
+ IK.Init(IK.Bones[0].transform);
+
+ ikInitialized = true;
+
+ IK_ApplyLimitBoneSettings();
+ }
+
+
+ Vector3? _IKCustomPos = null;
+ public void IKSetCustomPosition(Vector3? tgt)
+ {
+ _IKCustomPos = tgt;
+ }
+
+ void UpdateIK()
+ {
+ if (!ikInitialized) InitIK();
+ if (IKBlend <= Mathf.Epsilon) return;
+
+ if (_IKCustomPos != null) IK.IKTargetPosition = _IKCustomPos.Value;
+ else
+ {
+ if (IKTarget == null) IK.IKTargetPosition = TailSegments[TailSegments.Count - 1].ProceduralPosition;
+ else IK.IKTargetPosition = IKTarget.position;
+ }
+
+ IK.Invert = IkInvertOrder;
+ IK.IKWeight = IKBlend;
+ IK.SyncWithAnimator = IKAnimatorBlend; //else IK.SyncWithAnimator = 0f;
+ IK.ReactionQuality = IKReactionQuality;
+ IK.Smoothing = IKSmoothing;
+ IK.StretchToTarget = IKStretchToTarget;
+ IK.StretchCurve = IKStretchCurve;
+ IK.ContinousSolving = IKContinousSolve;
+ if (IK.StretchToTarget > 0f) IK.ContinousSolving = false;
+ if (Axis2D == 3) IK.Use2D = true; else IK.Use2D = false;
+
+ IK.Update();
+
+ if (IKAlignEndWithTarget > 0f && IKTarget != null && IK.Bones.Length > 1)
+ {
+ var lastBone = IK.Bones[IK.Bones.Length - 1];
+
+ #region Old faster code but for two axes only
+
+ //Quaternion targetRotation = Quaternion.FromToRotation((lastBone.transform.position - lastBone.transform.parent.position).normalized, IKTarget.forward);
+ //targetRotation = targetRotation * lastBone.transform.rotation;
+ //if (IKAlignEndWithTarget < 1f) targetRotation = Quaternion.Slerp(lastBone.transform.rotation, targetRotation, IKAlignEndWithTarget);
+ //lastBone.transform.rotation = targetRotation;
+
+ #endregion
+
+ Vector3 boneForward = (lastBone.transform.position - lastBone.transform.parent.position).normalized;
+ Vector3 boneUp = lastBone.transform.up;
+ Vector3 targetForward = IKTarget.forward;
+ Vector3 targetUp = IKTarget.up;
+
+ Quaternion boneRot = Quaternion.LookRotation(boneForward, boneUp);
+ Quaternion targetRot = Quaternion.LookRotation(targetForward, targetUp);
+ Quaternion delta = targetRot * Quaternion.Inverse(boneRot);
+
+ Quaternion finalRot = delta * lastBone.transform.rotation;
+ if (IKAlignEndWithTarget < 1f) finalRot = Quaternion.Slerp(lastBone.transform.rotation, finalRot, IKAlignEndWithTarget);
+ lastBone.transform.rotation = finalRot;
+ }
+
+ if (DetachChildren)
+ {
+ TailSegment child = TailSegments[0];
+
+ child = TailSegments[1];
+ if (IncludeParent == false)
+ {
+ child.RefreshKeyLocalPositionAndRotation(child.InitialLocalPosition, child.InitialLocalRotation);
+ child = TailSegments[2];
+ }
+
+ while (child != GhostChild)
+ {
+ child.RefreshKeyLocalPositionAndRotation(child.InitialLocalPosition, child.InitialLocalRotation);
+ child = child.ChildBone;
+ }
+ }
+ else
+ {
+ TailSegment child = TailSegments[0];
+ while (child != GhostChild)
+ {
+ child.RefreshKeyLocalPositionAndRotation();
+ child = child.ChildBone;
+ }
+ }
+
+ }
+
+
+ ///
+ /// FC: Helper class to manage ik bones settings
+ ///
+ [System.Serializable]
+ public class IKBoneSettings
+ {
+ [Range(0f, 181f)]
+ public float AngleLimit = 45f;
+ [Range(0f, 181f)]
+ public float TwistAngleLimit = 5f;
+
+ public bool UseInChain = true;
+ }
+
+
+ ///
+ /// Applying changes to IK bones only when changes occuring
+ ///
+ public void IK_ApplyLimitBoneSettings()
+ {
+ if (!IKAutoAngleLimits)
+ {
+ if (IKLimitSettings.Count != _TransformsGhostChain.Count)
+ IK_RefreshLimitSettingsContainer();
+
+ if (IK.IKBones.Length != IKLimitSettings.Count)
+ {
+ Debug.Log("[TAIL ANIMATOR IK] Wrong IK bone count!");
+ return;
+ }
+
+ if (!IKAutoAngleLimits)
+ {
+ for (int i = 0; i < IKLimitSettings.Count; i++)
+ {
+ IK.IKBones[i].AngleLimit = IKLimitSettings[i].AngleLimit;
+ IK.IKBones[i].TwistAngleLimit = IKLimitSettings[i].TwistAngleLimit;
+ }
+ }
+ }
+
+ if (ikInitialized) if (IKAutoWeights) IK.AutoWeightBones(IKBaseReactionWeight); else IK.AutoWeightBones(IKReactionWeightCurve);
+ if (IKAutoAngleLimits) IK.AutoLimitAngle(IKAutoAngleLimit, 10f + IKAutoAngleLimit / 10f);
+ }
+
+ ///
+ /// Generating new IK Limit Settings list with the same length as ghost transforms chain
+ ///
+ public void IK_RefreshLimitSettingsContainer()
+ {
+ IKLimitSettings = new List();
+ for (int i = 0; i < _TransformsGhostChain.Count; i++)
+ {
+ IKLimitSettings.Add(new IKBoneSettings());
+ }
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Extensions.IK.cs.meta b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Extensions.IK.cs.meta
new file mode 100644
index 000000000..53076d5b3
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Extensions.IK.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: adf0396b6095c7c4f93a78f8ee022984
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Extensions.PointPostProcessing.cs b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Extensions.PointPostProcessing.cs
new file mode 100644
index 000000000..8cd3e529a
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Extensions.PointPostProcessing.cs
@@ -0,0 +1,114 @@
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace FIMSpace.FTail
+{
+ // Positions Post Processing support calculations for effects like deflection
+ // which needs baked position to correctly detect needed stuff for
+ // every frame update
+ public partial class TailAnimator2
+ {
+ /// Always return chain with coordinates without any POST processes as reference for POST processing algorithms. Separated list of tail bones operating on the same transforms but without post processed coords
+ private List _pp_reference;
+
+ // Artificial bone points bakery
+ private TailSegment _pp_ref_rootParent;
+ private TailSegment _pp_ref_lastChild;
+
+ private bool _pp_initialized = false;
+
+
+ ///
+ /// Return true if Tail Aniamtor is using feature which requires post processing support
+ ///
+ bool PostProcessingNeeded()
+ {
+ if (Deflection > Mathf.Epsilon) return true;
+ else return false;
+ }
+
+
+ ///
+ /// Post processing start frame calculations
+ ///
+ void PostProcessing_Begin()
+ {
+ TailSegments_UpdateCoordsForRootBone(_pp_reference[_tc_startI]);
+
+ // Deflection support
+ if (Deflection > Mathf.Epsilon) Deflection_BeginUpdate();
+ }
+
+
+ ///
+ /// Computing reference coordinates for POST processing
+ ///
+ void PostProcessing_ReferenceUpdate()
+ {
+ TailSegment child = _pp_reference[_tc_startI];
+
+ #region Prepare base positions calculation for tail segments to use in coords calculations and as reference
+
+
+ while (child != _pp_ref_lastChild)
+ {
+ child.ParamsFrom(TailSegments[child.Index]); // Copying parameters settings from true bones
+ TailSegment_PrepareVelocity(child);
+ child = child.ChildBone;
+ }
+
+ // Udpate for artificial end bone
+ TailSegment_PrepareMotionParameters(_pp_ref_lastChild);
+ TailSegment_PrepareVelocity(_pp_ref_lastChild);
+
+ #endregion
+
+
+ #region Processing segments, calculating full target coords and apply to transforms
+
+ child = _pp_reference[_tc_startII];
+
+ if (!DetachChildren)
+ {
+ while (child != _pp_ref_lastChild)
+ {
+ TailSegment_PrepareRotation(child);
+ TailSegment_BaseSwingProcessing(child);
+ TailCalculations_SegmentPreProcessingStack(child);
+ TailSegment_PreRotationPositionBlend(child);
+ child = child.ChildBone;
+ }
+ }
+ else
+ {
+ while (child != _pp_ref_lastChild)
+ {
+ TailSegment_PrepareRotationDetached(child);
+ TailSegment_BaseSwingProcessing(child);
+ TailCalculations_SegmentPreProcessingStack(child);
+ TailSegment_PreRotationPositionBlend(child);
+ child = child.ChildBone;
+ }
+ }
+
+ // Applying processing for artificial child bone without transform
+ TailCalculations_UpdateArtificialChildBone(_pp_ref_lastChild);
+
+ #endregion
+
+
+ child = _pp_reference[_tc_startII];
+ while (child != _pp_ref_lastChild)
+ {
+ // Calculate rotation
+ TailCalculations_SegmentRotation(child, child.LastKeyframeLocalPosition);
+ child = child.ChildBone;
+ }
+
+ // If ghost child has transform let's apply motion too (change rotation of last bone)
+ TailCalculations_SegmentRotation(child, child.LastKeyframeLocalPosition);
+ child.ParentBone.RefreshFinalRot(child.ParentBone.TrueTargetRotation);
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Extensions.PointPostProcessing.cs.meta b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Extensions.PointPostProcessing.cs.meta
new file mode 100644
index 000000000..d44cab564
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Extensions.PointPostProcessing.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 9655b675af6b2334ea694f30ff189f44
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Extensions.Shaping.cs b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Extensions.Shaping.cs
new file mode 100644
index 000000000..3d7a9d331
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Extensions.Shaping.cs
@@ -0,0 +1,154 @@
+using UnityEngine;
+
+namespace FIMSpace.FTail
+{
+ public partial class TailAnimator2
+ {
+ [Tooltip("Rotation offset for tail (just first (root) bone is rotated)")]
+ public Quaternion RotationOffset = Quaternion.identity;
+
+
+ [Tooltip("Rotate each segment a bit to create curving effect")]
+ public Quaternion Curving = Quaternion.identity;
+ [Tooltip("Spread curving rotation offset weight over tail segments")]
+ public bool UseCurvingCurve = false;
+ [FPD_FixedCurveWindow(0f, -1f, 1f, 1f, 0.75f, .75f, 0.75f, 0.85f)]
+ public AnimationCurve CurvCurve = AnimationCurve.EaseInOut(0f, 0.75f, 1f, 1f);
+ Quaternion lastCurving = Quaternion.identity;
+ Keyframe[] lastCurvingKeys;
+
+ [Tooltip("Make tail longer or shorter")]
+ public float LengthMultiplier = 1f;
+ [Tooltip("Spread length multiplier weight over tail segments")]
+ public bool UseLengthMulCurve = false;
+ [FPD_FixedCurveWindow(0, 0, 1f, 3f)]
+ public AnimationCurve LengthMulCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 1f);
+ float lastLengthMul = 1f;
+ Keyframe[] lastLengthKeys;
+
+ [Tooltip("Spread gravity weight over tail segments")]
+ public bool UseGravityCurve = false;
+ [FPD_FixedCurveWindow(0, 0, 1f, 1f, 0.85f, .35f, 0.25f, 0.85f)]
+ [Tooltip("Spread gravity weight over tail segments")]
+ public AnimationCurve GravityCurve = AnimationCurve.EaseInOut(0f, .65f, 1f, 1f);
+ [Tooltip("Simulate gravity weight for tail logics")]
+ public Vector3 Gravity = Vector3.zero;
+ Vector3 lastGravity = Vector3.zero;
+ Keyframe[] lastGravityKeys;
+
+
+ void ShapingParamsUpdate()
+ {
+ Shaping_UpdateCurving();
+ Shaping_UpdateGravity();
+ Shaping_UpdateLengthMultiplier();
+ }
+
+
+
+ void Shaping_UpdateCurving()
+ {
+ if (!FEngineering.QIsZero(Curving))
+ {
+ if (UseCurvingCurve) // Operations with curve
+ {
+ _ex_bone = TailSegments[0];
+ while (_ex_bone != null) { _ex_bone.Curving = Quaternion.LerpUnclamped(Quaternion.identity, Curving, CurvCurve.Evaluate(_ex_bone.IndexOverlLength)); _ex_bone = _ex_bone.ChildBone; }
+ }
+ else // Operations without curve
+ {
+ if (!FEngineering.QIsSame(Curving, lastCurving))
+ for (int i = 0; i < TailSegments.Count; i++) TailSegments[i].Curving = Curving;
+ }
+ }
+ else // Curving reset
+ {
+ if (!FEngineering.QIsSame(Curving, lastCurving))
+ for (int i = 0; i < TailSegments.Count; i++) TailSegments[i].Curving = Quaternion.identity;
+ }
+ }
+
+
+ void Shaping_UpdateGravity()
+ {
+ if (!FEngineering.VIsZero(Gravity))
+ {
+ if (UseGravityCurve) // Operations with curve
+ {
+ //if (!FEngineering.VIsSame(Gravity, lastGravity) || KeysChanged(GravityCurve.keys, lastGravityKeys))
+ //{
+ // for (int i = 0; i < TailSegments.Count; i++)
+ // {
+ // TailSegments[i].Gravity = Gravity * GetValueFromCurve(i, GravityCurve) / 40f;
+ // TailSegments[i].Gravity *= (1 + ((TailSegments[i].Index / 2f) * (1f - TailSegments[i].Slithery)));
+ // }
+ //}
+
+ _ex_bone = TailSegments[0];
+ while (_ex_bone != null) { _ex_bone.Gravity = Gravity * 40f * GravityCurve.Evaluate(_ex_bone.IndexOverlLength); _ex_bone = _ex_bone.ChildBone; }
+ }
+ else // Operations without curve
+ {
+ if (!FEngineering.VIsSame(Gravity, lastGravity))
+ for (int i = 0; i < TailSegments.Count; i++)
+ {
+ TailSegments[i].Gravity = Gravity / 40f;
+ TailSegments[i].Gravity *= (1 + ((TailSegments[i].Index / 2f) * (1f - TailSegments[i].Slithery)));
+ }
+ }
+ }
+ else // Gravity reset
+ {
+ if (!FEngineering.VIsSame(Gravity, lastGravity))
+ {
+ for (int i = 0; i < TailSegments.Count; i++)
+ {
+ TailSegments[i].Gravity = Vector3.zero;
+ TailSegments[i].GravityLookOffset = Vector3.zero;
+ }
+ }
+ }
+ }
+
+
+ void Shaping_UpdateLengthMultiplier()
+ {
+ if (UseLengthMulCurve)
+ {
+ //if (lastLengthMul != LengthMultiplier || KeysChanged(LengthMulCurve.keys, lastLengthKeys))
+ //{
+ // for (int i = 0; i < TailSegments.Count; i++) TailSegments[i].LengthMultiplier = /*LengthMultiplier */ GetValueFromCurve(i, LengthMulCurve);
+ //}
+
+ _ex_bone = TailSegments[0];
+ while (_ex_bone != null) { _ex_bone.LengthMultiplier = LengthMulCurve.Evaluate(_ex_bone.IndexOverlLength); _ex_bone = _ex_bone.ChildBone; }
+ }
+ else
+ {
+ if (lastLengthMul != LengthMultiplier)
+ for (int i = 0; i < TailSegments.Count; i++) TailSegments[i].LengthMultiplier = LengthMultiplier;
+ }
+ }
+
+
+
+ ///
+ /// Remembering previous parameters to avoid triggering full tail iterations every frame
+ ///
+ void ShapingEndUpdate()
+ {
+ lastCurving = Curving;
+ if (!UseCurvingCurve) if (lastCurvingKeys != null) { lastCurvingKeys = null; lastCurving.x += 0.001f; }
+ //if (UseCurvingCurve) lastCurvingKeys = CurvCurve.keys; else if (lastCurvingKeys != null) { lastCurvingKeys = null; lastCurving.x += 0.001f; }
+
+ lastGravity = Gravity;
+ if (!UseGravityCurve) if (lastGravityKeys != null) { lastGravityKeys = null; lastGravity.x += 0.001f; }
+ //if (UseGravityCurve) lastGravityKeys = GravityCurve.keys; else if (lastGravityKeys != null) { lastGravityKeys = null; lastGravity.x += 0.001f; }
+
+ lastLengthMul = LengthMultiplier;
+ if (!UseLengthMulCurve) if (lastLengthKeys != null) { lastLengthKeys = null; lastLengthMul += 0.0001f; }
+ //if (UseLengthMulCurve) lastLengthKeys = LengthMulCurve.keys; else if (lastLengthKeys != null) { lastLengthKeys = null; lastLengthMul += 0.0001f; }
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Extensions.Shaping.cs.meta b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Extensions.Shaping.cs.meta
new file mode 100644
index 000000000..49f727442
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Extensions.Shaping.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 9d872664813634c49b522c82ee361f4c
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Extensions.Waving.cs b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Extensions.Waving.cs
new file mode 100644
index 000000000..bc6497589
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Extensions.Waving.cs
@@ -0,0 +1,165 @@
+using UnityEngine;
+
+namespace FIMSpace.FTail
+{
+ public partial class TailAnimator2
+ {
+
+ #region Inspector Variables
+
+ [Tooltip("Using auto waving option to give floating effect")]
+ public bool UseWaving = true;
+
+ [Tooltip("Adding some variation to waving animation")]
+ public bool CosinusAdd = false;
+
+ [Tooltip("If you want few tails to wave in the same way you can set this sinus period cycle value")]
+ public float FixedCycle = 0f;
+
+ [Tooltip("How frequent swings should be")]
+ public float WavingSpeed = 3f;
+ [Tooltip("How big swings should be")]
+ public float WavingRange = 0.8f;
+
+ [Tooltip("What rotation axis should be used in auto waving")]
+ public Vector3 WavingAxis = new Vector3(1.0f, 1.0f, 1.0f);
+
+ public Quaternion WavingRotationOffset { get; private set; }
+
+ [Tooltip("Type of waving animation algorithm, it can be simple trigonometric wave or animation based on noises (advanced)")]
+ public FEWavingType WavingType = FEWavingType.Advanced;
+ public enum FEWavingType { Simple, Advanced }
+
+ [Tooltip("Offsetting perlin noise to generate different variation of tail rotations")]
+ public float AlternateWave = 1f;
+
+ #endregion
+
+
+
+ // ------------------------ Auto Waving Section ------------------------ \\
+
+ /// Trigonometric function time variable
+ float _waving_waveTime;
+ float _waving_cosTime;
+
+
+ ///
+ /// Defining time variables for trigonometrics
+ ///
+ void Waving_Initialize()
+ {
+ if (FixedCycle == 0f)
+ {
+ _waving_waveTime = Random.Range(-Mathf.PI, Mathf.PI) * 100f;
+ _waving_cosTime = Random.Range(-Mathf.PI, Mathf.PI) * 50f;
+ }
+ else
+ {
+ _waving_waveTime = FixedCycle;
+ _waving_cosTime = FixedCycle;
+ }
+
+ _waving_sustain = Vector3.zero;
+ //_waving_sustainVelo = Vector3.zero;
+ }
+
+
+ ///
+ /// Calculating trigonometric waving feature
+ ///
+ void Waving_AutoSwingUpdate()
+ {
+ // Defining base variables
+ _waving_waveTime += justDelta * (2 * WavingSpeed);
+
+ // Simple trigonometrical waving
+ if (WavingType == FEWavingType.Simple)
+ {
+ float sinVal = Mathf.Sin(_waving_waveTime) * (30f * WavingRange);
+
+ if (CosinusAdd)
+ {
+ _waving_cosTime += justDelta * (2.535f * WavingSpeed);
+ sinVal += Mathf.Cos(_waving_cosTime) * (27f * WavingRange);
+ }
+
+ WavingRotationOffset = Quaternion.Euler(sinVal * WavingAxis * TailSegments[0].BlendValue);
+ }
+ else
+ // Advanced waving based on perlin noise
+ {
+ float perTime = _waving_waveTime * 0.23f;
+
+ float altX = AlternateWave * -5f;
+ float altY = AlternateWave * 100f;
+ float altZ = AlternateWave * 20f;
+
+ float x = Mathf.PerlinNoise(perTime, altX) * 2.0f - 1.0f;
+ float y = Mathf.PerlinNoise(altY + perTime, perTime + altY) * 2.0f - 1.0f;
+ float z = Mathf.PerlinNoise(altZ, perTime) * 2.0f - 1.0f;
+
+ WavingRotationOffset = Quaternion.Euler(Vector3.Scale(WavingAxis * WavingRange * 35f * TailSegments[0].BlendValue, new Vector3(x, y, z)));
+ }
+ }
+
+
+
+
+ // ------------------------ Sustain Section ------------------------ \\
+
+
+ /// Sustain smooth damp helper variable
+ //Vector3 _waving_sustainVelo = Vector3.zero;
+ /// Sustain position offset for previous procedural position
+ Vector3 _waving_sustain = Vector3.zero;
+
+ ///
+ /// Calculating sustain feature offset
+ ///
+ void Waving_SustainUpdate()
+ {
+ TailSegment firstB = TailSegments[0];
+
+ // When tail is short and have few segments we have to ampify sustain effect behaviour and vice versa
+ float tailRatio = (_TC_TailLength / (float)TailSegments.Count);
+ tailRatio = Mathf.Pow(tailRatio, 1.65f);
+ tailRatio = (_sg_curly / tailRatio) / 6f;
+
+ // Clamp extreme values
+ if (tailRatio < 0.1f) tailRatio = 0.1f; else if (tailRatio > 1f) tailRatio = 1f;
+
+ int mid = (int)Mathf.LerpUnclamped(TailSegments.Count * 0.4f, TailSegments.Count * 0.6f, Sustain);
+
+ float susFact = FEasing.EaseOutExpo(1f, 0.09f, Sustain);
+
+ float mild = 1.5f;
+ mild *= (1f - TailSegments[0].Curling / 8f);
+ mild *= (1.5f - tailRatio / 1.65f);
+ mild *= Mathf.Lerp(0.7f, 1.2f, firstB.Slithery);
+ mild *= FEasing.EaseOutExpo(1f, susFact, firstB.Springiness);
+
+ Vector3 velo = TailSegments[mid].PreviousPush;
+ if (mid + 1 < TailSegments.Count) velo += TailSegments[mid + 1].PreviousPush;
+ if (mid - 1 > TailSegments.Count) velo += TailSegments[mid - 1].PreviousPush;
+
+
+ _waving_sustain = velo * Sustain * mild * 2f;
+
+ #region Backup
+ //_waving_sustain = Vector3.Lerp(_waving_sustain, TailBones[mid].PreviousPush * Sustain * mild, unifiedDelta);
+ //Vector3.SmoothDamp
+ //(
+ //_waving_sustain,
+ //TailBones[mid].PreviousPush * Sustain * mild,
+ //ref _waving_sustainVelo,
+ //Mathf.LerpUnclamped(0.15f + tailRatio / 5f, 0.1f + tailRatio / 5f, Sustain),
+ //Mathf.Infinity, Time.smoothDeltaTime);
+
+ //TailBones[Mathf.Min(TailBones.Count - 1, _tc_startII)].PreviousPosition += _waving_sustain * mild;
+ #endregion
+ }
+
+
+ }
+}
\ No newline at end of file
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Extensions.Waving.cs.meta b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Extensions.Waving.cs.meta
new file mode 100644
index 000000000..8c9bbe676
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Extensions.Waving.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: fcfde61a5f0bcac4fac26bf2152d6a2e
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Extensions.Wind.cs b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Extensions.Wind.cs
new file mode 100644
index 000000000..3d3cdc234
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Extensions.Wind.cs
@@ -0,0 +1,26 @@
+using UnityEngine;
+
+namespace FIMSpace.FTail
+{
+ public partial class TailAnimator2
+ {
+ public bool UseWind = false;
+ [FPD_Suffix(0f, 2.5f, FPD_SuffixAttribute.SuffixMode.PercentageUnclamped)]
+ public float WindEffectPower = 1f;
+ [FPD_Suffix(0f, 2.5f, FPD_SuffixAttribute.SuffixMode.PercentageUnclamped)]
+ public float WindTurbulencePower = 1f;
+ [FPD_Suffix(0f, 1.5f, FPD_SuffixAttribute.SuffixMode.PercentageUnclamped)]
+ public float WindWorldNoisePower = 0.5f;
+
+ /// Wind power vector used by Tail Animator Wind component
+ public Vector3 WindEffect = Vector3.zero;
+
+ void WindEffectUpdate()
+ {
+ if (TailAnimatorWind.Instance)
+ {
+ TailAnimatorWind.Instance.AffectTailWithWind(this);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Extensions.Wind.cs.meta b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Extensions.Wind.cs.meta
new file mode 100644
index 000000000..da633179f
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Extensions.Wind.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: dfa827566ed68c5469e8b78e674d1d89
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Gizmos.cs b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Gizmos.cs
new file mode 100644
index 000000000..9aedb93f1
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Gizmos.cs
@@ -0,0 +1,424 @@
+#if UNITY_EDITOR
+
+using FIMSpace.FEditor;
+using UnityEditor;
+using UnityEngine;
+
+namespace FIMSpace.FTail
+{
+ public partial class TailAnimator2
+ {
+ [FPD_Header("Debug Switch")]
+ [SerializeField]
+ private bool fDebug = false;
+
+ public Transform _gizmosEditorStartPreview;
+ public Transform _gizmospesp;
+ public Transform _gizmosEditorEndPreview;
+ public Transform _gizmospeep;
+
+ public string _editor_Title = "Tail Animator 2";
+ public bool _editor_IsInspectorViewingColliders = true;
+ public bool _editor_IsInspectorViewingIncludedColliders = false;
+ public int _editor_animatorViewedCounter = -1;
+
+ void OnDrawGizmosSelected()
+ {
+ RefreshTransformsList();
+ if (_TransformsGhostChain.Count == 0) return;
+ if (!DrawGizmos) return;
+
+ if (UseIK) Gizmos_DrawIK();
+
+ if (UseMaxDistance) Gizmos_DrawMaxDistance();
+
+ if (Application.isPlaying)
+ {
+ if (!initialized) return;
+
+ if (!IncludeParent) Editor_TailCalculations_RefreshArtificialParentBone();
+
+ if (_Editor_Category == ETailCategory.Shaping || fDebug)
+ {
+ Handles.color = new Color(0.2f, .2f, 0.85f, 0.5f);
+ Handles.SphereHandleCap(0, TailSegments[0].transform.position, Quaternion.identity, HandleUtility.GetHandleSize(TailSegments[0].transform.position) * 0.05f, EventType.Repaint);
+
+ Handles.color = new Color(0.5f, 1f, 0.35f, 0.3f);
+
+ for (int i = 1; i < TailSegments.Count; i++)
+ {
+ Handles.SphereHandleCap(0, TailSegments[i].ProceduralPosition, Quaternion.identity, HandleUtility.GetHandleSize(TailSegments[i].ProceduralPosition) * 0.09f, EventType.Repaint);
+ Handles.DrawDottedLine(TailSegments[i].ProceduralPosition, TailSegments[i].ParentBone.ProceduralPosition, 2f);
+ }
+
+ if (IncludeParent) Handles.color = new Color(1f, .2f, 0.6f, 1f);
+ Handles.DrawDottedLine(TailSegments[0].ProceduralPosition, TailSegments[0].ParentBone.ProceduralPosition, 2f);
+
+ Handles.color = new Color(1f, .2f, 0.6f, 1f);
+ Handles.DrawDottedLine(GhostChild.ProceduralPosition, GhostChild.ParentBone.ProceduralPosition, 2f);
+
+ Handles.SphereHandleCap(0, GhostParent.ProceduralPosition, Quaternion.identity, HandleUtility.GetHandleSize(GhostParent.ProceduralPosition) * 0.09f, EventType.Repaint);
+ Handles.SphereHandleCap(0, GhostChild.ProceduralPosition, Quaternion.identity, HandleUtility.GetHandleSize(GhostParent.ProceduralPosition) * 0.09f, EventType.Repaint);
+ }
+
+
+ if (fDebug)
+ {
+ Vector3 uoff;
+
+ if (PostProcessingNeeded() && _pp_initialized)
+ {
+ uoff = Vector3.up * _TC_TailLength * 0.065f;
+ Gizmos.color = new Color(0.8f, 0.2f, 0.5f, 0.4f); // Post processing reference line (transparent dark pinnk)
+ for (int i = 0; i < _pp_reference.Count; i++)
+ {
+ Gizmos.DrawSphere(_pp_reference[i].ProceduralPosition, .3f);
+
+ Gizmos.DrawLine(_pp_reference[i].ParentBone.ProceduralPosition + uoff, _pp_reference[i].ProceduralPosition + uoff);
+ }
+
+ Handles.color = new Color(0.8f, 0.2f, 0.5f, 0.4f); // Deflection source segment sphere
+ for (int i = 0; i < _defl_source.Count; i++)
+ Handles.SphereHandleCap(0, _defl_source[i].ParentBone.ProceduralPosition + uoff, Quaternion.identity, HandleUtility.GetHandleSize(_defl_source[i].ProceduralPosition) * 0.09f, EventType.Repaint);
+
+ Handles.color = new Color(0.55f, .2f, 0.8f, 0.6f); // Deflection source segment sphere
+ for (int i = 0; i < _defl_source.Count; i++)
+ Handles.SphereHandleCap(0, Vector3.LerpUnclamped(TailSegments[_defl_source[i].Index].ParentBone.ProceduralPosition, TailSegments[_defl_source[i].Index].ProceduralPosition, 0.5f) + uoff, Quaternion.identity, HandleUtility.GetHandleSize(_defl_source[i].ProceduralPosition) * 0.09f, EventType.Repaint);
+
+
+ #region Debug
+
+ //Handles.color = new Color(0.55f, .2f, 0.8f, 0.8f);
+ //for (int i = 0; i < _defl_source.Count; i++)
+ // Handles.DrawDottedLine(_defl_source[i].ProceduralPosition + uoff, _defl_source[i].DeflectionWorldPosition + uoff, 2f);
+
+ //Handles.color = new Color(0.0f, 1f, 1f, 0.8f);
+ //for (int i = 0; i < _defl_source.Count; i++)
+ //{
+ // int backRange = _tc_startI; if (i > 0) backRange = _defl_source[i - 1].Index;
+
+ // for (int k = _defl_source[i].Index; k >= backRange; k--)
+ // Handles.DrawDottedLine(TailBones[k].ProceduralPosition + uoff, _defl_source[i].DeflectionWorldPosition + uoff, 2f);
+ //}
+
+ #endregion
+
+ Gizmos.color = new Color(1f, 0.1f, 0.35f, 0.6f); // Deflection push focus (magenta)
+ for (int i = 0; i < _defl_source.Count; i++)
+ {
+ Gizmos.DrawLine(_defl_source[i].DeflectionWorldPosition + uoff, _defl_source[i].ParentBone.ProceduralPosition + uoff);
+ //Handles.Label(_pp_reference[_defl_source[i].Index].ParentBone.ProceduralPosition + uoff + transform.right * _tc_tailLength * 0.032f + uoff, "b.par=[" + _defl_source[i].Index + "]");
+ Handles.DrawDottedLine(_pp_reference[_defl_source[i].Index].ParentBone.ProceduralPosition + uoff + transform.right * _TC_TailLength * 0.032f + uoff, TailSegments[_defl_source[i].Index].ProceduralPosition + uoff, 3f);
+ }
+
+
+ uoff = Vector3.up * _TC_TailLength * 0.044f;
+ Gizmos.color = new Color(0.2f, 0.9f, 0.4f, 0.5f); // True position line
+ for (int i = 0; i < _pp_reference.Count; i++)
+ Gizmos.DrawLine(TailSegments[i].ParentBone.ProceduralPosition + uoff, TailSegments[i].ProceduralPosition + uoff);
+
+ Gizmos.DrawLine(_pp_ref_lastChild.ParentBone.ProceduralPosition + uoff, _pp_ref_lastChild.ProceduralPosition + uoff);
+
+
+ // All segments debug draw
+ uoff = Vector3.up * _TC_TailLength * 0.065f;
+ Handles.color = new Color(1f, 1f, 1f, 0.4f);
+ for (int i = 0; i < TailSegments.Count; i++)
+ {
+ Handles.SphereHandleCap(0, TailSegments[i].ProceduralPosition, Quaternion.identity, HandleUtility.GetHandleSize(TailSegments[i].ProceduralPosition) * 0.09f, EventType.Repaint);
+ Handles.Label(TailSegments[i].ProceduralPosition - transform.right * _TC_TailLength * 0.02f + uoff, "[" + i + "]");
+ }
+ }
+ }
+ }
+
+ if (_Editor_Category == ETailCategory.Setup)
+ {
+ if (_TransformsGhostChain != null)
+ {
+ if (_TransformsGhostChain.Count > 1)
+ {
+
+ if (!IncludeParent) Handles.color = new Color(.9f, .4f, .7f, .9f); else Handles.color = new Color(0.5f, 1f, 0.35f, 0.8f);
+
+ if (_TransformsGhostChain.Count > 1)
+ {
+ FGUI_Handles.DrawBoneHandle(_TransformsGhostChain[0].position, _TransformsGhostChain[1].position, BaseTransform.forward, 1f);
+ Handles.SphereHandleCap(0, _TransformsGhostChain[0].position, Quaternion.identity, HandleUtility.GetHandleSize(_TransformsGhostChain[0].position) * 0.09f, EventType.Repaint);
+ }
+
+
+ for (int i = 1; i < _TransformsGhostChain.Count - 1; i++) // -1 because we painting bones from i to i+1
+ {
+ Handles.color = new Color(0.5f, 1f, 0.35f, 0.8f);
+ FGUI_Handles.DrawBoneHandle(_TransformsGhostChain[i].position, _TransformsGhostChain[i + 1].position, BaseTransform.forward, 1f);
+
+ Handles.color = new Color(0.5f, 1f, 0.35f, 0.3f);
+ Handles.SphereHandleCap(0, _TransformsGhostChain[i].position, Quaternion.identity, HandleUtility.GetHandleSize(_TransformsGhostChain[i].position) * 0.09f, EventType.Repaint);
+ }
+
+ if (_TransformsGhostChain.Count > 1)
+ if (IncludeParent)
+ {
+ if (_TransformsGhostChain[0].parent)
+ {
+ Handles.color = new Color(1f, .2f, 0.6f, 0.3f);
+ FGUI_Handles.DrawBoneHandle(_TransformsGhostChain[0].parent.position, _TransformsGhostChain[0].position, BaseTransform.forward, 1f);
+ }
+ }
+ }
+ else
+ {
+ if (_TransformsGhostChain.Count > 0)
+ {
+ if (_TransformsGhostChain[0].parent)
+ {
+ Transform t = _TransformsGhostChain[0]; Transform p = _TransformsGhostChain[0].parent;
+
+ Handles.color = new Color(0.8f, .8f, 0.2f, 0.8f);
+ FGUI_Handles.DrawBoneHandle(_TransformsGhostChain[0].parent.position, _TransformsGhostChain[0].position, BaseTransform.forward, 1f);
+ Handles.color = new Color(0.8f, .8f, 0.2f, 0.3f);
+ Handles.SphereHandleCap(0, _TransformsGhostChain[0].position, Quaternion.identity, HandleUtility.GetHandleSize(_TransformsGhostChain[0].position) * 0.135f, EventType.Repaint);
+ Handles.Label(t.position + Vector3.Cross(t.forward, p.forward).normalized * (t.position - p.position).magnitude / 2f, new GUIContent("[i]", "Tail chain with one bone setup - try using End Bone Offset in 'Setup' tab"));
+ }
+
+ }
+ }
+
+ }
+ }
+
+
+ if (_TransformsGhostChain.Count < 2)
+ {
+ Handles.color = new Color(1f, 1f, 1f, 0.5f);
+ Handles.SphereHandleCap(0, _TransformsGhostChain[0].position, Quaternion.identity, HandleUtility.GetHandleSize(_TransformsGhostChain[0].position) * 0.135f, EventType.Repaint);
+
+ if (_TransformsGhostChain.Count > 0)
+ {
+ if (!_TransformsGhostChain[0].parent)
+ {
+ Handles.color = new Color(1f, .2f, 0.2f, 0.8f);
+ Vector3 infoPos = _TransformsGhostChain[0].position + (_TransformsGhostChain[0].up + _TransformsGhostChain[0].right) * 0.2f;
+ Handles.DrawDottedLine(_TransformsGhostChain[0].position, infoPos, 2f);
+ Handles.DrawDottedLine(_TransformsGhostChain[0].position, transform.position, 2f);
+ Handles.Label(infoPos, new GUIContent(FGUI_Resources.Tex_Warning, "No parent in this bone, tail chain can't be created"));
+ }
+ }
+ }
+
+
+ if (_Editor_Category == ETailCategory.Setup)
+ {
+ Handles.color = new Color(1f, .2f, 0.2f, 0.8f);
+ Gizmos_DrawEndBoneJoint();
+ }
+
+
+ if (_editor_IsInspectorViewingColliders && _Editor_Category == ETailCategory.Features) Gizmos_DrawColliders();
+ }
+
+
+ void Gizmos_DrawEndBoneJoint()
+ {
+ // Drawing auto end joint offset
+ if (FEngineering.VIsZero(EndBoneJointOffset))
+ {
+ Transform t = _TransformsGhostChain[_TransformsGhostChain.Count - 1];
+ Transform p = _TransformsGhostChain[_TransformsGhostChain.Count - 1].parent;
+
+ if (p) // Reference from parent
+ {
+ Vector3 worldOffset = t.position - p.position;
+
+ Handles.color = new Color(0.3f, .3f, 1f, 0.8f);
+ FGUI_Handles.DrawBoneHandle(t.position, t.position + worldOffset, BaseTransform.forward, 1f);
+ }
+ else // Reference to child
+ {
+ if (t.childCount > 0)
+ {
+ Transform ch = _TransformsGhostChain[0].GetChild(0);
+ Vector3 worldOffset = ch.position - t.position;
+ FGUI_Handles.DrawBoneHandle(t.position, t.position + worldOffset, BaseTransform.forward, 1f);
+ }
+ }
+ }
+ // Drawing custom joint offset
+ else
+ {
+ Transform t = _TransformsGhostChain[_TransformsGhostChain.Count - 1];
+ Handles.color = new Color(0.3f, .3f, 1f, 0.8f);
+ FGUI_Handles.DrawBoneHandle(t.position, t.position + t.TransformVector(EndBoneJointOffset), BaseTransform.forward, 1f);
+ }
+ }
+
+
+ void Gizmos_DrawColliders()
+ {
+ if (UseCollision)
+ {
+ if (IncludedColliders == null) IncludedColliders = new System.Collections.Generic.List();
+
+ Color preCol = Gizmos.color;
+ Gizmos.color = new Color(0.2f, 1f, 0.2f, 0.25f);
+
+ for (int i = 1; i < _TransformsGhostChain.Count - 1; i++)
+ {
+ if (_TransformsGhostChain[i] == null) continue;
+ Matrix4x4 curr = Matrix4x4.TRS(_TransformsGhostChain[i].position, _TransformsGhostChain[i].rotation, _TransformsGhostChain[i].lossyScale);
+ float radius = 1f;
+ if (Application.isPlaying) radius = TailSegments[i].ColliderRadius; else radius = GetColliderSphereRadiusFor(_TransformsGhostChain, i);
+
+ if (CollidersType != 0)
+ {
+ if (CollisionSpace == ECollisionSpace.World_Slow)
+ {
+ float preRadius = 1f;
+ if (Application.isPlaying) preRadius = TailSegments[i - 1].ColliderRadius; else preRadius = GetColliderSphereRadiusFor(_TransformsGhostChain, i - 1);
+
+ Gizmos.color = Color.HSVToRGB((float)i / (float)_TransformsGhostChain.Count, 0.9f, 0.9f) * new Color(1f, 1f, 1f, 0.55f);
+
+ Matrix4x4 pre = Matrix4x4.TRS(_TransformsGhostChain[i - 1].position, _TransformsGhostChain[i - 1].rotation, _TransformsGhostChain[i - 1].lossyScale);
+
+ Gizmos.DrawLine(pre.MultiplyPoint(Vector3.up * preRadius), curr.MultiplyPoint(Vector3.up * radius));
+ Gizmos.DrawLine(pre.MultiplyPoint(-Vector3.up * preRadius), curr.MultiplyPoint(-Vector3.up * radius));
+ Gizmos.DrawLine(pre.MultiplyPoint(Vector3.right * preRadius), curr.MultiplyPoint(Vector3.right * radius));
+ Gizmos.DrawLine(pre.MultiplyPoint(Vector3.left * preRadius), curr.MultiplyPoint(Vector3.left * radius));
+
+ if (i % 2 == 0)
+ {
+ Gizmos.matrix = curr;
+ Gizmos.DrawWireSphere(Vector3.zero, radius);
+ Gizmos.matrix = Matrix4x4.identity;
+ }
+ }
+ else
+ {
+ Gizmos.matrix = curr;
+ Gizmos.DrawWireSphere(Vector3.zero, radius);
+ Gizmos.matrix = Matrix4x4.identity;
+ }
+ }
+ else
+ {
+ Gizmos.matrix = curr;
+ Gizmos.DrawWireSphere(Vector3.zero, radius);
+ Gizmos.matrix = Matrix4x4.identity;
+ }
+ }
+
+
+ if (CollisionSpace == ECollisionSpace.Selective_Fast)
+ {
+ if (_editor_IsInspectorViewingIncludedColliders)
+ {
+ Handles.color = new Color(0.4f, 1f, 0.25f, 0.22f);
+ int c = Mathf.Min(IncludedColliders.Count, 10); // Drawing max 10 lines toward included colliders
+ for (int i = 0; i < c; i++)
+ {
+ if (IncludedColliders[i] != null)
+ {
+ Handles.DrawDottedLine(_TransformsGhostChain[0].position, IncludedColliders[i].transform.position, 2f);
+ Handles.SphereHandleCap(0, IncludedColliders[i].transform.position, Quaternion.identity, HandleUtility.GetHandleSize(IncludedColliders[i].transform.position) * 0.09f, EventType.Repaint);
+ }
+ }
+ }
+
+ if (!Application.isPlaying)
+ if (DynamicWorldCollidersInclusion)
+ {
+ float scaleRef = Vector3.Distance(_TransformsGhostChain[0].position, _TransformsGhostChain[_TransformsGhostChain.Count - 1].position);
+ Transform collSource = _TransformsGhostChain[_TransformsGhostChain.Count / 2];
+ Gizmos.DrawWireSphere(collSource.position, scaleRef * InclusionRadius);
+ }
+ }
+
+
+ Gizmos.color = preCol;
+ }
+ }
+
+
+ void Gizmos_DrawIK()
+ {
+ if (_TransformsGhostChain.Count < 2) return;
+ if (_Editor_Category != ETailCategory.Features) return;
+ if (_Editor_FeaturesCategory != ETailFeaturesCategory.IK) return;
+
+ Vector3 start = _TransformsGhostChain[0].position;
+ Vector3 end = _TransformsGhostChain[_TransformsGhostChain.Count - 1].position;
+ Vector3 targetIK;
+
+ if (IKTarget)
+ {
+ Handles.color = new Color(0f, 0.7f, 0.3f, 0.7f);
+ targetIK = IKTarget.position;
+ }
+ else
+ {
+ Handles.color = new Color(0.7f, 0.0f, 0.3f, 0.7f);
+ targetIK = _TransformsGhostChain[_TransformsGhostChain.Count - 1].position;
+ }
+
+ float d = (start - end).magnitude * 0.06f;
+
+ Handles.DrawDottedLine(start, targetIK, 3f);
+ Handles.DrawDottedLine(end, targetIK, 3f);
+
+ Handles.DrawLine(targetIK - BaseTransform.forward * d, targetIK + BaseTransform.forward * d);
+ Handles.DrawLine(targetIK - BaseTransform.right * d, targetIK + BaseTransform.right * d);
+ Handles.DrawLine(targetIK - BaseTransform.up * d, targetIK + BaseTransform.up * d);
+ Handles.SphereHandleCap(0, targetIK, Quaternion.identity, d * 0.25f, EventType.Repaint);
+
+ }
+
+
+ void Gizmos_DrawMaxDistance()
+ {
+ if (MaximumDistance <= 0f) return;
+
+ float a = 0.525f;
+ Vector3 startPos = BaseTransform.position + BaseTransform.TransformVector(DistanceMeasurePoint);
+
+ if (DistanceWithoutY)
+ {
+ if (maxDistanceExceed)
+ Handles.color = new Color(1f, .1f, .1f, a);
+ else Handles.color = new Color(0.02f, .65f, 0.2f, a);
+
+ Handles.DrawWireDisc(startPos, Vector3.up, MaximumDistance);
+
+ if (DistanceMeasurePoint != Vector3.zero)
+ {
+ Gizmos.color = new Color(0.02f, .65f, 0.2f, a);
+ Gizmos.DrawLine(startPos - Vector3.right * (MaximumDistance + MaximumDistance * MaxOutDistanceFactor), startPos + Vector3.right * (MaximumDistance + MaximumDistance * MaxOutDistanceFactor));
+ Gizmos.DrawLine(startPos - Vector3.forward * (MaximumDistance + MaximumDistance * MaxOutDistanceFactor), startPos + Vector3.forward * (MaximumDistance + MaximumDistance * MaxOutDistanceFactor));
+ }
+
+ if (MaxOutDistanceFactor > 0f)
+ {
+ Handles.color = new Color(.835f, .135f, .08f, a);
+ Handles.DrawWireDisc(startPos, Vector3.up, MaximumDistance + MaximumDistance * MaxOutDistanceFactor);
+ }
+ }
+ else
+ {
+ if (maxDistanceExceed)
+ Gizmos.color = new Color(1f, .1f, .1f, a);
+ else
+ Gizmos.color = new Color(0.02f, .65f, 0.2f, a);
+
+ Gizmos.DrawWireSphere(startPos, MaximumDistance);
+
+ if (MaxOutDistanceFactor > 0f)
+ {
+ Gizmos.color = new Color(.835f, .135f, .08f, a);
+ Gizmos.DrawWireSphere(startPos, MaximumDistance + MaximumDistance * MaxOutDistanceFactor);
+ }
+ }
+ }
+ }
+}
+
+#endif
\ No newline at end of file
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Gizmos.cs.meta b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Gizmos.cs.meta
new file mode 100644
index 000000000..7f3640e12
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Gizmos.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 516e3bfcbbd526a419d62b47bb170926
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Logic.Initialize.cs b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Logic.Initialize.cs
new file mode 100644
index 000000000..f9e11f411
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Logic.Initialize.cs
@@ -0,0 +1,312 @@
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace FIMSpace.FTail
+{
+ public partial class TailAnimator2
+ {
+ /// Procedural tail bone list
+ public List TailSegments;
+
+ /// Artificial or existing parent bone instance for slithery motion support
+ [SerializeField] TailSegment GhostParent;
+ [SerializeField] TailSegment GhostChild;
+
+ ///
+ /// Method to initialize component, to have more controll than waiting for Start() method, init can be executed before or after start, as programmer need it.
+ ///
+ protected virtual void Init()
+ {
+ if (initialized) return;
+
+
+ // Checking if we have transform to create tail chain from
+ if (_TransformsGhostChain == null || _TransformsGhostChain.Count == 0)
+ {
+ _TransformsGhostChain = new List();
+ GetGhostChain();
+ }
+
+
+ // Generating tail instances for procedural animation
+ TailSegments = new List();
+
+ for (int i = 0; i < _TransformsGhostChain.Count; i++)
+ {
+ if (_TransformsGhostChain[i] == null)
+ {
+ Debug.Log("[Tail Animator] Null bones in " + name + " !");
+ continue;
+ }
+
+ TailSegment b = new TailSegment(_TransformsGhostChain[i]);
+ b.SetIndex(i, _TransformsGhostChain.Count);
+ TailSegments.Add(b);
+ }
+
+
+ // Checking correctness
+ if (TailSegments.Count == 0)
+ {
+ Debug.Log("[Tail Animator] Could not create tail bones chain in " + name + " !");
+ return;
+ }
+
+
+ _TC_TailLength = 0f;
+ _baseTransform = _TransformsGhostChain[0];
+
+ //if (_baseTransform.parent)
+ // _baseTransform = _baseTransform.parent;
+ //else
+ // IncludeParent = false;
+
+
+ // Setting parent-child relation for tail logics
+ for (int i = 0; i < TailSegments.Count; i++)
+ {
+ TailSegment current = TailSegments[i];
+ TailSegment parent;
+
+ #region Defining Parent Bones
+
+ if (i == 0)
+ {
+ if (current.transform.parent)
+ {
+ // Creating parent and setting safety parent
+ parent = new TailSegment(current.transform.parent);
+ parent.SetParentRef(new TailSegment(parent.transform.parent));
+ }
+ else
+ #region If first bone is parentless
+ {
+ parent = new TailSegment(current.transform);
+
+ Vector3 toStartDir;
+
+ if (_TransformsGhostChain.Count > 1)
+ {
+ toStartDir = _TransformsGhostChain[0].position - _TransformsGhostChain[1].position;
+ if (toStartDir.magnitude == 0) toStartDir = transform.position - _TransformsGhostChain[1].position;
+ }
+ else
+ {
+ toStartDir = current.transform.position - _TransformsGhostChain[0].position;
+ }
+
+ if (toStartDir.magnitude == 0) toStartDir = transform.position - _TransformsGhostChain[0].position;
+ if (toStartDir.magnitude == 0) toStartDir = transform.forward;
+
+ parent.LocalOffset = parent.transform.InverseTransformPoint(parent.transform.position + toStartDir);
+ parent.SetParentRef(new TailSegment(current.transform));
+ }
+ #endregion
+
+ //current.InitialLocalRotation = Quaternion.Inverse(current.transform.localRotation);
+ GhostParent = parent;
+ GhostParent.Validate();
+ current.SetParentRef(GhostParent);
+ }
+ else // i != 0
+ {
+ parent = TailSegments[i - 1];
+ // If bones are removed manually from chain we support custom length of bone undependent from transform parenting chain structure
+ current.ReInitializeLocalPosRot(parent.transform.InverseTransformPoint(current.transform.position), current.transform.localRotation);
+ }
+
+
+ #endregion
+
+
+ #region Defining Last Child Bone
+
+ if (i == TailSegments.Count - 1)
+ {
+ Transform childT = null;
+ if (current.transform.childCount > 0) childT = current.transform.GetChild(0);
+
+ GhostChild = new TailSegment(childT);
+
+ // Scale ref for ghosting object position offset
+ Vector3 scaleDir;
+
+ if (FEngineering.VIsZero(EndBoneJointOffset))
+ {
+ if (current.transform.parent)
+ { scaleDir = current.transform.position - current.transform.parent.position; }
+ else
+ if (current.transform.childCount > 0)
+ { scaleDir = current.transform.GetChild(0).position - current.transform.position; }
+ else
+ { scaleDir = current.transform.TransformDirection(Vector3.forward) * 0.05f; }
+ }
+ else
+ scaleDir = current.transform.TransformVector(EndBoneJointOffset);
+
+
+ GhostChild.ProceduralPosition = current.transform.position + scaleDir;
+ GhostChild.ProceduralPositionWeightBlended = GhostChild.ProceduralPosition;
+ GhostChild.PreviousPosition = GhostChild.ProceduralPosition;
+ GhostChild.PosRefRotation = Quaternion.identity;
+ GhostChild.PreviousPosReferenceRotation = Quaternion.identity;
+ GhostChild.ReInitializeLocalPosRot(current.transform.InverseTransformPoint(GhostChild.ProceduralPosition), Quaternion.identity);
+ GhostChild.RefreshFinalPos(GhostChild.ProceduralPosition);
+ GhostChild.RefreshFinalRot(GhostChild.PosRefRotation);
+ GhostChild.TrueTargetRotation = GhostChild.PosRefRotation;
+ current.TrueTargetRotation = current.transform.rotation;
+
+ current.SetChildRef(GhostChild);
+ GhostChild.SetParentRef(current);
+ }
+ else
+ {
+ current.SetChildRef(TailSegments[i + 1]);
+ }
+
+ #endregion
+
+
+ current.SetParentRef(parent);
+
+ _TC_TailLength += Vector3.Distance(current.ProceduralPosition, parent.ProceduralPosition);
+
+ if (current.transform != _baseTransform) current.AssignDetachedRootCoords(BaseTransform);
+ }
+
+
+ // List with ghosts for curves etc.
+ GhostParent.SetIndex(-1, TailSegments.Count);
+ GhostChild.SetIndex(TailSegments.Count, TailSegments.Count);
+ GhostParent.SetChildRef(TailSegments[0]);
+
+ previousWorldPosition = BaseTransform.position;
+ WavingRotationOffset = Quaternion.identity;
+
+ if (CollidersDataToCheck == null) CollidersDataToCheck = new List();
+
+ DynamicAlwaysInclude = new List();
+ if (UseCollision) SetupSphereColliders();
+
+ // List instance for deflection feature
+ if (_defl_source == null) _defl_source = new List();
+
+ Waving_Initialize();
+
+ if (DetachChildren) DetachChildrenTransforms();
+
+ initialized = true;
+
+ if (TailSegments.Count == 1)
+ {
+ if (TailSegments[0].transform.parent == null)
+ {
+ Debug.Log("[Tail Animator] Can't initialize one-bone length chain on bone which don't have any parent!");
+ Debug.LogError("[Tail Animator] Can't initialize one-bone length chain on bone which don't have any parent!");
+ TailAnimatorAmount = 0f;
+ initialized = false;
+ return;
+ }
+ }
+
+ if (UseWind) TailAnimatorWind.Refresh();
+
+ if (PostProcessingNeeded()) if (!_pp_initialized) InitializePostProcessing();
+
+ #region Prewarming tail to target state
+
+ if (Prewarm)
+ {
+ ShapingParamsUpdate();
+ ExpertParamsUpdate();
+
+ Update();
+ LateUpdate();
+
+ justDelta = rateDelta;
+ secPeriodDelta = 1f;
+ deltaForLerps = secPeriodDelta;
+ rateDelta = 1f / 60f;
+
+ CheckIfTailAnimatorShouldBeUpdated();
+
+ if (updateTailAnimator)
+ {
+ int loopCount = 60 + TailSegments.Count / 2;
+
+ for (int d = 0; d < loopCount; d++)
+ {
+ PreCalibrateBones();
+ LateUpdate();
+ }
+ }
+ }
+
+ #endregion
+
+ }
+
+
+ ///
+ /// Detaching children for optimized work of Unity transform matrixes when tail is very long
+ ///
+ public void DetachChildrenTransforms()
+ {
+ int to = IncludeParent ? 0 : 1;
+ for (int i = TailSegments.Count - 1; i >= to; i--)
+ {
+ if (TailSegments[i].transform)
+ TailSegments[i].transform.DetachChildren();
+ }
+ }
+
+
+
+ ///
+ /// Initialize post processing reference points
+ ///
+ void InitializePostProcessing()
+ {
+ _pp_reference = new List();
+
+ // Generating copy of whole tail processing chain
+ _pp_ref_rootParent = new TailSegment(GhostParent);
+ for (int i = 0; i < TailSegments.Count; i++) { TailSegment bone = new TailSegment(TailSegments[i]); _pp_reference.Add(bone); }
+ _pp_ref_lastChild = new TailSegment(GhostChild);
+
+
+ // Setting child parent relation
+ _pp_ref_rootParent.SetChildRef(_pp_reference[0]); // root have just child
+ _pp_ref_rootParent.SetParentRef(new TailSegment(GhostParent.ParentBone.transform)); // Safety parent
+
+ for (int i = 0; i < _pp_reference.Count; i++)
+ {
+ TailSegment bone = _pp_reference[i];
+ bone.SetIndex(i, TailSegments.Count);
+
+ if (i == 0) // First bone have ghost parent
+ {
+ bone.SetParentRef(_pp_ref_rootParent);
+ bone.SetChildRef(_pp_reference[i + 1]);
+ }
+ else if (i == _pp_reference.Count - 1) // last bone have ghost child
+ {
+ bone.SetParentRef(_pp_reference[i - 1]);
+ bone.SetChildRef(_pp_ref_lastChild);
+ }
+ else // Default bone from chain middle points
+ {
+ bone.SetParentRef(_pp_reference[i - 1]);
+ bone.SetChildRef(_pp_reference[i + 1]);
+ }
+ }
+
+ _pp_ref_lastChild.SetParentRef(_pp_reference[_pp_reference.Count - 1]); // end have just parent
+
+
+ _pp_initialized = true;
+ }
+
+
+ }
+}
\ No newline at end of file
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Logic.Initialize.cs.meta b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Logic.Initialize.cs.meta
new file mode 100644
index 000000000..dff391b8e
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Logic.Initialize.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: e3b722fb0fe3ed44685a7cfc9ad05ac8
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Logic.Limits.cs b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Logic.Limits.cs
new file mode 100644
index 000000000..e8806a154
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Logic.Limits.cs
@@ -0,0 +1,354 @@
+using UnityEngine;
+
+namespace FIMSpace.FTail
+{
+ public partial class TailAnimator2
+ {
+ Vector3 _limiting_limitPosition = Vector3.zero;
+ Vector3 _limiting_influenceOffset = Vector3.zero;
+
+ /// Helping stretching limiting be more responsible (lerp value help)
+ float _limiting_stretchingHelperTooLong = 0f;
+ float _limiting_stretchingHelperTooShort = 0f;
+
+ ///
+ /// If tail is too long we making it shorter if too short - back to default scale
+ ///
+ protected void StretchingLimiting(TailSegment bone)
+ {
+ Vector3 backDir = (bone.ParentBone.ProceduralPosition) - (bone.ProceduralPosition);
+ float dist = backDir.magnitude;
+
+ if (dist > 0f)
+ {
+ float maxDist = bone.BoneLengthScaled + bone.BoneLengthScaled * 2.5f * MaxStretching;
+
+ if (dist > maxDist) // If tail too long
+ {
+ if (MaxStretching == 0f)
+ {
+ _limiting_limitPosition = bone.ProceduralPosition + backDir * ((dist - bone.BoneLengthScaled) / dist);
+ bone.ProceduralPosition = _limiting_limitPosition;
+ }
+ else
+ {
+ _limiting_limitPosition = bone.ParentBone.ProceduralPosition - backDir.normalized * maxDist;
+ //bone.ProceduralPosition = _limiting_limitPosition;
+ float limValue = Mathf.InverseLerp(dist, 0f, maxDist) + _limiting_stretchingHelperTooLong; if (limValue > 0.999f) limValue = 0.99f;
+ if (ReactionSpeed < 0.5f) limValue *= deltaForLerps * (10f + ReactionSpeed * 30f);
+ bone.ProceduralPosition = Vector3.Lerp(bone.ProceduralPosition, _limiting_limitPosition, limValue);
+ }
+ }
+ else // If tail too short
+ {
+ maxDist = bone.BoneLengthScaled + bone.BoneLengthScaled * 1.1f * MaxStretching;
+
+ if (dist < maxDist)
+ {
+ _limiting_limitPosition = bone.ProceduralPosition + backDir * ((dist - bone.BoneLengthScaled) / dist);
+
+ if (MaxStretching == 0f)
+ bone.ProceduralPosition = _limiting_limitPosition;
+ else
+ bone.ProceduralPosition = Vector3.LerpUnclamped(bone.ProceduralPosition, _limiting_limitPosition, Mathf.InverseLerp(dist, 0f, maxDist) + _limiting_stretchingHelperTooShort);
+ }
+ }
+
+ }
+
+ }
+
+ Quaternion _limiting_angle_ToTargetRot;
+ Quaternion _limiting_angle_targetInLocal;
+ Quaternion _limiting_angle_newLocal;
+
+ ///
+ /// If segment rotation is in too big angle we straighten it
+ ///
+ protected Vector3 AngleLimiting(TailSegment child, Vector3 targetPos)
+ {
+ float angleFactor = 0f;
+ _limiting_limitPosition = targetPos;
+
+
+ _limiting_angle_ToTargetRot = (
+ Quaternion.FromToRotation
+ (
+ child.ParentBone.transform.TransformDirection(child.LastKeyframeLocalPosition),
+ targetPos - child.ParentBone.ProceduralPosition)
+ )
+ * child.ParentBone.transform.rotation;
+
+ _limiting_angle_targetInLocal = FEngineering.QToLocal(child.ParentBone.transform.rotation, _limiting_angle_ToTargetRot); // Quaternion.Inverse(child.ParentBone.PreviousRotation) * _limiting_angle_ToTargetRot;
+
+
+ // Limiting all axis or one
+ float angleDiffToInitPose = 0f;
+
+ if (AngleLimitAxis.sqrMagnitude == 0f) // All axis limit angle
+ angleDiffToInitPose = Quaternion.Angle(_limiting_angle_targetInLocal, child.LastKeyframeLocalRotation);
+ else // Selective axis
+ {
+ #region Selective axis limits
+
+ AngleLimitAxis.Normalize();
+
+ if (LimitAxisRange.x == LimitAxisRange.y)
+ {
+ angleDiffToInitPose = Mathf.DeltaAngle(
+ Vector3.Scale(child.InitialLocalRotation.eulerAngles, AngleLimitAxis).magnitude,
+ Vector3.Scale(_limiting_angle_targetInLocal.eulerAngles, AngleLimitAxis).magnitude);
+
+ if (angleDiffToInitPose < 0f) angleDiffToInitPose = -angleDiffToInitPose;
+ }
+ else
+ {
+ angleDiffToInitPose = Mathf.DeltaAngle(
+ Vector3.Scale(child.InitialLocalRotation.eulerAngles, AngleLimitAxis).magnitude,
+ Vector3.Scale(_limiting_angle_targetInLocal.eulerAngles, AngleLimitAxis).magnitude);
+
+ if (angleDiffToInitPose > LimitAxisRange.x && angleDiffToInitPose < LimitAxisRange.y) angleDiffToInitPose = 0f;
+ if (angleDiffToInitPose < 0) angleDiffToInitPose = -angleDiffToInitPose;
+ }
+
+ #endregion
+ }
+
+
+ #region Debug
+ //Debug.Log("Atarget in local = " +
+ // FEngineering.WrapVector(_limiting_angle_targetInLocal.eulerAngles) + " last key local = " +
+ // FEngineering.WrapVector(child.lastKeyframeLocalRotation.eulerAngles) + " angle = " + angleDiffToInitPose);
+ #endregion
+
+ // Finding rotate back to limited angle coordinates
+ if (angleDiffToInitPose > AngleLimit)
+ {
+
+ float exceededAngle = Mathf.Abs(Mathf.DeltaAngle(angleDiffToInitPose, AngleLimit));
+ angleFactor = Mathf.InverseLerp(0f, AngleLimit, exceededAngle); // percentage value (0-1) from target rotation to limit
+
+ #region Debug
+
+ //Debug.DrawLine(child.ParentBone.ParentBone.transform.position + child.ParentBone.ParentBone.ProceduralRotation * child.ParentBone.transform.localPosition,
+ //child.ProceduralPosition, Color.red, 1f);
+
+ //Debug.Log("[" + child.Index + "] diff = "
+ // + angleDiffToInitPose + " exc = "
+ // + exceededAngle + " fact = "
+ // + angleFactor);
+
+ #endregion
+
+
+ if (LimitSmoothing > Mathf.Epsilon)
+ {
+ float smooth = Mathf.Lerp(55f, 15f, LimitSmoothing);
+ _limiting_angle_newLocal = Quaternion.SlerpUnclamped(_limiting_angle_targetInLocal, child.LastKeyframeLocalRotation, deltaForLerps * smooth * angleFactor);
+ }
+ else
+ _limiting_angle_newLocal = Quaternion.SlerpUnclamped(_limiting_angle_targetInLocal, child.LastKeyframeLocalRotation, angleFactor);
+
+
+ _limiting_angle_ToTargetRot = FEngineering.QToWorld(child.ParentBone.transform.rotation, _limiting_angle_newLocal);
+ _limiting_limitPosition = child.ParentBone.ProceduralPosition + _limiting_angle_ToTargetRot * Vector3.Scale(child.transform.lossyScale, child.LastKeyframeLocalPosition);
+
+ }
+
+ if (angleFactor > Mathf.Epsilon) return _limiting_limitPosition; else return targetPos;
+ }
+
+
+ ///
+ /// Limiting tail motion in world space position movement
+ ///
+ void MotionInfluenceLimiting()
+ {
+ if (MotionInfluence != 1f)
+ { // one - param: param = 1 -> 0 param = 0 -> 1
+
+ _limiting_influenceOffset = (BaseTransform.position - previousWorldPosition) * (1f - MotionInfluence);
+
+ if (MotionInfluenceInY < 1f)
+ _limiting_influenceOffset.y = (BaseTransform.position.y - previousWorldPosition.y) * (1f - MotionInfluenceInY);
+
+ for (int i = 0; i < TailSegments.Count; i++)
+ {
+ TailSegments[i].ProceduralPosition += _limiting_influenceOffset;
+ TailSegments[i].PreviousPosition += _limiting_influenceOffset;
+ }
+
+ GhostChild.ProceduralPosition += _limiting_influenceOffset;
+ GhostChild.PreviousPosition += _limiting_influenceOffset;
+ }
+ }
+
+
+ /// Helper gravity calculations variable to avoid GC
+ Vector3 _tc_segmentGravityOffset = Vector3.zero;
+ /// Helper gravity calculations variable to avoid GC
+ Vector3 _tc_segmentGravityToParentDir = Vector3.zero;
+ Vector3 _tc_preGravOff = Vector3.zero;
+
+ ///
+ /// Calculating gravity parameter position offset for tail segment with some vector direction operations
+ ///
+ void CalculateGravityPositionOffsetForSegment(TailSegment bone)
+ {
+ //if (updateLoops > 0)
+ {
+ _tc_segmentGravityOffset = (bone.Gravity + WindEffect) * bone.BoneLengthScaled;
+ _tc_segmentGravityToParentDir = bone.ProceduralPosition - bone.ParentBone.ProceduralPosition;
+
+ _tc_preGravOff = (_tc_segmentGravityToParentDir + _tc_segmentGravityOffset).normalized * _tc_segmentGravityToParentDir.magnitude;
+
+ // Keeping same length of the bone to prevent gravity effect from stretching bones but offsetting in computed direction
+ bone.ProceduralPosition = bone.ParentBone.ProceduralPosition + _tc_preGravOff;
+ }
+ //else
+ //{
+ // bone.ProceduralPosition = bone.ParentBone.ProceduralPosition + _tc_preGravOff;
+ //}
+ }
+
+
+ ///
+ /// Limiting movement of tail bones in selected axis
+ ///
+ void Axis2DLimit(TailSegment child)
+ {
+ child.ProceduralPosition -=
+ FEngineering.VAxis2DLimit(
+ child.ParentBone.transform,
+ child.ParentBone.ProceduralPosition,
+ child.ProceduralPosition, Axis2D);
+
+ }
+
+
+ #region Distance Limiting Calculations
+
+ [Tooltip("If you want to use max distance fade option to smoothly disable tail animator when object is going far away from camera")]
+ public bool UseMaxDistance = false;
+
+ [Tooltip("(By default camera transform) Measuring distance from this object to define if object is too far and not need to update tail animator")]
+ public Transform DistanceFrom;
+ [HideInInspector]
+ public Transform _distanceFrom_Auto;
+
+ [Tooltip("Max distance to main camera / target object to smoothly turn off tail animator.")]
+ public float MaximumDistance = 35f;
+
+ [Tooltip("If object in range should be detected only when is nearer than 'MaxDistance' to avoid stuttery enabled - disable switching")]
+ [Range(0.0f, 1f)]
+ public float MaxOutDistanceFactor = 0f;
+
+ [Tooltip("If distance should be measured not using Up (y) axis")]
+ public bool DistanceWithoutY = false;
+
+ [Tooltip("Offsetting point from which we want to measure distance to target")]
+ public Vector3 DistanceMeasurePoint;
+
+ [Tooltip("Disable fade duration in seconds")]
+ [Range(0.25f, 2f)]
+ public float FadeDuration = 0.75f;
+
+ private bool maxDistanceExceed = false;
+ private Transform finalDistanceFrom;
+ private bool wasCameraSearch = false;
+
+ /// Multiplier for blend weight when tail animator is far from camera or provided object
+ private float distanceWeight = 1f;
+
+
+ ///
+ /// Getting distance value from distance measure point to target position
+ ///
+ public float GetDistanceMeasure(Vector3 targetPosition)
+ {
+ if (DistanceWithoutY)
+ {
+ Vector3 p = BaseTransform.position + BaseTransform.TransformVector(DistanceMeasurePoint);
+ Vector2 p2 = new Vector2(p.x, p.z);
+ return Vector2.Distance(p2, new Vector2(targetPosition.x, targetPosition.z));
+ }
+ else
+ return Vector3.Distance(BaseTransform.position + BaseTransform.TransformVector(DistanceMeasurePoint), targetPosition);
+ }
+
+
+ ///
+ /// Handling max distance feature
+ ///
+ private void MaxDistanceCalculations()
+ {
+
+ if (DistanceFrom != null)
+ finalDistanceFrom = DistanceFrom;
+ #region Defining distance measure reference if not found
+ else
+ {
+ if (finalDistanceFrom == null)
+ {
+ if (_distanceFrom_Auto == null)
+ {
+ Camera c = Camera.main;
+ if (c) _distanceFrom_Auto = c.transform;
+ else
+ {
+ if (!wasCameraSearch)
+ {
+#if UNITY_2023_1_OR_NEWER
+ c = FindFirstObjectByType();
+#else
+ c = FindObjectOfType();
+#endif
+ if (c) _distanceFrom_Auto = c.transform;
+ wasCameraSearch = true;
+ }
+ }
+ }
+
+ finalDistanceFrom = _distanceFrom_Auto;
+ }
+ }
+ #endregion
+
+
+ // If we are using distance limitation
+ if (MaximumDistance > 0f && finalDistanceFrom != null)
+ {
+ if (!maxDistanceExceed) // If look motion is not out of look range etc.
+ {
+ float distance = GetDistanceMeasure(finalDistanceFrom.position);
+
+ if (distance > MaximumDistance + MaximumDistance * MaxOutDistanceFactor)
+ maxDistanceExceed = true;
+
+ distanceWeight += Time.unscaledDeltaTime * (1f / FadeDuration);
+ if (distanceWeight > 1f) distanceWeight = 1f;
+ }
+ else // When disabling tail animator
+ {
+ // Entering back distance range
+ float distance = GetDistanceMeasure(finalDistanceFrom.position);
+ if (distance <= MaximumDistance) maxDistanceExceed = false;
+
+ distanceWeight -= Time.unscaledDeltaTime * (1f / FadeDuration);
+ if (distanceWeight < 0f) distanceWeight = 0f;
+ }
+ }
+ else // If we don't use max of distance feature
+ {
+ maxDistanceExceed = false;
+ distanceWeight = 1f;
+ }
+ }
+
+
+ #endregion
+
+
+ }
+
+}
\ No newline at end of file
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Logic.Limits.cs.meta b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Logic.Limits.cs.meta
new file mode 100644
index 000000000..9d651dc2f
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Logic.Limits.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: bfe18301d3b8b4e49b7767eb91d25c7e
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Logic.Smoothing.cs b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Logic.Smoothing.cs
new file mode 100644
index 000000000..0919639fc
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Logic.Smoothing.cs
@@ -0,0 +1,81 @@
+using UnityEngine;
+
+namespace FIMSpace.FTail
+{
+ public partial class TailAnimator2
+ {
+
+ #region Position
+
+ /// [Tail Calculations - TC] Smoothing position for _tc_bone changing _tc_smoothPos variable in iteration towards _tc_targetPos
+ Vector3 TailCalculations_SmoothPosition(Vector3 from, Vector3 to, TailSegment bone)
+ {
+ if (SmoothingStyle == EAnimationStyle.Accelerating)
+ return TailCalculations_SmoothPositionSmoothDamp(from, to, ref bone.VelocityHelper, bone.PositionSpeed);
+ else if (SmoothingStyle == EAnimationStyle.Quick)
+ return TailCalculations_SmoothPositionLerp(from, to, bone.PositionSpeed);
+ else
+ return TailCalculations_SmoothPositionLinear(from, to, bone.PositionSpeed );
+ }
+
+
+ /// Smoothing position for _tc_bone with lerp divide logics changing _tc_smoothPos variable in iteration towards _tc_targetPos
+ Vector3 TailCalculations_SmoothPositionLerp(Vector3 from, Vector3 to, float speed)
+ {
+ return Vector3.Lerp(from, to, secPeriodDelta * speed);
+ }
+
+ /// Smoothing position for _tc_bone with smooth damp method changing _tc_smoothPos variable in iteration towards _tc_targetPos
+ Vector3 TailCalculations_SmoothPositionSmoothDamp(Vector3 from, Vector3 to, ref Vector3 velo, float speed)
+ {
+ return Vector3.SmoothDamp(from, to, ref velo, Mathf.LerpUnclamped(0.08f, 0.0001f, Mathf.Sqrt(Mathf.Sqrt(speed))), Mathf.Infinity, rateDelta);
+ }
+
+ /// Smoothing position for _tc_bone linearly changing _tc_smoothPos variable in iteration towards _tc_targetPos
+ Vector3 TailCalculations_SmoothPositionLinear(Vector3 from, Vector3 to, float speed)
+ {
+ return Vector3.MoveTowards(from, to, deltaForLerps * speed * 45f);
+ }
+
+ #endregion
+
+
+ #region Rotation
+
+
+
+ /// [Tail Calculations - TC] Smoothing rotation for _tc_bone changing _tc_smoothRot variable in iteration towards _tc_targetRot
+ Quaternion TailCalculations_SmoothRotation(Quaternion from, Quaternion to, TailSegment bone)
+ {
+ if (SmoothingStyle == EAnimationStyle.Accelerating)
+ return TailCalculations_SmoothRotationSmoothDamp(from, to, ref bone.QVelocityHelper, bone.RotationSpeed);
+ else
+ if (SmoothingStyle == EAnimationStyle.Quick)
+ return TailCalculations_SmoothRotationLerp(from, to, bone.RotationSpeed);
+ else
+ return TailCalculations_SmoothRotationLinear(from, to, bone.RotationSpeed);
+ }
+
+ /// Smoothing rotation for _tc_bone with lerp divide logics changing _tc_smoothRot variable in iteration towards _tc_targetRot
+ Quaternion TailCalculations_SmoothRotationLerp(Quaternion from, Quaternion to, float speed)
+ {
+ return Quaternion.Lerp(from, to, secPeriodDelta * speed);
+ }
+
+ /// Smoothing rotation for _tc_bone with smooth damp method changing _tc_smoothRot variable in iteration towards _tc_targetRot
+ Quaternion TailCalculations_SmoothRotationSmoothDamp(Quaternion from, Quaternion to, ref Quaternion velo, float speed)
+ {
+ return FEngineering.SmoothDampRotation(from, to, ref velo, Mathf.LerpUnclamped(0.25f, 0.0001f, Mathf.Sqrt(Mathf.Sqrt(speed))), rateDelta);
+ }
+
+ /// Smoothing rotation for _tc_bone linearly changing _tc_smoothRot variable in iteration towards _tc_targetRot
+ Quaternion TailCalculations_SmoothRotationLinear(Quaternion from, Quaternion to, float speed)
+ {
+ return (Quaternion.RotateTowards(from, to, speed * deltaForLerps * 1600f));
+ }
+
+
+ #endregion
+
+ }
+}
\ No newline at end of file
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Logic.Smoothing.cs.meta b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Logic.Smoothing.cs.meta
new file mode 100644
index 000000000..d10219c1b
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Logic.Smoothing.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: d1f8936842303b74dbace3df066c79d2
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Logic.TailCalculations.cs b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Logic.TailCalculations.cs
new file mode 100644
index 000000000..470afad81
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Logic.TailCalculations.cs
@@ -0,0 +1,213 @@
+using UnityEngine;
+
+namespace FIMSpace.FTail
+{
+ public partial class TailAnimator2
+ {
+ /// Tail calculations start index for interations
+ int _tc_startI = 0;
+ /// Indexes in front of root
+ int _tc_startII = 1;
+ /// Delta time multiplied one itme instead of i-times
+ //float _tc_offsetDelta = 0.1f;
+ /// Full length of tail computed at initialize in world space, used for unify animation feature
+ public float _TC_TailLength { get; private set; }
+
+ /// Tail calculations helper bone class instance reference
+ TailSegment _tc_rootBone = null;
+
+ /// Tail calculations helper rotation variable to avoid GC
+ Quaternion _tc_lookRot = Quaternion.identity;
+ /// Tail calculations helper rotation variable to avoid GC
+ Quaternion _tc_targetParentRot = Quaternion.identity;
+
+ /// Chain root offset rotation for shaping and auto-waving features
+ Quaternion _tc_startBoneRotOffset = Quaternion.identity;
+ float _tc_tangle = 1f;
+
+
+ ///
+ /// Define root of chain >> _tc_rootBone - root bone of tail chain >> TailBones[0] or GhostParent
+ ///
+ void TailCalculations_Begin()
+ {
+ if (IncludeParent) // Include first bone in chain to be modified
+ {
+ _tc_startI = 0;
+ _tc_rootBone = TailSegments[0];
+ }
+ else // Leaving first bone in chain intact (exclude)
+ {
+ _tc_startI = 1;
+ if (TailSegments.Count > 1) _tc_rootBone = TailSegments[1]; else { _tc_rootBone = TailSegments[0]; _tc_startI = -1; }
+ }
+
+ _tc_startII = _tc_startI + 1;
+ if (_tc_startII > TailSegments.Count - 1) _tc_startII = -1;
+
+ if (Deflection > Mathf.Epsilon) if (!_pp_initialized) InitializePostProcessing();
+
+
+ if (Tangle < 0)
+ _tc_tangle = Mathf.LerpUnclamped(1f, 1.5f, Tangle + 1f);
+ else
+ _tc_tangle = Mathf.LerpUnclamped(1f, -4f, Tangle);
+ }
+
+
+
+ ///
+ /// Defining start bone root reference coordinates and initial processing
+ ///
+ void TailSegments_UpdateRootFeatures()
+ {
+ // Root bone rotation offset for auto-waving feature
+ if (UseWaving)
+ {
+ Waving_AutoSwingUpdate();
+ _tc_startBoneRotOffset = (WavingRotationOffset * RotationOffset);
+ }
+ else
+ _tc_startBoneRotOffset = RotationOffset;
+
+ // Sustain support
+ if (Sustain > Mathf.Epsilon) Waving_SustainUpdate();
+
+ // Post process advanced features
+ if (PostProcessingNeeded()) PostProcessing_Begin();
+
+ }
+
+
+
+ ///
+ /// Processing calculated simple segment position with special effects like limiting / collision / smoothing etc.
+ /// Calling methods using bone's parent variables
+ ///
+ void TailCalculations_SegmentPreProcessingStack(TailSegment child)
+ {
+ if (!UseCollision) // Basic motion without collision
+ // Different update order with enable/disable collisions to avoid jittering on angle limiting
+ {
+ // Limit segments angles
+ if (AngleLimit < 181) child.ProceduralPosition = AngleLimiting(child, child.ProceduralPosition);
+
+ // Smoothing motion
+ if (child.PositionSpeed < 1f) child.ProceduralPosition = TailCalculations_SmoothPosition(child.PreviousPosition /*+ _limiting_influenceOffset*/, child.ProceduralPosition, child);
+ }
+ else
+ {
+ // Smoothing motion
+ if (child.PositionSpeed < 1f) child.ProceduralPosition = TailCalculations_SmoothPosition(child.PreviousPosition /*+ _limiting_influenceOffset*/, child.ProceduralPosition, child);
+
+ // Computing collision offset as first thing
+ TailCalculations_ComputeSegmentCollisions(child, ref child.ProceduralPosition);
+
+ // Limit segments angles
+ if (AngleLimit < 181) child.ProceduralPosition = AngleLimiting(child, child.ProceduralPosition);
+ }
+
+
+ // Control stretching
+ if (MaxStretching < 1f) StretchingLimiting(child);
+
+ // Apply gravity
+ if (!FEngineering.VIsZero(child.Gravity) || UseWind) CalculateGravityPositionOffsetForSegment(child);
+
+ if (Axis2D > 0) Axis2DLimit(child);
+ }
+
+
+ ///
+ /// Post processing for segment if used for example deflection
+ ///
+ void TailCalculations_SegmentPostProcessing(TailSegment bone)
+ {
+ // Applying deflection
+ if (Deflection > Mathf.Epsilon) Deflection_SegmentOffsetSimple(bone, ref bone.ProceduralPosition);
+
+ // Soon there may be more post processes
+ }
+
+
+ ///
+ /// Second iteration for segments rotation calculations
+ /// Rotating segments towards calculated procedural positions with blending if used
+ ///
+ void TailCalculations_SegmentRotation(TailSegment child, Vector3 localOffset)
+ {
+
+ // Calculating correct rotation towards calculated position in parent orientation
+ _tc_lookRot = Quaternion.FromToRotation
+ ( // Support negative scale with transform direction
+ child.ParentBone.transform.TransformDirection(localOffset), // Child local pos offset - direction from parent true position towards default bone postion from keyframe animation
+ child.ProceduralPositionWeightBlended - child.ParentBone.ProceduralPositionWeightBlended // Direction from parent calculated position towards child target calculated postion
+ );
+
+ // Rotating towards desired orientation
+ _tc_targetParentRot = _tc_lookRot * child.ParentBone.transform.rotation;
+
+ if ( AnimateRoll)
+ {
+ _tc_targetParentRot = Quaternion.Lerp(child.ParentBone.TrueTargetRotation, _tc_targetParentRot, deltaForLerps * Mathf.LerpUnclamped(10f, 60f, child.RotationSpeed));
+ }
+
+ // Notice than we setting parent rotation from child relation : parent rotation is dictating child position
+ // Remember transform rotaiton before smoothing reference rotation !!!
+ child.ParentBone.TrueTargetRotation = _tc_targetParentRot;
+
+ // Remembering previous value before changing to new
+ child.ParentBone.PreviousPosReferenceRotation = child.ParentBone.PosRefRotation;
+
+ // Setting positions reference rotation separately
+ if ( !AnimateRoll) if (child.RotationSpeed < 1f) _tc_targetParentRot = TailCalculations_SmoothRotation(child.ParentBone.PosRefRotation, _tc_targetParentRot, child);
+
+ child.ParentBone.PosRefRotation = _tc_targetParentRot;
+ }
+
+ ///
+ /// Detached tail mode works on slightly different vector logics
+ ///
+ void TailCalculations_SegmentRotationDetached(TailSegment child, Vector3 localOffset)
+ {
+ //Quaternion tgtRot = child.ParentBone.TrueTargetRotation;
+ //if (child.IsDetachable)
+ //{
+ // tgtRot = FEngineering.QToWorld(BaseTransform.rotation, child.ParentBone.InitialLocalRotationInRoot);
+ //}
+
+ _tc_lookRot = Quaternion.FromToRotation
+ (
+ child.ParentBone.transform.TransformDirection(localOffset), // Child local pos offset - direction from parent true position towards default bone postion
+ child.ProceduralPositionWeightBlended - child.ParentBone.ProceduralPositionWeightBlended // Direction from parent calculated position towards child target calculated postion
+ );
+
+
+
+ _tc_targetParentRot = _tc_lookRot * child.transform.rotation;
+ if (AnimateRoll) _tc_targetParentRot = Quaternion.Lerp(child.ParentBone.TrueTargetRotation, _tc_targetParentRot, deltaForLerps * Mathf.LerpUnclamped(10f, 60f, child.RotationSpeed));
+
+ child.ParentBone.TrueTargetRotation = _tc_targetParentRot;
+ child.ParentBone.PreviousPosReferenceRotation = child.ParentBone.PosRefRotation;
+
+ if (!AnimateRoll) if (child.RotationSpeed < 1f) _tc_targetParentRot = TailCalculations_SmoothRotation(child.ParentBone.PosRefRotation, _tc_targetParentRot, child);
+
+ child.ParentBone.PosRefRotation = _tc_targetParentRot;
+
+ }
+
+ ///
+ /// Applying tail motion to transforms
+ /// Accesing parent of bone to change it's rotation
+ ///
+ void TailCalculations_ApplySegmentMotion(TailSegment child)
+ {
+ child.ParentBone.transform.rotation = child.ParentBone.TrueTargetRotation;
+ child.transform.position = child.ProceduralPositionWeightBlended;
+
+ child.RefreshFinalPos(child.ProceduralPositionWeightBlended);
+ child.ParentBone.RefreshFinalRot(child.ParentBone.TrueTargetRotation);
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Logic.TailCalculations.cs.meta b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Logic.TailCalculations.cs.meta
new file mode 100644
index 000000000..f1adb20f3
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Logic.TailCalculations.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 94df3f76d7ce99142bd705f911882f19
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Logic.TailSegments.cs b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Logic.TailSegments.cs
new file mode 100644
index 000000000..bcfbb9182
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Logic.TailSegments.cs
@@ -0,0 +1,334 @@
+using UnityEngine;
+
+namespace FIMSpace.FTail
+{
+ ///
+ /// FC: Calculations focused on single tail bone segments operations
+ ///
+ public partial class TailAnimator2
+ {
+ // Motion controll variables
+ float _sg_springVelo = 0.5f;
+ //float _sg_curl = 0.5f;
+ float _sg_curly = 0.5f;
+
+ // Motion calculation variables
+ Vector3 _sg_push;
+ Vector3 _sg_targetPos;
+ Vector3 _sg_targetChildWorldPosInParentFront;
+ Vector3 _sg_dirToTargetParentFront;
+ Quaternion _sg_orientation;
+ float _sg_slitFactor = 0.5f;
+
+
+ void TailSegment_PrepareBoneLength(TailSegment child)
+ {
+ // Remember bone scale referenced from initial position
+ child.BoneDimensionsScaled = Vector3.Scale(child.ParentBone.transform.lossyScale * child.LengthMultiplier, child.LastKeyframeLocalPosition);
+ child.BoneLengthScaled = child.BoneDimensionsScaled.magnitude; //(child.ParentBone.transform.position - child.transform.position).magnitude * child.LengthMultiplier;
+ }
+
+ ///
+ /// Preparing motion parameters for individual segment settings
+ ///
+ void TailSegment_PrepareMotionParameters(TailSegment child)
+ {
+ //// Non-Slithery
+ //_sg_curly = Mathf.LerpUnclamped(0.6f, 0.15f, child.Curling);
+ //_sg_springVelo = Mathf.LerpUnclamped(0.65f, 0.9f, child.Springiness);
+
+ //// Slithery Blend
+ //_sg_curly = Mathf.Lerp(_sg_curly, Mathf.LerpUnclamped(0.99f, 0.135f, child.Curling), child.Slithery);
+ //_sg_springVelo = Mathf.Lerp(_sg_springVelo, Mathf.LerpUnclamped(0.0f, 0.8f, child.Springiness), child.Slithery);
+
+ // Non-Slithery
+ _sg_curly = Mathf.LerpUnclamped(0.5f, 0.125f, child.Curling);
+ _sg_springVelo = Mathf.LerpUnclamped(0.65f, 0.9f, child.Springiness);
+
+ // Slithery Blend
+ _sg_curly = Mathf.Lerp(_sg_curly, Mathf.LerpUnclamped(0.95f, 0.135f, child.Curling), child.Slithery);
+ _sg_springVelo = Mathf.Lerp(_sg_springVelo, Mathf.LerpUnclamped(0.1f, 0.85f, child.Springiness), child.Slithery);
+ }
+
+
+ ///
+ /// Preparing segment positioning parameters
+ ///
+ void TailSegment_PrepareVelocity(TailSegment child)
+ {
+ // Velocity change check
+ _sg_push = (child.ProceduralPosition - child.PreviousPosition);
+
+ // Remember actual position after using previous position memory
+ child.PreviousPosition = child.ProceduralPosition;
+
+ // Collision slippery modify
+ float swinginess = _sg_springVelo;
+ if (child.CollisionContactFlag) swinginess *= child.Slippery;
+
+ // Tail Motion velocity motion base calculations
+ child.ProceduralPosition += _sg_push * swinginess;
+
+ // Remember previous push for sustain feature
+ child.PreviousPush = _sg_push;
+ }
+
+
+ void TailSegment_PrepareRotation(TailSegment child)
+ {
+ _sg_targetChildWorldPosInParentFront = child.ParentBone.ProceduralPosition + TailSegment_GetSwingRotation(child, _sg_slitFactor) * child.BoneDimensionsScaled; // Local offset scaled with custom rotation
+ }
+
+ void TailSegment_PrepareRotationDetached(TailSegment child)
+ {
+ _sg_targetChildWorldPosInParentFront = child.ParentBone.ProceduralPosition + TailSegment_GetSwingRotationDetached(child, _sg_slitFactor) * child.BoneDimensionsScaled; // Local offset scaled with custom rotation
+ }
+
+ ///
+ /// Base position processing for swingy parameters animation
+ /// Changing UnprocessedPosition value in child argument
+ ///
+ void TailSegment_BaseSwingProcessing(TailSegment child)
+ {
+ _sg_slitFactor = child.Slithery; // Collision fixing for slithery calculations
+ if (child.CollisionContactRelevancy > 0f) _sg_slitFactor = ReflectCollision; // (0.5f - Mathf.Min(0.5f, child.CollisionContactRelevancy * 10f) ) * child.Slithery;
+
+ _sg_dirToTargetParentFront = _sg_targetChildWorldPosInParentFront - child.ProceduralPosition;
+
+ // Unifying bendiness parameters on tail length and segments count then translating
+ if (UnifyBendiness > 0f)
+ child.ProceduralPosition += _sg_dirToTargetParentFront * secPeriodDelta *
+ _sg_curly * TailSegment_GetUnifiedBendinessMultiplier(child);
+ else
+ // Translating toward target position without restricitons
+ child.ProceduralPosition += _sg_dirToTargetParentFront * _sg_curly * secPeriodDelta;
+
+ if (Tangle != 0f)
+ if (child.Slithery >= 1f)
+ child.ProceduralPosition = Vector3.LerpUnclamped(child.ProceduralPosition, _sg_targetChildWorldPosInParentFront, _tc_tangle);
+ }
+
+
+ ///
+ /// Processing position for blending weight
+ ///
+ void TailSegment_PreRotationPositionBlend(TailSegment child)
+ {
+ if (child.BlendValue * conditionalWeight < 1f)
+ child.ProceduralPositionWeightBlended = Vector3.LerpUnclamped(
+ child.transform.position, child.ProceduralPosition, child.BlendValue * conditionalWeight);
+ //child.ParentBone.transform.TransformVector(child.LastFinalLocalPosition), child.ProceduralPosition, child.BlendValue);
+ else
+ child.ProceduralPositionWeightBlended = child.ProceduralPosition;
+ }
+
+
+ ///
+ /// Calculations for slithery tail motion reference parent rotation
+ ///
+ Quaternion TailSegment_RotationSlithery(TailSegment child)
+ {
+
+ if (!FEngineering.QIsZero(child.Curving))
+ {
+ return GetSlitheryReferenceRotation(child) // Back rotation for parent of parent bone
+ * child.Curving // Curving
+ * child.ParentBone.LastKeyframeLocalRotation; // Sync with animator
+ }
+ else
+ {
+ return GetSlitheryReferenceRotation(child) // Back rotation for parent of parent bone
+ * child.ParentBone.LastKeyframeLocalRotation; // Sync with animator
+ }
+ }
+
+ ///
+ /// Calculations for slithery tail motion reference parent rotation
+ ///
+ Quaternion TailSegment_RotationSlitheryDetached(TailSegment child)
+ {
+
+ if (!FEngineering.QIsZero(child.Curving))
+ {
+ return GetSlitheryReferenceRotation(child) // Back rotation for parent of parent bone
+ * child.Curving // Curving
+ * child.ParentBone.InitialLocalRotation; // Sync with animator
+ }
+ else
+ {
+ return GetSlitheryReferenceRotation(child) // Back rotation for parent of parent bone
+ * child.ParentBone.InitialLocalRotation; // Sync with animator
+ }
+ }
+
+ Quaternion GetSlitheryReferenceRotation(TailSegment child)
+ {
+ if (child.Slithery <= 1f)
+ return child.ParentBone.ParentBone.PosRefRotation;
+ else
+ {
+ return Quaternion.LerpUnclamped(child.ParentBone.ParentBone.PosRefRotation,
+ child.ParentBone.ParentBone.PreviousPosReferenceRotation, (child.Slithery - 1f) * 5f);
+ }
+ }
+
+ ///
+ /// Calculations for stiff tail motion reference parent rotation
+ ///
+ Quaternion TailSegment_RotationStiff(TailSegment child)
+ {
+ // Curving feature
+ if (!FEngineering.QIsZero(child.Curving))
+ {
+ return child.ParentBone.transform.rotation * // Parent bone rotation
+ MultiplyQ(child.Curving, child.Index * 2f) // Curving multiplier
+ ;
+ }
+ else // No Curving
+ {
+ return child.ParentBone.transform.rotation; // Parent bone rotation
+ }
+ }
+
+ ///
+ /// Defining style of tail motion
+ ///
+ Quaternion TailSegment_GetSwingRotation(TailSegment child, float curlFactor)
+ {
+ if (curlFactor >= 1f) // Slithery == 1
+ {
+ return TailSegment_RotationSlithery(child);
+ }
+ else if (curlFactor > Mathf.Epsilon) // Blend non slithery with slithery feature
+ {
+ return Quaternion.LerpUnclamped(
+ TailSegment_RotationStiff(child), // A - Stiff
+ TailSegment_RotationSlithery(child), // B - Slithery
+ curlFactor); // Lerp
+ }
+ else // Slithery == 0
+ return TailSegment_RotationStiff(child);
+ }
+
+
+ Quaternion TailSegment_GetSwingRotationDetached(TailSegment child, float curlFactor)
+ {
+ if (curlFactor >= 1f) // Slithery == 1
+ {
+ return TailSegment_RotationSlitheryDetached(child);
+ }
+ else if (curlFactor > Mathf.Epsilon) // Blend non slithery with slithery feature
+ {
+ return Quaternion.LerpUnclamped(
+ TailSegment_RotationStiff(child), // A - Stiff
+ TailSegment_RotationSlitheryDetached(child), // B - Slithery
+ curlFactor); // Lerp
+ }
+ else // Slithery == 0
+ return TailSegment_RotationStiff(child);
+ }
+
+
+ ///
+ /// Calculating multiplier value for translation based on tail length and segments count
+ /// To make different length and segment count tails behave in similar way
+ ///
+ float TailSegment_GetUnifiedBendinessMultiplier(TailSegment child)
+ {
+ // When short tail -> 0.2f / 1.25f -> 0.16 -> We want here small mul value
+ // When long and many segments -> 0.1f / 8f -> 0.0125 -> We want here high mul value
+ float segmentRatio = (child.BoneLength / _TC_TailLength);
+ segmentRatio = Mathf.Pow(segmentRatio, 0.5f);
+
+ if (segmentRatio == 0f) segmentRatio = 1f; // No dividing by zero ¯\_(ツ)_/¯
+
+ float unifyMul = (_sg_curly / segmentRatio) / 2f;
+ unifyMul = Mathf.LerpUnclamped(_sg_curly, unifyMul, UnifyBendiness);
+
+ // Clamp extreme values
+ if (unifyMul < 0.15f) unifyMul = 0.15f; else if (unifyMul > 1.4f) unifyMul = 1.4f;
+
+ //Debug.Log(System.Math.Round( unifyMul, 3) + " Count = " + TailSegments.Count + " child.BoneLength " + child.BoneLength + "_tc_tailLength " + _TC_TailLength + "curl = " + _sg_curly + " Mul " + unifyMul + " segmentRatio " + segmentRatio + " mixed = " + (_sg_curly * unifyMul) );
+ return unifyMul;
+ }
+
+
+ ///
+ /// Updateing root parent bone with component parameters and features
+ ///
+ public void TailSegments_UpdateCoordsForRootBone(TailSegment parent)
+ {
+ TailSegment root = TailSegments[0];
+ root.transform.localRotation = root.LastKeyframeLocalRotation * _tc_startBoneRotOffset;
+ //parent.transform.localRotation = parent.LastKeyframeLocalRotation * _tc_startBoneRotOffset;
+
+ parent.PreviousPosReferenceRotation = parent.PosRefRotation;
+ parent.PosRefRotation = parent.transform.rotation;
+
+ parent.PreviousPosition = parent.ProceduralPosition;
+ parent.ProceduralPosition = parent.transform.position;
+ if (DetachChildren) root.TrueTargetRotation = root.transform.rotation;
+
+ parent.RefreshFinalPos(parent.transform.position);
+
+ parent.ProceduralPositionWeightBlended = parent.ProceduralPosition;
+
+ if (parent.ParentBone.transform != null)
+ {
+ // Update of ghost parent for slithery motion
+ parent.ParentBone.PreviousPosReferenceRotation = parent.ParentBone.PosRefRotation;
+ parent.ParentBone.PreviousPosition = parent.ParentBone.ProceduralPosition;
+
+ parent.ParentBone.ProceduralPosition = parent.ParentBone.transform.position;
+ parent.ParentBone.PosRefRotation = parent.ParentBone.transform.rotation;
+
+ parent.ParentBone.ProceduralPositionWeightBlended = parent.ParentBone.ProceduralPosition;
+ }
+
+ TailSegments[_tc_startI].ChildBone.PreviousPosition += _waving_sustain;
+ root.RefreshKeyLocalPosition();
+ }
+
+
+ ///
+ /// Begin update operations for additionaly genrated child bone of chain
+ ///
+ public void TailCalculations_UpdateArtificialChildBone(TailSegment child)
+ {
+ // Pre processing with limiting, gravity etc.
+ //TailCalculations_SegmentPreProcessingStack(lastChild);
+
+ //// Blending animation weight
+ //TailSegment_PreRotationPositionBlend(lastChild);
+
+ if (DetachChildren) TailSegment_PrepareRotationDetached(child); else TailSegment_PrepareRotation(child);
+ TailSegment_BaseSwingProcessing(child);
+
+ if (child.PositionSpeed < 1f) child.ProceduralPosition = TailCalculations_SmoothPosition(child.PreviousPosition /*+ _limiting_influenceOffset*/, child.ProceduralPosition, child);
+
+ if (MaxStretching < 1f) StretchingLimiting(child);
+
+ if (!FEngineering.VIsZero(child.Gravity) || UseWind) CalculateGravityPositionOffsetForSegment(child);
+
+ if (Axis2D > 0) Axis2DLimit(child);
+
+ child.CollisionContactRelevancy = -1f;
+
+ // Blending or just setting target position
+ if (child.BlendValue * conditionalWeight < 1f)
+ child.ProceduralPositionWeightBlended = Vector3.LerpUnclamped(
+ child.ParentBone.transform.TransformPoint(child.LastKeyframeLocalPosition), child.ProceduralPosition, child.BlendValue * conditionalWeight);
+ else
+ child.ProceduralPositionWeightBlended = child.ProceduralPosition;
+ }
+
+
+ ///
+ /// Refreshing position for additionaly generated parent bone
+ ///
+ public void Editor_TailCalculations_RefreshArtificialParentBone()
+ {
+ GhostParent.ProceduralPosition = GhostParent.transform.position + FEngineering.TransformVector(GhostParent.transform.rotation, GhostParent.transform.lossyScale, GhostParent.LocalOffset);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Logic.TailSegments.cs.meta b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Logic.TailSegments.cs.meta
new file mode 100644
index 000000000..6f489ac76
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Logic.TailSegments.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 90e74887a690e1c44b4c416583a50f76
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Logic.UpdateStacks.cs b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Logic.UpdateStacks.cs
new file mode 100644
index 000000000..f22b5fa19
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Logic.UpdateStacks.cs
@@ -0,0 +1,255 @@
+using UnityEngine;
+
+namespace FIMSpace.FTail
+{
+ public partial class TailAnimator2
+ {
+
+ void SimulateTailMotionFrame(bool pp)
+ {
+ #region Prepare base positions calculation for tail segments to use in coords calculations and as reference
+
+ TailSegments_UpdateRootFeatures();
+
+ TailSegments_UpdateCoordsForRootBone(_tc_rootBone);
+
+ if (pp) PostProcessing_ReferenceUpdate();
+
+
+ if (_tc_startI > -1)
+ {
+ TailSegment child = TailSegments[_tc_startI]; // Used in while() loops below
+ // Going in while is 2x faster than for(i;i;i) loop
+
+ if (!DetachChildren)
+ {
+ while (child != GhostChild)
+ {
+ // Remember bone scale referenced from initial position
+ child.BoneDimensionsScaled = Vector3.Scale(child.ParentBone.transform.lossyScale * child.LengthMultiplier, child.LastKeyframeLocalPosition);
+ child.BoneLengthScaled = child.BoneDimensionsScaled.magnitude; //(child.ParentBone.transform.position - child.transform.position).magnitude * child.LengthMultiplier;
+
+ // Preparing parameter values adapted to stiff and slithery character and blended
+ TailSegment_PrepareBoneLength(child);
+ TailSegment_PrepareMotionParameters(child);
+
+ // Velocity changes detection
+ TailSegment_PrepareVelocity(child);
+
+ child = child.ChildBone;
+ }
+ }
+ else
+ {
+ while (child != GhostChild)
+ {
+ // Remember bone scale referenced from initial position
+ child.BoneDimensionsScaled = Vector3.Scale(child.ParentBone.transform.lossyScale * child.LengthMultiplier, child.InitialLocalPosition);
+ child.BoneLengthScaled = child.BoneDimensionsScaled.magnitude; //(child.ParentBone.transform.position - child.transform.position).magnitude * child.LengthMultiplier;
+ TailSegment_PrepareMotionParameters(child);
+ TailSegment_PrepareVelocity(child);
+ child = child.ChildBone;
+ }
+ }
+ }
+
+ // Udpate for artificial end bone
+ TailSegment_PrepareBoneLength(GhostChild);
+ TailSegment_PrepareMotionParameters(GhostChild);
+ TailSegment_PrepareVelocity(GhostChild);
+
+ #endregion
+
+ #region Processing segments, calculating full target coords and apply to transforms
+
+ if (_tc_startII > -1)
+ {
+ // Ignoring root related calculations
+ TailSegment child = TailSegments[_tc_startII];
+
+ if (!DetachChildren)
+ {
+ while (child != GhostChild)
+ {
+ TailSegment_PrepareRotation(child);
+ TailSegment_BaseSwingProcessing(child);
+
+ // Pre processing with limiting, gravity etc.
+ TailCalculations_SegmentPreProcessingStack(child);
+
+ if (pp) TailCalculations_SegmentPostProcessing(child);
+
+ // Blending animation weight
+ TailSegment_PreRotationPositionBlend(child);
+
+ child = child.ChildBone;
+ }
+ }
+ else
+ {
+ while (child != GhostChild)
+ {
+ TailSegment_PrepareRotationDetached(child);
+ TailSegment_BaseSwingProcessing(child);
+ TailCalculations_SegmentPreProcessingStack(child);
+ if (pp) TailCalculations_SegmentPostProcessing(child);
+ TailSegment_PreRotationPositionBlend(child);
+ child = child.ChildBone;
+ }
+ }
+ }
+
+ // Applying processing for artificial child bone without transform
+ TailCalculations_UpdateArtificialChildBone(GhostChild);
+
+ #endregion
+
+ }
+
+ void UpdateTailAlgorithm()
+ {
+ TailCalculations_Begin(); // Root definition
+
+ if (DeltaType != EFDeltaType.UnscaledDeltaTime && Time.timeScale == 0f) // Pause motion
+ {
+ if (_tc_startI > -1)
+ {
+ TailSegment segment = TailSegments[_tc_startI];
+
+ while (segment != null)
+ {
+ if (segment.transform)
+ {
+ segment.transform.position = segment.LastFinalPosition;
+ segment.transform.rotation = segment.LastFinalRotation;
+ }
+ else break;
+
+ segment = segment.ChildBone;
+ }
+ }
+
+ return;
+ }
+
+ if (framesToSimulate != 0) // If framerate not defined then framesToSimulate is always == 1
+ {
+
+ if (UseCollision) BeginCollisionsUpdate(); // Updating colliders to collide with
+
+ // If post processing is needed we computing reference coordinates
+ bool postProcesses = PostProcessingNeeded();
+
+ MotionInfluenceLimiting();
+
+ for (int i = 0; i < framesToSimulate; i++) // Simulating update frames
+ SimulateTailMotionFrame(postProcesses);
+
+ // Updating root bone position
+ TailSegments[_tc_startI].transform.position = TailSegments[_tc_startI].ProceduralPositionWeightBlended;
+ TailSegments[_tc_startI].RefreshFinalPos(TailSegments[_tc_startI].ProceduralPositionWeightBlended);
+ //TailSegments[_tc_startI].RefreshFinalLocalPos(TailSegments[_tc_startI].transform.localPosition);
+
+ if (!DetachChildren) // When using common algorithm
+ {
+ // Applying calculated coords to transforms
+ if (_tc_startII > -1)
+ {
+ TailSegment child = TailSegments[_tc_startII]; // Used in while() loops below
+ while (child != GhostChild)
+ {
+ // Calculate rotation
+ TailCalculations_SegmentRotation(child, child.LastKeyframeLocalPosition);
+
+ // Apply coords to segments
+ TailCalculations_ApplySegmentMotion(child);
+ child = child.ChildBone;
+ }
+ }
+ }
+ else // Detached mode needs some changes
+ {
+ #region Detached Mode
+
+ if (_tc_startII > -1)
+ {
+ TailSegment child = TailSegments[_tc_startII]; // Used in while() loops below
+ while (child != GhostChild)
+ {
+ TailCalculations_SegmentRotation(child, child.InitialLocalPosition);
+ //TailCalculations_SegmentRotationDetached(child, child.InitialLocalPosition);
+ TailCalculations_ApplySegmentMotion(child);
+ child = child.ChildBone;
+ }
+ }
+
+ #endregion
+ }
+
+ // If ghost child has transform let's apply motion too (change rotation of last bone)
+ TailCalculations_SegmentRotation(GhostChild, GhostChild.LastKeyframeLocalPosition);
+ GhostChild.ParentBone.transform.rotation = GhostChild.ParentBone.TrueTargetRotation;
+ GhostChild.ParentBone.RefreshFinalRot(GhostChild.ParentBone.TrueTargetRotation);
+
+ if (GhostChild.transform)
+ {
+ GhostChild.RefreshFinalPos(GhostChild.transform.position);
+ GhostChild.RefreshFinalRot(GhostChild.transform.rotation);
+ }
+ }
+ else // Skipping tail motion simulation and just applying coords computed lately
+ // Executed only when using target UpdateRate
+ {
+
+ if (InterpolateRate)
+ {
+ secPeriodDelta = rateDelta / 24f;
+ deltaForLerps = secPeriodDelta; // Unify delta value not amplified -> 1f / rate
+
+ SimulateTailMotionFrame(PostProcessingNeeded());
+
+ if (_tc_startII > -1)
+ {
+ TailSegment child = TailSegments[_tc_startII];
+ while (child != GhostChild)
+ {
+ TailCalculations_SegmentRotation(child, child.LastKeyframeLocalPosition);
+ TailCalculations_ApplySegmentMotion(child);
+ child = child.ChildBone;
+ }
+ }
+
+ TailCalculations_SegmentRotation(GhostChild, GhostChild.LastKeyframeLocalPosition);
+ GhostChild.ParentBone.transform.rotation = GhostChild.ParentBone.TrueTargetRotation;
+ GhostChild.ParentBone.RefreshFinalRot(GhostChild.ParentBone.TrueTargetRotation);
+ }
+ else
+ {
+ if (_tc_startI > -1)
+ {
+ TailSegment segment = TailSegments[_tc_startI];
+
+ while (segment != null)
+ {
+ if (segment.transform)
+ {
+ segment.transform.position = segment.LastFinalPosition;
+ segment.transform.rotation = segment.LastFinalRotation;
+ }
+ else break;
+
+ segment = segment.ChildBone;
+ }
+ }
+ else
+ {
+
+ }
+ }
+ }
+
+ }
+
+
+ }
+}
\ No newline at end of file
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Logic.UpdateStacks.cs.meta b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Logic.UpdateStacks.cs.meta
new file mode 100644
index 000000000..4e90d379a
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Logic.UpdateStacks.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 6fd7b67b43fe5784cb55474315c6c30e
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Misc.cs b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Misc.cs
new file mode 100644
index 000000000..00ad7986e
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Misc.cs
@@ -0,0 +1,396 @@
+using System.Collections;
+using UnityEngine;
+
+namespace FIMSpace.FTail
+{
+ public partial class TailAnimator2
+ {
+ /// For resetting tail procedural data when just enabling animator
+ bool wasDisabled = true;
+ /// Just selected delta value from Time.delta unmodified
+ float justDelta = 0.016f;
+ /// Delta used for component logics -> it's value is near full 1f
+ float secPeriodDelta = 0.5f;
+ /// Delta for pos = Lerp(pos, target) operations -> It's value is desired to be around 0.016f but much higher in higher fps domain
+ float deltaForLerps = 0.016f;
+ /// Helper delta for target update rate usage -> -> It's value is desired to be 1f / targetRate
+ float rateDelta = 0.016f;
+
+ /// Helper for calculating stable delta calculations
+ protected float collectedDelta = 0f;
+ /// How many udpate loops should be done according to stable update rate
+ protected int framesToSimulate = 1;
+ protected int previousframesToSimulate = 1;
+
+ bool updateTailAnimator = false;
+
+ ///
+ /// Conditions to do any calculations within Tail Animator
+ ///
+ void CheckIfTailAnimatorShouldBeUpdated()
+ {
+ if (!initialized)
+ {
+ if (StartAfterTPose)
+ {
+ startAfterTPoseCounter++;
+ if (startAfterTPoseCounter > 6) Init();
+ }
+
+ updateTailAnimator = false;
+ return;
+ }
+
+ #region Debug "`" disable key for editor only
+
+#if UNITY_EDITOR
+#if ENABLE_LEGACY_INPUT_MANAGER
+ if (Input.GetKey(KeyCode.BackQuote))
+ {
+ updateTailAnimator = false;
+ return;
+ }
+#endif
+#endif
+
+ #endregion
+
+
+ if (UseMaxDistance)
+ {
+ MaxDistanceCalculations();
+ conditionalWeight = OverrideWeight * distanceWeight;
+ }
+ else
+ conditionalWeight = OverrideWeight;
+
+
+ #region Force disable transition implementation
+
+ if (_forceDisable) // fade to disabled state
+ {
+ if (FadeDuration > 0f)
+ {
+ _forceDisableElapsed += Time.unscaledDeltaTime * (1f / FadeDuration);
+ if (_forceDisableElapsed > 1f) _forceDisableElapsed = 1f;
+ }
+ else
+ _forceDisableElapsed = 1f;
+
+ conditionalWeight *= 1f - _forceDisableElapsed;
+ }
+ else // Fade back in
+ {
+ if (_forceDisableElapsed > 0f)
+ if (FadeDuration > 0f)
+ {
+ _forceDisableElapsed -= Time.unscaledDeltaTime * (1f / FadeDuration);
+ if (_forceDisableElapsed < 0f) _forceDisableElapsed = 0f;
+ conditionalWeight *= 1f - _forceDisableElapsed;
+ }
+ }
+
+ #endregion
+
+
+ if (DisabledByInvisibility()) return;
+
+ //#region Triggering Animate Physics Support
+
+ //if (AnimatePhysics)
+ //{
+ // if (!animatePhysicsWorking) StartCoroutine(AnimatePhysicsClock());
+ // if (!triggerAnimatePhysics) { updateTailAnimator = false; return; } else triggerAnimatePhysics = false;
+ //}
+
+ //#endregion
+
+ if (UseCollision) if (!collisionInitialized) SetupSphereColliders();
+
+ if (TailSegments.Count == 0)
+ {
+ Debug.LogError("[TAIL ANIMATOR] No tail bones defined in " + name + " !");
+ initialized = false;
+ updateTailAnimator = false;
+ return;
+ }
+
+
+ // Enabling / disabling with blending value
+ if (TailAnimatorAmount * conditionalWeight <= Mathf.Epsilon)
+ {
+ wasDisabled = true;
+ updateTailAnimator = false;
+ return;
+ }
+ else
+ {
+ if (wasDisabled)
+ {
+ User_ReposeTail();
+ previousWorldPosition = transform.position;
+ wasDisabled = false;
+ }
+ }
+
+ if (IncludeParent) if (TailSegments.Count > 0) if (!TailSegments[0].transform.parent) IncludeParent = false;
+
+ if (TailSegments.Count < 1)
+ {
+ updateTailAnimator = false;
+ return;
+ }
+
+ updateTailAnimator = true;
+ }
+
+
+ public bool DisabledByInvisibility()
+ {
+ if (OptimizeWithMesh != null)
+ {
+ bool somethingVisible = false;
+ if (OptimizeWithMesh.isVisible) somethingVisible = true;
+ else
+ {
+ if (OptimizeWithMeshes != null)
+ if (OptimizeWithMeshes.Length > 0)
+ for (int i = 0; i < OptimizeWithMeshes.Length; i++)
+ {
+ if (OptimizeWithMeshes[i] == null) continue;
+ if (OptimizeWithMeshes[i].isVisible) { somethingVisible = true; break; }
+ }
+ }
+
+ if (somethingVisible == false) { updateTailAnimator = false; return true; }
+ }
+
+ return false; // Not Disabled
+ }
+
+
+ ///
+ /// Just defining delta time for component operations
+ ///
+ void DeltaTimeCalculations()
+ {
+ if (UpdateRate > 0) // If we setted target update rate
+ {
+ switch (DeltaType)
+ {
+ case EFDeltaType.SafeDelta: case EFDeltaType.DeltaTime: justDelta = Time.deltaTime / Mathf.Clamp(Time.timeScale, 0.01f, 1f); break;
+ case EFDeltaType.SmoothDeltaTime: justDelta = Time.smoothDeltaTime; break;
+ case EFDeltaType.UnscaledDeltaTime: justDelta = Time.unscaledDeltaTime; break;
+ case EFDeltaType.FixedDeltaTime: justDelta = Time.fixedDeltaTime; break;
+ }
+
+ justDelta *= TimeScale;
+ secPeriodDelta = 1f;
+ deltaForLerps = secPeriodDelta;
+ rateDelta = 1f / (float)UpdateRate;
+
+ StableUpdateRateCalculations();
+ }
+ else // Unlimited update rate
+ {
+ switch (DeltaType)
+ {
+ case EFDeltaType.SafeDelta: justDelta = Mathf.Lerp(justDelta, GetClampedSmoothDelta(), 0.075f); break;
+ case EFDeltaType.DeltaTime: justDelta = Time.deltaTime; break;
+ case EFDeltaType.SmoothDeltaTime: justDelta = Time.smoothDeltaTime; break;
+ case EFDeltaType.UnscaledDeltaTime: justDelta = Time.unscaledDeltaTime; break;
+ case EFDeltaType.FixedDeltaTime: justDelta = Time.fixedDeltaTime; break;
+ }
+
+ rateDelta = justDelta;
+ deltaForLerps = Mathf.Pow(secPeriodDelta, 0.1f) * 0.02f;
+ justDelta *= TimeScale;
+
+ // Helper parameter to not calculate "*60" i-times
+ secPeriodDelta = Mathf.Min(1f, justDelta * 60f);
+
+ framesToSimulate = 1;
+ previousframesToSimulate = 1;
+ }
+
+ }
+
+
+ ///
+ /// Calculating how many update loops should be done in this frame according to target update rate and elapsed deltaTime
+ ///
+ void StableUpdateRateCalculations()
+ {
+ previousframesToSimulate = framesToSimulate; // Remembering how many loops used in this frame for bones animation calibration in next frame
+ collectedDelta += justDelta; // Collecting delta time from game frames
+ framesToSimulate = 0; // Collecting delta for [one second] div by [UpdateRate] update so for one frame in static defined time rate
+
+ while (collectedDelta >= rateDelta) // Collected delta is big enough to do tail motion frame
+ {
+ collectedDelta -= rateDelta;
+ framesToSimulate += 1;
+ if (framesToSimulate >= 3) { collectedDelta = 0; break; } // Simulating up to 3 frames update in one unity game frame
+ }
+ }
+
+
+ ///
+ /// Preparing not animated bones, if animated they will be changed after Update() and before LateUpdate() by Unity Animator
+ ///
+ void PreCalibrateBones()
+ {
+ TailSegment child = TailSegments[0];
+
+ while (child != GhostChild)
+ {
+ child.PreCalibrate();
+ child = child.ChildBone;
+ }
+
+ }
+
+
+ ///
+ /// Preparing bones for animation synchronized with keyframe animations
+ ///
+ void CalibrateBones()
+ {
+ if (UseIK)
+ if (IKBlend > 0f)
+ {
+ UpdateIK();
+ }
+
+ _limiting_stretchingHelperTooLong = Mathf.Lerp(0.4f, 0.0f, MaxStretching);
+ _limiting_stretchingHelperTooShort = _limiting_stretchingHelperTooLong * 1.5f;
+ }
+
+
+ ///
+ /// Checking for null referencees in ghost chain list
+ ///
+ public void CheckForNullsInGhostChain()
+ {
+ if (_TransformsGhostChain == null) _TransformsGhostChain = new System.Collections.Generic.List();
+ for (int i = _TransformsGhostChain.Count - 1; i >= 0; i--)
+ {
+ if (_TransformsGhostChain[i] == null) _TransformsGhostChain.RemoveAt(i);
+ }
+ }
+
+
+
+ /// Helper variable for start after t-pose feature
+ int startAfterTPoseCounter;
+
+
+ ///
+ /// Limiting smooth delta in certain ranges to prevent jittery
+ ///
+ float GetClampedSmoothDelta()
+ {
+ return Mathf.Clamp(Time.smoothDeltaTime, 0f, 0.25f);
+ }
+
+
+ ///
+ /// Helper quaternion multiply method for non-slithery motion
+ ///
+ Quaternion MultiplyQ(Quaternion rotation, float times)
+ {
+ return Quaternion.AngleAxis(rotation.x * Mathf.Rad2Deg * times, Vector3.right) *
+ Quaternion.AngleAxis(rotation.z * Mathf.Rad2Deg * times, Vector3.forward) *
+ Quaternion.AngleAxis(rotation.y * Mathf.Rad2Deg * times, Vector3.up);
+ }
+
+
+ #region Curves Operations
+
+
+
+ ///
+ /// Evaluating value for tail segment from given clamped curve
+ ///
+ public float GetValueFromCurve(int i, AnimationCurve c)
+ {
+ if (!initialized) return c.Evaluate((float)i / (float)_TransformsGhostChain.Count);
+ else
+ return c.Evaluate(TailSegments[i].IndexOverlLength);
+ }
+
+
+ ///
+ /// Clamping curve keys to fit in given bounds
+ ///
+ public AnimationCurve ClampCurve(AnimationCurve a, float timeStart, float timeEnd, float lowest, float highest)
+ {
+ Keyframe[] keys = a.keys;
+
+ for (int i = 0; i < keys.Length; i++)
+ {
+ if (keys[i].time < timeStart) keys[i].time = timeStart; else if (keys[i].time > timeEnd) keys[i].time = timeEnd;
+ if (keys[i].value < lowest) keys[i].value = lowest; else if (keys[i].value > highest) keys[i].value = highest;
+ }
+
+ a.keys = keys;
+ return a;
+ }
+
+
+ ///
+ /// Checking if curve keyframes are not equal
+ ///
+ //public bool KeysChanged(Keyframe[] a, Keyframe[] b)
+ //{
+ // if (a == null || b == null) return true;
+ // if (a.Length != b.Length) return true;
+
+ // for (int i = 0; i < a.Length; i++)
+ // {
+ // if (a[i].time != b[i].time) return true;
+ // if (a[i].value != b[i].value) return true;
+ // if (a[i].inTangent != b[i].inTangent) return true;
+ // if (a[i].outTangent != b[i].outTangent) return true;
+ // }
+
+ // return false;
+ //}
+
+ #endregion
+
+
+ ///
+ /// Making sure ghost transform chain list is valid
+ ///
+ public void RefreshTransformsList()
+ {
+ if (_TransformsGhostChain == null) _TransformsGhostChain = new System.Collections.Generic.List();
+ else
+ for (int i = _TransformsGhostChain.Count - 1; i >= 0; i--)
+ if (_TransformsGhostChain[0] == null) _TransformsGhostChain.RemoveAt(i);
+ }
+
+ /// Getting helper bone marker used for animating last bone in chain
+ public TailSegment GetGhostChild() { return GhostChild; }
+
+ /// Helper flag for basic animate physics mode
+ bool fixedUpdated = false;
+
+ // Supporting second solution for fixed animate physics mode
+ private bool lateFixedIsRunning = false;
+ private bool fixedAllow = true;
+ private IEnumerator LateFixed()
+ {
+ WaitForFixedUpdate fixedWait = new WaitForFixedUpdate();
+ lateFixedIsRunning = true;
+
+ while (true)
+ {
+ yield return fixedWait;
+ PreCalibrateBones();
+ fixedAllow = true;
+ }
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Misc.cs.meta b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Misc.cs.meta
new file mode 100644
index 000000000..43540e600
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Misc.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 4eccae1c8b93bb74ab7e39c82b68bd06
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.PP.Deflection.cs b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.PP.Deflection.cs
new file mode 100644
index 000000000..5c419d956
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.PP.Deflection.cs
@@ -0,0 +1,130 @@
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace FIMSpace.FTail
+{
+ ///
+ /// POST POSITION PROCESSING - Deflection
+ ///
+ public partial class TailAnimator2
+ {
+ [Tooltip("Making tail segment deflection influence back segments")]
+ [Range(0f, 1f)]
+ public float Deflection = 0.0f;
+ [FPD_Suffix(1f, 89f, FPD_SuffixAttribute.SuffixMode.FromMinToMaxRounded, "°")]
+ public float DeflectionStartAngle = 10f;
+ [Range(0f, 1f)]
+ public float DeflectionSmooth = 0f;
+ [FPD_FixedCurveWindow(0, 0f, 1f, 1f, .65f, 0.4f, 1f, 0.9f)]
+ public AnimationCurve DeflectionFalloff = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f);
+ [Tooltip("Deflection can be triggered every time tail is waving but you not always would want this feature be enabled (different behaviour of tail motion)")]
+ public bool DeflectOnlyCollisions = true;
+
+ // Deflection feature variables
+ private List _defl_source;
+ private float _defl_treshold = 0.01f;
+
+
+ ///
+ /// Searching for deflection points on stored segments position
+ /// before post processing with deflection to avoid jitter
+ ///
+ void Deflection_BeginUpdate()
+ {
+ // Defining constants for segments
+ _defl_treshold = DeflectionStartAngle / 90f;
+ float smoothTime = DeflectionSmooth / 9f;
+
+ //for (int i = TailBones.Count-1; i >=_tc_startII; --i)
+ for (int i = _tc_startII; i < TailSegments.Count; i++)
+ {
+ TailSegment ppChild = _pp_reference[i];
+
+ // Checking deflection state to detect bend amount
+ bool cleared = ppChild.CheckDeflectionState(_defl_treshold, smoothTime, rateDelta);
+
+ // Detecting if deflection occured and adding as deflection source point
+ if (!cleared)
+ {
+ bool dependenciesMeet = true;
+
+ if (DeflectOnlyCollisions)
+ if (ppChild.CollisionContactRelevancy <= 0f)
+ dependenciesMeet = false; // No collision - no deflection
+
+ // Adding to deflection points list
+ if (dependenciesMeet)
+ {
+ Deflection_AddDeflectionSource(ppChild);
+ }
+ else
+ Deflection_RemoveDeflectionSource(ppChild);
+ }
+ else
+ {
+ Deflection_RemoveDeflectionSource(ppChild);
+ }
+ }
+ }
+
+
+ ///
+ /// Checking conditions to remove deflection source point
+ ///
+ void Deflection_RemoveDeflectionSource(TailSegment child)
+ {
+ if (child.DeflectionRestoreState() == null)
+ if (_defl_source.Contains(child)) _defl_source.Remove(child);
+ }
+
+
+ ///
+ /// Checking conditions to add deflection source point and sorting list by index
+ ///
+ void Deflection_AddDeflectionSource(TailSegment child)
+ {
+ if (child.DeflectionRelevant())
+ if (!_defl_source.Contains(child)) _defl_source.Add(child);
+ }
+
+ ///
+ /// Changing position of segment for deflection pose if deflection points are detected
+ ///
+ void Deflection_SegmentOffsetSimple(TailSegment child, ref Vector3 position)
+ {
+ if (child.Index == _tc_startI) return; // We not affecting first bone
+
+ // We using greatest deflection so we must remember last one used in loop
+ float lastDeflectionPower = 0f;
+
+ // Defining influence of further children deflection on this segment
+ // Going through all detected deflection points in this loop
+ for (int i = 0; i < _defl_source.Count; i++)
+ {
+ // When there is one deflection and another one in next index then deflection is cancelling
+ if (child.Index > _defl_source[i].Index) continue; // When segment is further on tail than deflection point then don't do anything here
+ if (child.Index == _defl_source[i].Index) continue; // Not deflecting deflection source point
+
+ // If we already used deflection with greater power
+ if (_defl_source[i].DeflectionFactor < lastDeflectionPower) continue;
+ lastDeflectionPower = _defl_source[i].DeflectionFactor;
+
+ // Using curve over segments from zero or previous deflection source towards current one
+ float preI = 0; if (i > 0) preI = _defl_source[i].Index; // Index for falloff curve
+ float timeOnCurve = Mathf.InverseLerp(preI, _defl_source[i].Index, child.Index); // Falloff from previous deflection point to next one over curve
+
+ // Direction from procedural position towards deflective position
+ Vector3 towardDeflection = _defl_source[i].DeflectionWorldPosition - child.ParentBone.ProceduralPosition;
+
+ // Calculating position of segment directed towards deflection compensation
+ Vector3 deflectedSegmentPos = child.ParentBone.ProceduralPosition;
+ deflectedSegmentPos += towardDeflection.normalized * child.BoneLengthScaled; // Scale support
+
+ // Applying certain amount of deflection on segment position
+ child.ProceduralPosition = Vector3.LerpUnclamped(child.ProceduralPosition, deflectedSegmentPos, Deflection * DeflectionFalloff.Evaluate(timeOnCurve) * _defl_source[i].DeflectionSmooth);
+ }
+ }
+
+
+ }
+}
\ No newline at end of file
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.PP.Deflection.cs.meta b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.PP.Deflection.cs.meta
new file mode 100644
index 000000000..743d07aa4
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.PP.Deflection.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: f9279b9459c57b248a52fb0f3d63e82e
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.User.cs b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.User.cs
new file mode 100644
index 000000000..4921281db
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.User.cs
@@ -0,0 +1,103 @@
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace FIMSpace.FTail
+{
+ ///
+ /// FC: In this parital class you will find methods useful for custom
+ /// coding and dynamic tail hierarchy changes etc.
+ ///
+ public partial class TailAnimator2
+ {
+
+ ///
+ /// Re-initialize tail with new transforms chain
+ ///
+ public void User_SetTailTransforms(List list)
+ {
+ StartBone = list[0];
+ EndBone = list[list.Count - 1];
+ _TransformsGhostChain = list;
+
+ StartAfterTPose = false;
+ initialized = false;
+ Init();
+ }
+
+ ///
+ /// Putting additional tail transform in chain list (added to the end of tail)
+ ///
+ public TailSegment User_AddTailTransform(Transform transform)
+ {
+ TailSegment newSeg = new TailSegment(transform);
+ TailSegment last = TailSegments[TailSegments.Count - 1];
+ newSeg.ParamsFromAll(last);
+
+ newSeg.RefreshFinalPos(newSeg.transform.position);
+ newSeg.RefreshFinalRot(newSeg.transform.rotation);
+ newSeg.ProceduralPosition = newSeg.transform.position;
+ newSeg.PosRefRotation = newSeg.transform.rotation;
+
+ _TransformsGhostChain.Add(transform);
+ TailSegments.Add(newSeg);
+ last.SetChildRef(newSeg);
+ newSeg.SetParentRef(last);
+ newSeg.SetChildRef(GhostChild);
+ GhostChild.SetParentRef(newSeg);
+
+ // Resetting indexes for curves
+ for (int i = 0; i < TailSegments.Count; i++)
+ TailSegments[i].SetIndex(i, TailSegments.Count);
+
+ return newSeg;
+ }
+
+
+ ///
+ /// Dynamically removing tail segments from chain
+ ///
+ /// Segment with this index will be removed too but used as ghosting child
+ public void User_CutEndSegmentsTo(int fromLastTo)
+ {
+ if (fromLastTo < TailSegments.Count)
+ {
+ GhostChild = TailSegments[fromLastTo];
+ GhostChild.SetChildRef(null);
+
+ for (int i = TailSegments.Count - 1; i >= fromLastTo; i--)
+ {
+ TailSegments.RemoveAt(i);
+ _TransformsGhostChain.RemoveAt(i);
+ }
+ }
+ else
+ {
+ Debug.Log("[Tail Animator Cutting] Wrong index, you want cut from end to " + fromLastTo + " segment but there are only " + TailSegments.Count + " segments!");
+ }
+ }
+
+
+ ///
+ /// Syncing tail with current transforms positions and rotations
+ ///
+ public void User_ReposeTail()
+ {
+ GhostParent.Reset();
+ for (int i = 0; i < TailSegments.Count; i++)
+ TailSegments[i].Reset();
+ GhostChild.Reset();
+ }
+
+
+ bool _forceDisable = false;
+ float _forceDisableElapsed = 0f;
+ ///
+ /// Disable tail animator with fade transition as "Max Distance" fade
+ ///
+ public void User_ForceDisabled(bool disable)
+ {
+ _forceDisable = disable;
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.User.cs.meta b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.User.cs.meta
new file mode 100644
index 000000000..c996d75b3
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.User.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: d6bf5d257ea4a6e47bbe76c86d216ec6
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Variables.cs b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Variables.cs
new file mode 100644
index 000000000..482c240cb
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Variables.cs
@@ -0,0 +1,149 @@
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace FIMSpace.FTail
+{
+ public partial class TailAnimator2 : UnityEngine.EventSystems.IDropHandler, IFHierarchyIcon
+ {
+
+ #region Hierarchy Icon
+
+ public string EditorIconPath { get { if (PlayerPrefs.GetInt("AnimsH", 1) == 0) return ""; else return "Tail Animator/Tail Animator Icon Small"; } }
+ public void OnDrop(UnityEngine.EventSystems.PointerEventData data) { }
+
+ #endregion
+
+ #region Enums
+
+ public enum EFDeltaType { DeltaTime, SmoothDeltaTime, UnscaledDeltaTime, FixedDeltaTime, SafeDelta }
+ public enum EAnimationStyle { Quick, Accelerating, Linear }
+
+ #endregion
+
+ public enum ETailCategory { Setup, Tweak, Features, Shaping }
+ public ETailCategory _Editor_Category = ETailCategory.Setup;
+ public enum ETailFeaturesCategory { Main, Collisions, IK, Experimental }
+ public ETailFeaturesCategory _Editor_FeaturesCategory = ETailFeaturesCategory.Main;
+
+ public bool DrawGizmos = true;
+
+ [Tooltip("First bone of tail motion chain")]
+ public Transform StartBone;
+ [Tooltip("Finish bone of tail motion chain")]
+ public Transform EndBone;
+
+ [Tooltip("Adjusting end point for end tail bone motion")]
+ public Vector3 EndBoneJointOffset = Vector3.zero;
+
+ public List _TransformsGhostChain;
+ public int _GhostChainInitCount = -1;
+
+ /// Initialization method controll flag
+ protected bool initialized = false;
+ public bool IsInitialized { get { return initialized; } }
+ [Tooltip("Target FPS update rate for Tail Animator.\n\nIf you want Tail Animator to behave the same in low/high fps, set this value for example to 60.\nIt also can help optimizing if your game have more than 60 fps.")]
+ public int UpdateRate = 0;
+
+ [Tooltip("If your character Unity's Animator have update mode set to 'Animate Physics' you should enable it here too")]
+ public EFixedMode AnimatePhysics = EFixedMode.None;
+ public enum EFixedMode { None, Basic, Late }
+
+ [Tooltip("When using target fps rate you can interpolate coordinates for smoother effect when object with tail is moving a lot")]
+ public bool InterpolateRate = false;
+
+ [Tooltip("Simulating tail motion at initiation to prevent jiggle start")]
+ public bool Prewarm = false;
+
+ /// For custom coding if you want to manipulate tail motion weight in additional way
+ internal float OverrideWeight = 1f;
+ /// Multiplier for tail motion weight computed from different conditions (max distance, override weight etc.)
+ protected float conditionalWeight = 1f;
+
+ protected bool collisionInitialized = false;
+ protected bool forceRefreshCollidersData = false;
+ Vector3 previousWorldPosition;
+
+ /// Parent transform of first tail transform
+ protected Transform rootTransform;
+
+ protected bool preAutoCorrect = false;
+
+
+
+ void OnValidate()
+ {
+ if (UpdateRate < 0) UpdateRate = 0;
+
+ if (Application.isPlaying)
+ {
+ RefreshSegmentsColliders();
+ //lastCurving = Curving; lastCurving.x += 0.001f;
+ if (UseIK) IK_ApplyLimitBoneSettings();
+ //if (UseWind) TailAnimatorWind.Refresh(this);
+ }
+
+ if (UsePartialBlend) { ClampCurve(BlendCurve, 0f, 1f, 0f, 1f); }
+ }
+
+ ///
+ /// Getting list of transform for Tail Animator using Start and End Bone Transform guides
+ ///
+ public void GetGhostChain()
+ {
+ if (_TransformsGhostChain == null) _TransformsGhostChain = new System.Collections.Generic.List();
+
+ if (EndBone == null)
+ {
+ // Just traight forward path through children
+ _TransformsGhostChain.Clear();
+
+ Transform tChild = StartBone;
+ if (tChild == null) tChild = transform;
+
+ _TransformsGhostChain.Add(tChild);
+
+ while (tChild.childCount > 0)
+ {
+ tChild = tChild.GetChild(0);
+ if (!_TransformsGhostChain.Contains(tChild)) _TransformsGhostChain.Add(tChild);
+ }
+
+ //if (!_TransformsGhostChain.Contains(tChild))
+ _GhostChainInitCount = _TransformsGhostChain.Count;
+ }
+ else // Going through parents of 'End Bone' to 'Start Bone'
+ {
+
+ System.Collections.Generic.List newTrs = new System.Collections.Generic.List();
+
+ Transform sBone = StartBone; if (sBone == null) sBone = transform;
+ Transform tParent = EndBone;
+
+ newTrs.Add(tParent);
+
+ while (tParent != null && tParent != StartBone)
+ {
+ tParent = tParent.parent;
+ if (!newTrs.Contains(tParent)) newTrs.Add(tParent);
+ }
+
+ if (tParent == null) // No parent of startbone!
+ {
+ Debug.Log("[Tail Animator Editor] " + EndBone.name + " is not child of " + sBone.name + "!");
+ Debug.LogError("[Tail Animator Editor] " + EndBone.name + " is not child of " + sBone.name + "!");
+ }
+ else
+ {
+ if (!newTrs.Contains(tParent)) newTrs.Add(tParent);
+
+ _TransformsGhostChain.Clear();
+ _TransformsGhostChain = newTrs;
+
+ _TransformsGhostChain.Reverse();
+ _GhostChainInitCount = _TransformsGhostChain.Count;
+ }
+ }
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Variables.cs.meta b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Variables.cs.meta
new file mode 100644
index 000000000..8c321fe7b
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Code/TailAnimator.Variables.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: a2dc5b1e05e72e44e91c60a332e6b401
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Packages - Demos - Converter.meta b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Packages - Demos - Converter.meta
new file mode 100644
index 000000000..d114ece95
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Packages - Demos - Converter.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 0396bd88bfc90b24f8713f695263a0d3
+folderAsset: yes
+timeCreated: 1600118724
+licenseType: Store
+DefaultImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Packages - Demos - Converter/FImpossible Assembly Definitions.unitypackage b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Packages - Demos - Converter/FImpossible Assembly Definitions.unitypackage
new file mode 100644
index 000000000..519ef7dae
Binary files /dev/null and b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Packages - Demos - Converter/FImpossible Assembly Definitions.unitypackage differ
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Packages - Demos - Converter/FImpossible Assembly Definitions.unitypackage.meta b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Packages - Demos - Converter/FImpossible Assembly Definitions.unitypackage.meta
new file mode 100644
index 000000000..86c056499
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Packages - Demos - Converter/FImpossible Assembly Definitions.unitypackage.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: e70277fbd3e17b54e91983280ca90b9a
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Packages - Demos - Converter/Tail Animator - Tails to Use Optimal.unitypackage b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Packages - Demos - Converter/Tail Animator - Tails to Use Optimal.unitypackage
new file mode 100644
index 000000000..e78334a13
Binary files /dev/null and b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Packages - Demos - Converter/Tail Animator - Tails to Use Optimal.unitypackage differ
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Packages - Demos - Converter/Tail Animator - Tails to Use Optimal.unitypackage.meta b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Packages - Demos - Converter/Tail Animator - Tails to Use Optimal.unitypackage.meta
new file mode 100644
index 000000000..4f65672b4
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Packages - Demos - Converter/Tail Animator - Tails to Use Optimal.unitypackage.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: c8a319bfdaa465646b09cab5796d7fe7
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Packages - Demos - Converter/Tail Animator - V2 Demo Unity 2019+ Examples.unitypackage b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Packages - Demos - Converter/Tail Animator - V2 Demo Unity 2019+ Examples.unitypackage
new file mode 100644
index 000000000..7dbc6305e
Binary files /dev/null and b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Packages - Demos - Converter/Tail Animator - V2 Demo Unity 2019+ Examples.unitypackage differ
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Packages - Demos - Converter/Tail Animator - V2 Demo Unity 2019+ Examples.unitypackage.meta b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Packages - Demos - Converter/Tail Animator - V2 Demo Unity 2019+ Examples.unitypackage.meta
new file mode 100644
index 000000000..af4a6997a
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Packages - Demos - Converter/Tail Animator - V2 Demo Unity 2019+ Examples.unitypackage.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 0a8cc58bf52c86a47b69e3e0d6a7029a
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Packages - Demos - Converter/Tail Animator - V2 Demo Unity Below 2018 Examples.unitypackage b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Packages - Demos - Converter/Tail Animator - V2 Demo Unity Below 2018 Examples.unitypackage
new file mode 100644
index 000000000..d7c8dda57
Binary files /dev/null and b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Packages - Demos - Converter/Tail Animator - V2 Demo Unity Below 2018 Examples.unitypackage differ
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Packages - Demos - Converter/Tail Animator - V2 Demo Unity Below 2018 Examples.unitypackage.meta b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Packages - Demos - Converter/Tail Animator - V2 Demo Unity Below 2018 Examples.unitypackage.meta
new file mode 100644
index 000000000..20ce97b56
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Packages - Demos - Converter/Tail Animator - V2 Demo Unity Below 2018 Examples.unitypackage.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 7c44e8a3d238b4d4f8f36d7af88d25f6
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Packages - Demos - Converter/Tail Animator V1 to V2 Converter + Old Examples.unitypackage b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Packages - Demos - Converter/Tail Animator V1 to V2 Converter + Old Examples.unitypackage
new file mode 100644
index 000000000..ac04ce251
Binary files /dev/null and b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Packages - Demos - Converter/Tail Animator V1 to V2 Converter + Old Examples.unitypackage differ
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Packages - Demos - Converter/Tail Animator V1 to V2 Converter + Old Examples.unitypackage.meta b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Packages - Demos - Converter/Tail Animator V1 to V2 Converter + Old Examples.unitypackage.meta
new file mode 100644
index 000000000..3a8f1ccfc
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Packages - Demos - Converter/Tail Animator V1 to V2 Converter + Old Examples.unitypackage.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: d5b3577c5e8a41c4ab0dd517d5d9737d
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/ReadMe - Tail Animator.txt b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/ReadMe - Tail Animator.txt
new file mode 100644
index 000000000..07d8e974c
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/ReadMe - Tail Animator.txt
@@ -0,0 +1,266 @@
+_________________________________________________________________________________________________________
+
+Package "Tail Animator V2"
+Version 2.0.7.4
+
+Made by FImpossible Creations - Filip Moeglich
+https://www.FilipMoeglich.pl
+FImpossibleGames@Gmail.com or Filip.Moeglich@Gmail.com
+
+_________________________________________________________________________________________________________
+
+Unity Connect: https://connect.unity.com/u/5b2e9407880c6425c117fab1
+Youtube: https://www.youtube.com/channel/UCDvDWSr6MAu1Qy9vX4w8jkw
+Facebook: https://www.facebook.com/FImpossibleCreations
+Twitter (@FimpossibleC): https://twitter.com/FImpossibleC
+Google+: https://plus.google.com/u/3/115325467674876785237
+
+_________________________________________________________________________________________________________
+
+Package Files Contests:
+
+- Tail Animator - V2 Demo Examples.unitypackage:
+ Few exmaple scenes, models and scripts showing some features of Tail Animator V2
+
+- Tail Animator V1 to V2 Converter.unitypackage:
+ Overriding Tail Animator V1.3.7.1 with buttons to convert Tail Animator V1 to V2
+ (Warning! You have to adjust motion variables anyway to make animation look the same)
+ Package also contains Tail Animator V1 example scenes and example scenes assets.
+
+- Tail Animator - Tails to Use.unitypackage:
+ Few example models which can be used in any way by owner of the package.
+
+_________________________________________________________________________________________________________
+Description:
+
+- Tail Animator is animating chains of transforms (it can be 3D/2D model bones)
+ simulating physical behaviour and can be highly customized
+
+- Package is providing mesh skinning API which can be used to create skinned mesh
+ renderers inside editor or in playmode (runtime)
+
+- Tail Animator component is providing highly customized inspector window (GUI)
+ to help user design desired motion responsively
+
+- Package is providing many example scenes presenting different features which can
+ be unpacked to project with “Tail Animator - New Demo Scenes” unitypackage file
+
+- In package’s demo scenes are used models with dense meshes (not optimized for
+ mobile for example) so package is providing few optimized tail models for custom
+ usage or to be used as rigging reference and it can be unpacked to project with
+ “Tail Animator - Tail Models for custom usage” unitypackage file
+
+- Package is providing tools to convert old Tail Animator V1 scripts to new one, it can
+ be unpacked to project with “Tail Animator - V1 to V2 Converter + Old Examples”
+
+- Tail Animator motion can be combined with skeleton keyframe animations to make
+ it more elastic and smooth
+
+_________________________________________________________________________________________________________
+Version history:
+
+V2.0.7.4
+- Fixed issue of Tail Animator not updating after being disabled, when using Fixed Update Late mode.
+- now is using all 3 axis for rotation
+
+V2.0.7.3
+- Implemented parameter, to make last tail bone be rotated as IK target object
+
+V2.0.7.2
+- Fixed dynamic colliders inclusion trigger sphere radius scale
+- Dynamic inclusion trigger collider reference is now accessable throught variable "GeneratedDynamicInclusionCollider"
+
+V2.0.7.1
+- When time scale is set to zero, tail motion will pause
+
+V2.0.7
+- Support for CharacterController collider
+- Added IK Invert Order option for Tail Animator IK
+
+V2.0.6
+- Reworked wind effect
+- Polished "Detach" feature which makes algorithm works up to 6 times faster but IT DOESN'T WORK WITH ANIMATED MODELS! It's good for example for cloth.
+- Some optimizations
+
+V2.0.5
+- Inspector window now is less vertical long, tweak categories are selected in horizontal menu
+- Added experimental version for 2D collision detection
+- Optimized some collision algorithms
+- Added "Animate" Roll toggle (under "Additional Parameters") which will make smooth rotate bones in forward axis (Tail Animator V1 style)
+
+
+---------- !!! WARNING FOR BIG UPDATE TO V2 !!! ----------
+Tail Animator V2 is using only one and new component for all Tail Animator features, old Tail Animators V1 can be converted to V2 component by importing Converter unitypackage.
+Tail Animator V2 motion can look different after conversion so it needs some adjustements after conversions.
+
+V2.0.0
+- New component containing all other components features (only it should used from V2) - Tail Animator V2
+- New GUI
+- Language support for inspector tabs titles
+- New parameters: "Slithery" -> V2 Slithery setted to 1 / 1.2 will make motion look almost the same like V1 motion
+ "Curling": Similar to V1 "Sensitivity" parameter
+ "Sustain" (experimental): Making tail bounce more after moving (more noticable with boosted "Springiness")
+ "Unify Bendiness" (experimental): Making tail bend in similar way no matter how many bones / how long tail model is
+ "Reaction Speed" / "Rotation Relevancy" / "Animation Mode": Working in almost the same way like V1 "positions / rotations speed
+- Fixed Update Rate mode to make Tail Animator motion look the same in Higher / Low fps domain
+- "Prewarm" option to pre-animate tail before first game frame to avoid jiggly start in some cases
+- "Root to parent" parameter replaced by "Include" / "Exclude" dropdown next to "Start Bone"
+- "Queue to last update" renamed to "Update as last"
+- "Blend To Original" renamed to "Tail Animator Amount" and reacting in reverse way than old "Blend To Original"
+- New parameter "Limit Axis 2D" to restrict tail animator for rotating around 2D space (please adjust auto waving axis if you using "Auto Waving" - some cases can't be restricted)
+- All main parameters now have possibility to spread values separately on each tail segment with curve
+
+- "Use Waving" renamed to "Auto Waving" and putted into new "Additional Modules" tab
+- "Fixed Cycle" for syncing tails waving animation for "Auto Waving"
+- "Collisions" feature in additional modules tab
+- Collisions algorithm upgraded and enchanced with some new paramters
+- "Collision Swapping" renamed to "Reflect Collisions" and working in reverse way than V1 parameter
+- Experimental "Collisions Slippery" parameter to make tails slide a bit less on colliders
+- Selective collision space have new tab "Dynamic World Colliders Inclusion" to dynamically add colliders from scene with trigger collider
+- "Partial Blend" as module
+- New "Inverse Kinematics" feature using CCD IK
+- New experimental "Deflection" feature to make collision affect back tail segments when deflecting it
+- New "Disable when Far" feature to smoothly disable tail animator when is far from main camera or other object
+- Experimental wind effector
+- Upgraded Mesh Skinning API to be used in Editor but also in Playmode
+- New demo scenes
+- Possibility and examples of cutting tail to smaller ones and generating additional segments dynamically
+- Example of generating tail model procedurally and skinning it in runtime
+- And much more small improvements
+
+v1.3.7.1
+- Added possibility to cull component's calculations with affected mesh visibility
+- Fixed issue with deactivating tail animator in first frame from code then activating - tail animator wasn't properly initialized in this situation
+
+v1.3.7
+- Added capsule collision option for World Space collision (not balanced yet)
+- Upgraded FTail_Skinner efficiency (spreading weights)
+- Now after skinning model with FTail_Skinner, vertex colors for meshes will be unchanged
+- Added download link for DynamicBone syncer in "DynamicBone Syncer.txt" to sync DynamicBone's collision system with tail animator and combine motion
+
+(between 1.3.7 and 1.3.6)
+- Added new animation parameter "Motion Influence" - if your character moves too fast you can controll influence of position changes for tail motion.
+- Added "Animate Root" option, which is applying animation rotations of first chain in bone like "Animate Corrections"
+- Small changes and fixes inside inspector window
+
+v1.3.6
+- Added "Max Angle" variable to limit maximum rotation of each segment from it's initial rotation
+- Using "Max Angle" parameter, enables other parameters to limit selective axis of rotating, otherwise all angles are clamped to "Max Angle"
+- Added parameter "Stiff Tail End" in "Experimental" tab which is making last tail segments more stiff for some extra tweak for tail motion
+- Upgraded behavior of "Gravity" parameter
+- Added new example scene and models for testing behavior of Tail Animator for hair
+
+v1.3.5
+- Added "Sensitivity" variable to give much more animation customization possibilities for tail motion, this variable making tail being more stiff (when lower) or entangled (when higher)
+- Added "Springiness" variable to give much more animation customization possibilities for tail motion, this variable gives tail more jiggly motion when cranked up
+- "MaxPositionOffset" variable replaced with "Max Stretching" which is 0-1 slider, on value 1 tail can stretch freely, on value 0 can't stretch a bit, setting this value to about 0.15 is giving the most natural feeling to the motion
+- Better support for single bone tail chains (root to parent toggle)
+- Cleaning code resulting in few optimization, preparations before next versions optimizations
+- New approaches to collisions, now there are three different methods of detecting collisions to choose (only in world space), old one is called "Rotation Offset" (needs bigger sphere tail colliders but works better in collision with mesh colliders), different methods can work better depending on situation etc.
+- Now you can choose to use world collision detection (collision space variable) or just include needed colliders without use of rigidbodies (quicker and smoother)
+- "Collision Swapping" (under Physics Tab - not available for 'Parental' look up method - it does it partially anyway) which is making collisions being less reflective in segment rotation (will be polished in next updates)
+- Added new demo scene "S_TailAnimator_Demo_CollisionWall"
+- Added info in ReadMe.txt which directories you can remove to purge unnecessary files if you don't need demo scenes anyomore
+- Some cleaning and changes inside inspector window for quicker navigation
++ (hidden update) Different variations of tail model examples models and scene
+
+
+v1.3.0
+- SmoothDelta changed and upgraded to SafeDelta to support more smoothed motion when fps are very unstable
+- Added option "Selective Rotations Not Animated" if some bones in tail chain don't have rotation keyframes in source animation
+- 'Rolled Bones' replaced with field where we can select LookUp algorithm, added 'CrossUp' algorithm which can support tail motion more precisely than previous methods and 'Parental' which seems to be the most universal but giving a bit different motion (then crank down positions and rotations speeds variable)
+- Added 'MaxPositionOffset' variable to limit stretching of tail when object moves very fast
+- Added 'Curving' and changed logics of 'Gravity' variable in "Experimental" tab
+- Added 'Fuman Elasticness' example scene
+- Some upgrades in the inspector window
+
+
+v1.2.9
+- Updated Skinner component to work with newest unity versions
+- Updated algorithm for "Rolled Bones" option
+- Updated algorithm for 'RootToParent' feature
+
+
+v1.2.8
+- "Advanced" option for waving animation, waving which is using perlin noise to calculate rotation of optional root animation
+- Some fixes for inspector windows
+- Added icon on the right inside hierarchy to easily indicate objects with attached tail animator
+- Added menu items under "Add Component" > "FImpossible Creations" > "Tail Animator" > Tail Animator Components
+
+
+v1.2.7
+- Support for realtime scalling object with tail animator attached
+
+
+V1.2.6
+- Added experimental collision detection feature
+- New example scene with collision feature
+- Added parameter "Gravity Power" simulating weight of tail
+- Some fixes inside editor stuff
+
+
+V1.2.5
+- Added support for one and two - length bone chains
+- Added variable "Root To Parent" to make first bone in chain be affected by parent transform (sometimes you will have to toggle "Full Correction" variable to make it work)
+
+
+V1.2.4
+- Added component "FTail_Animator_MassUpdater" which handles tail animators update method in one Update tick, it can boost performance of tail animator when you are using a lot of tail animators (from more than 100 it can give some boost, but when more tail animators, then difference more noticable)
+- Added new example scenes:
+ Fockatrice: Quadroped creature with tail, wings, long neck and feather like elements, all of that enchanced by tail animator to give you some ideas
+ Flime: Not animated slime model with some bones, animated only by tail animator components
+ Hair performance tests: Scene with different hairstyles using lots of tail animator components !read provided info on canvases!
+ Furry Fiped: Rouch example showing how many tails you can compute in the same time with low cpu overload in reference to components count
+
+
+V1.2.3
+- Added toggle "Queue To Last Update" which is putting component update order to be last, helpful for integrating other components which affecting bones hierarchy from code like Spine Animator
+So when you have this option toggles, tail animator will work on bones positions and rotations dictated by spine animator, not by unity animator
+- Few small polishes
+
+
+V1.2.2
+- Small tweaks for inspector window
+- Added Button "Connect with animator" which is changing variables 'Refresh Helpers', 'Full Correction' and 'Animate Corrections' so you switch to newest feature with one click and more intuitivity
+- Added toggle 'Refresh Helpers' which is refreshing helper variables in next frame, to use when your model's T-pose is much different from animations of tail chain you want to animate (for example arms)
+this option allows you to add tail animator to character's arms, pelvis etc. enable 'Full Correction' and 'Animate Corrections' so your model starts to be elastic and you can adjust stiffness
+- Added manual pdf file with visual friendly description to help you use Tail Animator features in most effetive way
+
+
+V1.2.1
+- Option "Auto go through all bones" under "Tuning Parameters" is renamed to "Full correction" and is upgraded
+to calculate correction for each bone individually, makes it match initial pose at lazy state
+also added new option "Animate Corrections" when you toggle "Full correction" which is matching keyframed animation's rotations
+
+
+V1.2.0 [Big Update]
+- Removed some scripts because they are not needed anymore, they're replaced by more efficient ones
+(FTail_FixedUpdate etc. because now you can choose which update clock should be used inside inspector)
+- Animator components are renamed to be more intuitive
+(FTail_Sinus to FTail_Animator, FTail_MecanimBones to FTail_AnimatorBlending, FTail_2D to FTail_Animator2D etc.)
+- Upgraded custom inspector and added rendering gizmos in scene view
+- Added icons for individual components so you find them easier
+- Added FTail_Editor_Skinner component to skin static meshes onto skinned mesh renderers with tail bone structure inside unity editor
+- Now bones hierarchy will not be changed at all in order to animate tail
+
+
+V1.1.2
+- Added "Automatic" tuning option for fixing orientation axes automatically by default
+- Added another auto-tuning wrong rotations options, making Tail Animator more universal to cooperate with different skeleton structures
+
+
+V1.1.0
+- Added new examples and components to animate transforms with tail animator in 2D space- UI and Sprites
+- Now you can put one transform to bones list and it will be root bone, so you can have component attached to much other object than tail bone
+- Custom inspector to see all parameters more clear
+- New example scenes
+- School of fish example scene
+
+
+V1.0.1
+- Added overrides for Start() method because in some cases it wasn't executed for some reason, probably different .net targets
+- Updated fSimpleAssets resources to V1.1
+
+
+V1.0 - 18/07/2018:
+Initial release
\ No newline at end of file
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/ReadMe - Tail Animator.txt.meta b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/ReadMe - Tail Animator.txt.meta
new file mode 100644
index 000000000..28663e3a7
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/ReadMe - Tail Animator.txt.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 212efa10c47ca0c45ac655ef13dafd52
+timeCreated: 1530012526
+licenseType: Store
+TextScriptImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Tail Animator - User Manual.pdf b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Tail Animator - User Manual.pdf
new file mode 100644
index 000000000..0c3657146
Binary files /dev/null and b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Tail Animator - User Manual.pdf differ
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Tail Animator - User Manual.pdf.meta b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Tail Animator - User Manual.pdf.meta
new file mode 100644
index 000000000..a289882bd
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Tail Animator - User Manual.pdf.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: de387e52748d23b4a8d49123904763ea
+timeCreated: 1538305915
+licenseType: Store
+DefaultImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/TailAnimator2.cs b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/TailAnimator2.cs
new file mode 100644
index 000000000..5733a1f32
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/TailAnimator2.cs
@@ -0,0 +1,306 @@
+using UnityEngine;
+
+namespace FIMSpace.FTail
+{
+ [AddComponentMenu("FImpossible Creations/Tail Animator 2")]
+ [DefaultExecutionOrder(-4)]
+ [HelpURL( "https://assetstore.unity.com/packages/tools/animation/tail-animator-121819" )]
+ public partial class TailAnimator2 : MonoBehaviour
+ {
+ /// -------- THIS IS PARTIAL CLASS - REST OF THE CODE IN SEPARATED .cs FILES -------- \\\
+
+
+ #region Public Inspector Variables
+
+ [Tooltip("Blending Slithery - smooth & soft tentacle like movement (value = 1)\nwith more stiff & springy motion (value = 0)\n\n0: Stiff somewhat like tree branch\n1: Soft like squid tentacle / Animal tail")]
+ [Range(0f, 1.2f)]
+ public float Slithery = 1f;
+
+ [Tooltip("How curly motion should be applied to tail segments")]
+ [Range(0f, 1f)]
+ public float Curling = 0.5f;
+
+ [Tooltip("Elastic spring effect making motion more 'meaty'")]
+ [Range(0f, 1f)]
+ public float Springiness = 0.0f;
+
+ [Tooltip("If you want to limit stretching/gumminess of position motion when object moves fast. Recommended adjust to go with it under 0.3 value.\nValue = 1: Unlimited stretching")]
+ [Range(0f, 1f)]
+ public float MaxStretching = .375f;
+
+ [Tooltip("Limiting max rotation angle for each tail segment")]
+ [FPD_Suffix(1f, 181f, FPD_SuffixAttribute.SuffixMode.FromMinToMaxRounded, "°")]
+ public float AngleLimit = 181f;
+ [Tooltip("If you need specific axis to be limited.\nLeave unchanged to limit all axes.")]
+ public Vector3 AngleLimitAxis = Vector3.zero;
+ [Tooltip("If you want limit axes symmetrically leave this parameter unchanged, if you want limit one direction of axis more than reversed, tweak this parameter")]
+ public Vector2 LimitAxisRange = Vector2.zero;
+ [Tooltip("If limiting shouldn't be too rapidly performed")]
+ [Range(0f, 1f)]
+ public float LimitSmoothing = 0.5f;
+
+ [Tooltip("If your object moves very fast making tail influenced by speed too much then you can controll it with this parameter")]
+ [FPD_Suffix(0f, 1.5f, FPD_SuffixAttribute.SuffixMode.PercentageUnclamped)]
+ public float MotionInfluence = 1f;
+ [Tooltip("Additional Y influence controll useful when your character is jumping (works only when MotionInfluence value is other than 100%)")]
+ [Range(0f, 1f)] public float MotionInfluenceInY = 1f;
+
+ [Tooltip("If first bone of chain should also be affected with whole chain")]
+ public bool IncludeParent = true;
+ [Tooltip("By basic algorithm of Tail Animator different sized tails with different number of bones would animate with different bending thanks to this toggle every setup bends in very similar amount.\n\nShort tails will bend more and longer oner with bigger amount of bones less with this option enabled.")]
+ [Range(0f, 1f)]
+ public float UnifyBendiness = 0f;
+
+ [Tooltip("Reaction Speed is defining how fast tail segments will return to target position, it gives animation more underwater/floaty feeling if it's lower")]
+ [Range(0f, 1f)]
+ public float ReactionSpeed = .9f;
+ [Tooltip("Sustain is similar to reaction speed in reverse, but providing sustain motion effect when increased")]
+ [Range(0f, 1f)]
+ public float Sustain = 0f;
+ [Tooltip("Rotation speed is defining how fast tail segments will return to target rotation, it gives animation more lazy feeling if it's lower")]
+ [Range(0f, 1f)]
+ public float RotationRelevancy = 1f;
+
+ [Tooltip("Smoothing motion values change over time style to be applied for 'Reaction Speed' and 'Rotation Relevancy' parameters")]
+ public EAnimationStyle SmoothingStyle = EAnimationStyle.Accelerating;
+ [Tooltip("Slowmo or speedup tail animation reaction")]
+ public float TimeScale = 1f;
+
+ [Tooltip("Delta time type to be used by algorithm")]
+ public EFDeltaType DeltaType = EFDeltaType.SafeDelta;
+
+ //[Tooltip("If tail motion should cooperate with keyframed animation if your model is not animated then disable this")]
+ //public bool SyncWithAnimator = true;
+
+ //[Tooltip("IF your model is not animated in any other way than Tail Animator then you can toggle it to avoid some unneccesary operations for optimization")]
+ //public bool NotAnimated = false;
+
+ [Tooltip("Useful when you use other components to affect bones hierarchy and you want this component to follow other component's changes\n\nIt can be really useful when working with 'Spine Animator'")]
+ public bool UpdateAsLast = true;
+ [Tooltip("Checking if keyframed animation has some empty keyframes which could cause unwanted twisting errors")]
+ public bool DetectZeroKeyframes = true;
+ [Tooltip("Initializing Tail Animator after first frames of game to not initialize with model's T-Pose but after playing some other animation")]
+ public bool StartAfterTPose = true;
+
+ [Tooltip("If you want Tail Animator to stop computing when choosed mesh is not visible in any camera view (editor's scene camera is detecting it too)")]
+ public Renderer OptimizeWithMesh;
+ [Tooltip("If you want to check multiple meshes visibility on screen to define if you want to disable tail animator. (useful when using LOD for skinned mesh renderer)")]
+ public Renderer[] OptimizeWithMeshes = null;
+
+ [Tooltip("Blend Source Animation (keyframed / unanimated) and Tail Animator")]
+ [FPD_Suffix(0f, 1f)]
+ public float TailAnimatorAmount = 1f;
+
+ [Tooltip("Removing transforms hierachy structure to optimize Unity's calculations on Matrixes.\nIt can give very big boost in performance for long tails but it can't work with animated models!")]
+ public bool DetachChildren = false;
+
+ [Tooltip("If tail movement should not move in depth you can use this parameter")]
+ /// 0: Unlimited 1: X is Depth 2: Y is Depth 3: Z is Depth
+ public int Axis2D = 0;
+
+ [Tooltip("[Experimental: Works only with Slithery Blend set to >= 1] Making each segment go to target pose in front of parent segment creating new animation effect")]
+ [Range(-1f, 1f)]
+ public float Tangle = 0f;
+
+ [Tooltip("Making tail animate also roll rotation like it was done in Tail Animator V1 ! Use Rotation Relevancy Parameter (set lower than 0.5) !")]
+ public bool AnimateRoll = false;
+
+ [Tooltip("Overriding keyframe animation with just Tail Animator option (keyframe animation treated as t-pose bones rotations)")]
+ [Range(0f, 1f)]
+ public float OverrideKeyframeAnimation = 0f;
+
+ public Transform BaseTransform { get { if (_baseTransform) return _baseTransform; else if (_TransformsGhostChain != null) if (_TransformsGhostChain.Count > 0) _baseTransform = _TransformsGhostChain[0]; if (_baseTransform != null) return _baseTransform; return transform; } }
+ private Transform _baseTransform;
+
+ #endregion
+
+
+ ///
+ /// Initialize component for correct work
+ ///
+ void Start()
+ {
+ if (UpdateAsLast) { enabled = false; enabled = true; }
+ if (StartAfterTPose) startAfterTPoseCounter = 6; else Init();
+ }
+
+
+#if UNITY_2019_1_OR_NEWER
+ ///
+ /// Setting curves which can't be created automatically when component is added to new object
+ ///
+ void Reset()
+ {
+ Keyframe key1 = new Keyframe(0f, 0f, 0.1f, 0.1f, 0.0f, 0.5f);
+ Keyframe key2 = new Keyframe(1f, 1f, 5f, 0f, 0.1f, 0.0f);
+ DeflectionFalloff = new AnimationCurve(new Keyframe[2] { key1, key2 });
+ }
+#endif
+
+ ///
+ /// Between Update() and LateUpdate() occurs Unity Animator's changes to transforms
+ /// We are using transform addRotation in Tail Animator algorithms and if bones are not animated
+ /// we would overrotate bones every frame, we setting here initial local coords to prevent it
+ /// If bones are animated it's rotations will be overrided after Update()
+ ///
+ void Update()
+ {
+ CheckIfTailAnimatorShouldBeUpdated();
+
+ // Preparations for target update
+ DeltaTimeCalculations();
+ if (UseWind) WindEffectUpdate();
+
+ if (AnimatePhysics != EFixedMode.None) return;
+ if (!updateTailAnimator) return;
+ if (DetachChildren) { if (_tc_rootBone != null) if (_tc_rootBone.transform) _tc_rootBone.PreCalibrate(); return; }
+
+ if (OverrideKeyframeAnimation < 1f) PreCalibrateBones();
+ }
+
+
+ ///
+ /// Sames as in Update() but for models with 'Animate Physics' enabled
+ ///
+ void FixedUpdate()
+ {
+ if (AnimatePhysics != EFixedMode.Basic) return;
+ if (!updateTailAnimator) return;
+ if (DetachChildren) { if (_tc_rootBone != null) if (_tc_rootBone.transform) _tc_rootBone.PreCalibrate(); return; }
+
+ fixedUpdated = true;
+ PreCalibrateBones();
+ }
+
+
+ ///
+ /// Updating bones after unity Animators [execution order -> Update() : UnityAnimators() : LateUpdate()]
+ ///
+ void LateUpdate()
+ {
+ if (!updateTailAnimator) return;
+
+
+ #region Support second solution for animate physics mode -----
+
+ if (AnimatePhysics == EFixedMode.Late)
+ {
+ if (!lateFixedIsRunning) { StartCoroutine(LateFixed()); }
+ if (fixedAllow) fixedAllow = false; else return;
+ }
+ else
+ {
+ if (lateFixedIsRunning) { StopCoroutine(LateFixed()); lateFixedIsRunning = false; }
+
+ if (AnimatePhysics == EFixedMode.Basic)
+ {
+ if (fixedUpdated == false) return;
+ fixedUpdated = false;
+ }
+ }
+ #endregion
+
+
+
+
+ #region Override Keyframe Animation
+
+ if (DetachChildren)
+ {
+ //PreCalibrateBones();
+ TailSegment child = TailSegments[0];
+ TailSegments[0].RefreshKeyLocalPositionAndRotation(child.InitialLocalPosition, child.InitialLocalRotation);
+ TailSegments[0].PreCalibrate();
+
+ child = TailSegments[1];
+ if (IncludeParent == false)
+ {
+ child.RefreshKeyLocalPositionAndRotation(child.InitialLocalPosition, child.InitialLocalRotation);
+ child.PreCalibrate();
+ child = TailSegments[2];
+ }
+
+ while (child != GhostChild)
+ {
+ child.RefreshKeyLocalPositionAndRotation(child.InitialLocalPosition, child.InitialLocalRotation);
+
+ //child.transform.localPosition = child.InitialLocalPosition;
+ child.transform.position = _baseTransform.TransformPoint(child.InitialLocalPositionInRoot);
+ // child.transform.localRotation = child.InitialLocalRotation;
+ child.transform.rotation = FEngineering.QToWorld(_baseTransform.rotation, child.InitialLocalRotationInRoot);
+ // tgtRot = FEngineering.QToWorld(BaseTransform.rotation, child.ParentBone.InitialLocalRotationInRoot);
+ child = child.ChildBone;
+ }
+ }
+ else
+ {
+ if (OverrideKeyframeAnimation > 0f)
+ {
+ if (OverrideKeyframeAnimation >= 1f)
+ {
+ PreCalibrateBones();
+
+ TailSegment child = TailSegments[0];
+ while (child != GhostChild)
+ {
+ child.RefreshKeyLocalPositionAndRotation();
+ child = child.ChildBone;
+ }
+ }
+ else
+ {
+ TailSegment child = TailSegments[0];
+
+ while (child != GhostChild)
+ {
+ child.transform.localPosition = Vector3.LerpUnclamped(child.transform.localPosition, child.InitialLocalPosition, OverrideKeyframeAnimation);
+ child.transform.localRotation = Quaternion.LerpUnclamped(child.transform.localRotation, child.InitialLocalRotation, OverrideKeyframeAnimation);
+ child.RefreshKeyLocalPositionAndRotation();
+ child = child.ChildBone;
+ }
+ }
+ }
+ else
+ {
+ TailSegment child = TailSegments[0];
+ while (child != GhostChild)
+ {
+ child.RefreshKeyLocalPositionAndRotation();
+ child = child.ChildBone;
+ }
+ }
+ }
+
+ #endregion
+
+
+ ExpertParamsUpdate();
+ ShapingParamsUpdate();
+
+ // Preparing tail animator for calculating motion
+ CalibrateBones();
+
+ UpdateTailAlgorithm();
+
+ // Shaping / expert parameters refresh + motion influence
+ EndUpdate();
+
+ }
+
+
+ void EndUpdate()
+ {
+ ShapingEndUpdate();
+ ExpertCurvesEndUpdate();
+ previousWorldPosition = BaseTransform.position;
+ }
+
+
+ void OnDisable()
+ {
+ lateFixedIsRunning = false;
+ wasDisabled = true;
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/TailAnimator2.cs.meta b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/TailAnimator2.cs.meta
new file mode 100644
index 000000000..bbb3820f3
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/TailAnimator2.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 61574e354ba34a141ae2cc1228f5eda3
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {fileID: 2800000, guid: 2e215648cc15ce04297817f7407c4e7b, type: 3}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Utilities.meta b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Utilities.meta
new file mode 100644
index 000000000..f749ceaba
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Utilities.meta
@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: c30d4b51e0607d04cbe6e0f813d883fa
+folderAsset: yes
+timeCreated: 1529356541
+licenseType: Store
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Utilities/Code.meta b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Utilities/Code.meta
new file mode 100644
index 000000000..6863df082
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Utilities/Code.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: c75d46b0788adf543b0088b6f6275521
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Utilities/Code/TailAnimator.Skinning.API.cs b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Utilities/Code/TailAnimator.Skinning.API.cs
new file mode 100644
index 000000000..ba15bd7eb
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Utilities/Code/TailAnimator.Skinning.API.cs
@@ -0,0 +1,266 @@
+using UnityEngine;
+using System.Collections.Generic;
+#if UNITY_EDITOR
+using UnityEditor;
+#endif
+
+
+namespace FIMSpace.FTail
+{
+ ///
+ /// FCr: Part of Tail Animator Skinning Static Meshes API
+ /// Methods used by skinner to create skinned mesh renderers from static meshes
+ ///
+ public static class FTail_Skinning
+ {
+
+ ///
+ /// Calculating base vertices datas for provided bones setup
+ ///
+ /// Mesh to be weighted
+ /// Required local positions and rotations for bones
+ /// Origin weighting offset which can be helpful in some cases, it can be Vector3.zero in most cases
+ /// To how many bones vertex can be weighted to create smooth weight effect
+ /// Smoothing weights on the edges of bones if lower then more smooth but don't oversmooth it
+ /// Making smoothing more sharp on edges
+ public static FTail_SkinningVertexData[] CalculateVertexWeightingData(Mesh baseMesh, Transform[] bonesCoords, Vector3 spreadOffset, int weightBoneLimit = 2, float spreadValue = 0.8f, float spreadPower = 0.185f)
+ {
+ Vector3[] pos = new Vector3[bonesCoords.Length];
+ Quaternion[] rot = new Quaternion[bonesCoords.Length];
+
+ //for (int i = 0; i < bonesCoords.Length; i++)
+ //{
+ // pos[i] = bonesCoords[i].position;
+ // rot[i] = bonesCoords[i].rotation;
+ //}
+
+ // We must reset bones structure to identity space
+ for (int i = 0; i < bonesCoords.Length; i++)
+ {
+ // Transforming from world to local space coords
+ pos[i] = bonesCoords[0].parent.InverseTransformPoint(bonesCoords[i].position);
+ rot[i] = FEngineering.QToLocal(bonesCoords[0].parent.rotation, bonesCoords[i].rotation);
+ }
+
+ return CalculateVertexWeightingData(baseMesh, pos, rot, spreadOffset, weightBoneLimit, spreadValue, spreadPower);
+ }
+
+
+ ///
+ /// Calculating base vertices datas for provided bones setup
+ ///
+ /// Mesh to be weighted
+ /// Mesh local space positions for bones
+ /// Mesh local space rotations for bones
+ /// Required local positions and rotations for bones
+ /// Origin weighting offset which can be helpful in some cases, it can be Vector3.zero in most cases
+ /// To how many bones vertex can be weighted to create smooth weight effect
+ /// Smoothing weights on the edges of bones if lower then more smooth but don't oversmooth it
+ /// Making smoothing more sharp on edges
+ public static FTail_SkinningVertexData[] CalculateVertexWeightingData(Mesh baseMesh, Vector3[] bonesPos, Quaternion[] bonesRot, Vector3 spreadOffset, int weightBoneLimit = 2, float spreadValue = 0.8f, float spreadPower = 0.185f)
+ {
+ if (weightBoneLimit < 1) weightBoneLimit = 1;
+ if (weightBoneLimit > 2) weightBoneLimit = 2; // Limiting for now
+
+ #region Editor progress dialogs
+#if UNITY_EDITOR
+ System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
+ watch.Start();
+#endif
+ #endregion
+
+ int vertCount = baseMesh.vertexCount;
+ FTail_SkinningVertexData[] vertexDatas = new FTail_SkinningVertexData[vertCount];
+
+ // Computing helper segments for weighting bones
+ Vector3[] boneAreas = new Vector3[bonesPos.Length];
+ for (int i = 0; i < bonesPos.Length - 1; i++)
+ {
+ // Direction vector towards further bone
+ boneAreas[i] = bonesPos[i + 1] - bonesPos[i]; //bonesCoords[i + 1].localPosition - bonesCoords[i].localPosition;
+ }
+
+ if (boneAreas.Length > 1) boneAreas[boneAreas.Length - 1] = boneAreas[boneAreas.Length - 2];
+
+
+#if UNITY_EDITOR
+ try
+ {
+ for (int i = 0; i < vertCount; i++)
+ {
+ vertexDatas[i] = new FTail_SkinningVertexData(baseMesh.vertices[i]);
+ vertexDatas[i].CalculateVertexParameters(bonesPos, bonesRot, boneAreas, weightBoneLimit, spreadValue, spreadOffset, spreadPower);
+
+ #region Editor progress dialogs
+ if (!Application.isPlaying)
+ // Displaying progress bar when iteration takes too much time
+ if (watch.ElapsedMilliseconds > 1500)
+ if (i % 10 == 0)
+ EditorUtility.DisplayProgressBar("Analizing mesh vertices...", "Analizing Vertices (" + i + "/" + vertCount + ")", ((float)i / (float)vertCount));
+ #endregion
+ }
+
+ #region Editor progress dialogs
+ if (!Application.isPlaying)
+ EditorUtility.ClearProgressBar();
+ #endregion
+ }
+ catch (System.Exception exc)
+ {
+ Debug.LogError(exc);
+ #region Editor progress dialogs
+ if (!Application.isPlaying)
+ EditorUtility.ClearProgressBar();
+ #endregion
+ }
+#else
+ for (int i = 0; i < vertCount; i++)
+ {
+ vertexDatas[i] = new FTail_SkinningVertexData(baseMesh.vertices[i]);
+ vertexDatas[i].CalculateVertexParameters(bonesPos, bonesRot, boneAreas, weightBoneLimit, spreadValue, spreadOffset, spreadPower);
+ }
+#endif
+
+ return vertexDatas;
+ }
+
+
+ ///
+ /// Skinning target mesh with helper vertex datas which you can get with CalculateVertexWeightingData() method
+ /// Using transforms as guidement for bones positions and rotations
+ ///
+ /// Skinned mesh can't be returned as 'Mesh' type because skinned mesh is mesh + bones transforms etc.
+ public static SkinnedMeshRenderer SkinMesh(Mesh baseMesh, Transform skinParent, Transform[] bonesStructure, FTail_SkinningVertexData[] vertData)
+ {
+ Vector3[] pos = new Vector3[bonesStructure.Length];
+ Quaternion[] rot = new Quaternion[bonesStructure.Length];
+
+ // We must reset bones structure to identity space
+ for (int i = 0; i < bonesStructure.Length; i++)
+ {
+ // Transforming from world to local space coords
+ pos[i] = skinParent.InverseTransformPoint(bonesStructure[i].position);
+ rot[i] = FEngineering.QToLocal(skinParent.rotation, bonesStructure[i].rotation);
+ }
+
+ SkinnedMeshRenderer skin = SkinMesh(baseMesh, pos, rot, vertData);
+
+ return skin;
+ }
+
+
+ ///
+ /// Skinning target mesh with helper vertex datas which you can
+ ///
+ /// Base static mesh to be skinned
+ /// Bones positions in mesh local space
+ /// Bones rotations in mesh local space
+ /// Get it with CalculateVertexWeightingData() method
+ /// Skinned mesh can't be returned as 'Mesh' type because skinned mesh is mesh + bones transforms etc.
+ public static SkinnedMeshRenderer SkinMesh(Mesh baseMesh, Vector3[] bonesPositions, Quaternion[] bonesRotations, FTail_SkinningVertexData[] vertData)
+ {
+ if (bonesPositions == null) return null;
+ if (bonesRotations == null) return null;
+ if (baseMesh == null) return null;
+ if (vertData == null) return null;
+
+ // Creating copy of target mesh and refreshing it
+ Mesh newMesh = GameObject.Instantiate(baseMesh);
+ newMesh.name = baseMesh.name + " [FSKINNED]";
+
+ // Preparing new object which will have skinned mesh renderer with new mesh and bones in it
+ GameObject newSkinObject = new GameObject(baseMesh.name + " [FSKINNED]");
+ Transform newParent = newSkinObject.transform;
+
+ // Preparing skin
+ SkinnedMeshRenderer skin = newParent.gameObject.AddComponent();
+
+ // Preparing bones for weighting
+ Transform[] bones = new Transform[bonesPositions.Length];
+ Matrix4x4[] bindPoses = new Matrix4x4[bonesPositions.Length];
+
+ string nameString;
+ if (baseMesh.name.Length < 6) nameString = baseMesh.name; else nameString = baseMesh.name.Substring(0, 5);
+
+ for (int i = 0; i < bonesPositions.Length; i++)
+ {
+ bones[i] = new GameObject("BoneF-" + nameString + "[" + i + "]").transform;
+ if (i == 0) bones[i].SetParent(newParent, true); else bones[i].SetParent(bones[i - 1], true);
+
+ bones[i].transform.position = bonesPositions[i];
+ bones[i].transform.rotation = bonesRotations[i];
+
+ bindPoses[i] = bones[i].worldToLocalMatrix * newParent.localToWorldMatrix;
+ }
+
+ BoneWeight[] weights = new BoneWeight[newMesh.vertexCount];
+ for (int v = 0; v < weights.Length; v++) weights[v] = new BoneWeight();
+
+ // Calculating and applying weights for verices
+ for (int i = 0; i < vertData.Length; i++)
+ {
+ for (int w = 0; w < vertData[i].weights.Length; w++)
+ {
+ weights[i] = SetWeightIndex(weights[i], w, vertData[i].bonesIndexes[w]);
+ weights[i] = SetWeightToBone(weights[i], w, vertData[i].weights[w]);
+ }
+ }
+
+ newMesh.bindposes = bindPoses;
+ newMesh.boneWeights = weights;
+
+ List normals = new List();
+ List < Vector4> tangents = new List();
+ baseMesh.GetNormals(normals);
+ baseMesh.GetTangents(tangents);
+
+ newMesh.SetNormals(normals);
+ newMesh.SetTangents(tangents);
+ newMesh.bounds = baseMesh.bounds;
+
+ // Applying generated mesh to skin controller
+ skin.sharedMesh = newMesh;
+ skin.rootBone = bones[0];
+ skin.bones = bones;
+
+ return skin;
+ }
+
+
+
+
+ ///
+ /// Method which is setting certain weight variable from BoneWeight struct
+ ///
+ public static BoneWeight SetWeightIndex(BoneWeight weight, int bone = 0, int index = 0)
+ {
+ switch (bone)
+ {
+ case 1: weight.boneIndex1 = index; break;
+ case 2: weight.boneIndex2 = index; break;
+ case 3: weight.boneIndex3 = index; break;
+ default: weight.boneIndex0 = index; break;
+ }
+
+ return weight;
+ }
+
+
+ ///
+ /// Method which is setting certain weight variable from BoneWeight struct
+ ///
+ public static BoneWeight SetWeightToBone(BoneWeight weight, int bone = 0, float value = 1f)
+ {
+ switch (bone)
+ {
+ case 1: weight.weight1 = value; break;
+ case 2: weight.weight2 = value; break;
+ case 3: weight.weight3 = value; break;
+ default: weight.weight0 = value; break;
+ }
+
+ return weight;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Utilities/Code/TailAnimator.Skinning.API.cs.meta b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Utilities/Code/TailAnimator.Skinning.API.cs.meta
new file mode 100644
index 000000000..e0ad4837c
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Utilities/Code/TailAnimator.Skinning.API.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 6dbb5fa7a5ec9084ba3564faf70c8899
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {fileID: 2800000, guid: f1f543bbb761e234cbb384a09c3482cc, type: 3}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Utilities/Code/TailAnimator.Skinning.VertexData.cs b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Utilities/Code/TailAnimator.Skinning.VertexData.cs
new file mode 100644
index 000000000..f81715715
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Utilities/Code/TailAnimator.Skinning.VertexData.cs
@@ -0,0 +1,231 @@
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace FIMSpace.FTail
+{
+ ///
+ /// FCr: Part of Tail Animator Skinning Static Meshes API
+ /// Simple helper class to store vertices parameters in reference to bones
+ ///
+ [System.Serializable]
+ public class FTail_SkinningVertexData
+ {
+ public Vector3 position;
+ //public Transform[] bones;
+
+ /// Indexes for helpers in visualization
+ public int[] bonesIndexes;
+ public int allMeshBonesCount;
+
+ // Assigned during custom weight calculations
+ public float[] weights;
+
+ public FTail_SkinningVertexData(Vector3 pos) { position = pos; }
+
+ ///
+ /// Distance to bone area for weighting
+ ///
+ public float DistanceToLine(Vector3 pos, Vector3 lineStart, Vector3 lineEnd)
+ {
+ Vector3 dirVector1 = pos - lineStart;
+ Vector3 dirVector2 = (lineEnd - lineStart).normalized;
+
+ float distance = Vector3.Distance(lineStart, lineEnd);
+ float dot = Vector3.Dot(dirVector2, dirVector1);
+
+ if (dot <= 0) return Vector3.Distance(pos, lineStart);
+ if (dot >= distance) return Vector3.Distance(pos, lineEnd);
+
+ Vector3 dotVector = dirVector2 * dot;
+ Vector3 closestPoint = lineStart + dotVector;
+
+ return Vector3.Distance(pos, closestPoint);
+ }
+
+
+ ///
+ /// Calculating vertex's distances to 4 nearest bones (4 bone weights is maximum count in Unity)
+ /// for further custom weight calculations
+ ///
+ public void CalculateVertexParameters(Vector3[] bonesPos, Quaternion[] bonesRot, Vector3[] boneAreas, int maxWeightedBones, float spread, Vector3 spreadOffset, float spreadPower = 1f)
+ {
+ allMeshBonesCount = bonesPos.Length;
+
+ // Using Vector2 for simple two float values in one variable, x = bone index y = distance of vertex to this bone, later we will sort list using distances
+ List calculatedDistances = new List();
+
+ // Check later if we don't need to transpone points to model space scale
+ for (int i = 0; i < bonesPos.Length; i++)
+ {
+ Vector3 boneEnd;
+ if (i != bonesPos.Length - 1)
+ boneEnd = Vector3.Lerp(bonesPos[i], bonesPos[i + 1], 0.9f);
+ else
+ boneEnd = Vector3.Lerp(bonesPos[i], bonesPos[i] + (bonesPos[i] - bonesPos[i - 1]), 0.9f);
+
+ boneEnd += bonesRot[i] * spreadOffset;
+
+ float distance = DistanceToLine(position, bonesPos[i], boneEnd);
+
+ // Making bone offset to behave like bone area
+ calculatedDistances.Add(new Vector2(i, distance));
+ }
+
+ // Sorting by nearest all bones
+ calculatedDistances.Sort((a, b) => a.y.CompareTo(b.y));
+
+ // Limiting vertex weight up to 4 bones
+ int maxBones = (int)Mathf.Min(maxWeightedBones, bonesPos.Length);
+
+ // Assigning max 4 nearest bones and their distances to this vertex
+ bonesIndexes = new int[maxBones];
+ float[] nearestDistances = new float[maxBones];
+
+ for (int i = 0; i < maxBones; i++)
+ {
+ bonesIndexes[i] = (int)calculatedDistances[i].x;
+ nearestDistances[i] = calculatedDistances[i].y;
+ }
+
+ // Basing on spread value we spreading weight to nearest bones
+ // Calculating percentage distances to bones
+ float[] boneWeightsForVertex = new float[maxBones];
+
+
+ AutoSetBoneWeights(boneWeightsForVertex, nearestDistances, spread, spreadPower, boneAreas);
+
+
+ float weightLeft = 1f; // Must amount of weight which needs to be assigned
+ weights = new float[maxBones]; // New weight parameters
+
+ // Applying weights to each bone assigned to vertex
+ for (int i = 0; i < maxBones; i++)
+ {
+ if (spread == 0) if (i > 0) break;
+
+ if (weightLeft <= 0f) // No more weight to apply
+ {
+ weights[i] = 0f;
+ continue;
+ }
+
+ float targetWeight = boneWeightsForVertex[i];
+
+ weightLeft -= targetWeight;
+ if (weightLeft <= 0f) targetWeight += weightLeft; else { if (i == maxBones - 1) targetWeight += weightLeft; } // Using weight amount which is left to assign
+
+ weights[i] = targetWeight;
+ }
+ }
+
+
+ public float[] debugDists;
+ public float[] debugDistWeights;
+ public float[] debugWeights;
+
+ ///
+ /// Spreading weights over bones for current vertex
+ ///
+ public void AutoSetBoneWeights(float[] weightForBone, float[] distToBone, float spread, float spreadPower, Vector3[] boneAreas)
+ {
+ int bonesC = weightForBone.Length;
+ float[] boneLengths = new float[bonesC]; for (int i = 0; i < boneLengths.Length; i++) boneLengths[i] = boneAreas[i].magnitude;
+ float[] normalizedDistanceWeights = new float[bonesC];
+ for (int i = 0; i < weightForBone.Length; i++) weightForBone[i] = 0f;
+
+ float normalizeDistance = 0f;
+ for (int i = 0; i < bonesC; i++) normalizeDistance += distToBone[i];
+ for (int i = 0; i < bonesC; i++) normalizedDistanceWeights[i] = 1f - distToBone[i] / normalizeDistance; // Reversing weight power - nearest (smallest distance) must have biggest weight value
+
+ debugDists = distToBone;
+
+ if (bonesC == 1 || spread == 0f) // Simpliest ONE BONE -------------------------------------------------------------
+ {
+ // [0] - nearest bone
+ weightForBone[0] = 1f; // Just one weight - spread does not change anything
+ }
+ else if (bonesC == 2) // Simple TWO BONES -------------------------------------------------------------
+ {
+ float normalizer = 1f;
+ weightForBone[0] = 1f;
+
+ // distToBone[0] is zero, max spread distance is length of bone / 3
+ float distRange = Mathf.InverseLerp(distToBone[0] + (boneLengths[0] / 1.25f) * spread, distToBone[0], distToBone[1]);
+ debugDists[0] = distRange;
+
+ // 0 -> full nearest bone weight
+ // 1 -> half nearest half second bone weight
+ float value = DistributionIn(Mathf.Lerp(0f, 1f, distRange), Mathf.Lerp(1.5f, 16f, spreadPower));
+
+ weightForBone[1] = value;
+ normalizer += value;
+
+ debugDistWeights = new float[weightForBone.Length];
+
+ weightForBone.CopyTo(debugDistWeights, 0);
+
+ for (int i = 0; i < bonesC; i++) weightForBone[i] /= normalizer;
+
+ debugWeights = weightForBone;
+ }
+ else // Complex > TWO BONES -------------------------------------------------------------
+ {
+ float reffVal = boneLengths[0] / 10f;
+ float refLength = boneLengths[0] / 2f;
+ float normalizer = 0f;
+
+ for (int i = 0; i < bonesC; i++)
+ {
+ float weight = Mathf.InverseLerp(0f, reffVal + refLength * (spread), distToBone[i]);
+ float value = Mathf.Lerp(1f, 0f, weight);
+ if (i == 0) if (value == 0f) value = 1f;
+
+ weightForBone[i] = value;
+
+ normalizer += value;
+ }
+
+ debugDistWeights = new float[weightForBone.Length];
+ weightForBone.CopyTo(debugDistWeights, 0);
+
+ for (int i = 0; i < bonesC; i++) weightForBone[i] /= normalizer;
+
+ debugWeights = weightForBone;
+ }
+ }
+
+ ///
+ /// Easing weight distribution
+ ///
+ public static float DistributionIn(float k, float power)
+ { return Mathf.Pow(k, power + 1f); }
+
+
+ ///
+ /// Returning helper color for bone
+ ///
+ public static Color GetBoneIndicatorColor(int boneIndex, int bonesCount, float s = 0.9f, float v = 0.9f)
+ {
+ float h = ((float)(boneIndex) * 1.125f) / bonesCount;
+ h += 0.125f * boneIndex;
+ h += 0.3f;
+ h %= 1f;
+
+ return Color.HSVToRGB(h, s, v);
+ }
+
+ ///
+ /// Returns average color value for weight idicator for this vertex
+ ///
+ public Color GetWeightColor()
+ {
+ Color lerped = GetBoneIndicatorColor(bonesIndexes[0], allMeshBonesCount, 1f, 1f);
+
+ for (int i = 1; i < bonesIndexes.Length; i++)
+ lerped = Color.Lerp(lerped, GetBoneIndicatorColor(bonesIndexes[i], allMeshBonesCount, 1f, 1f), weights[i]);
+
+ return lerped;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Utilities/Code/TailAnimator.Skinning.VertexData.cs.meta b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Utilities/Code/TailAnimator.Skinning.VertexData.cs.meta
new file mode 100644
index 000000000..dde079032
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Utilities/Code/TailAnimator.Skinning.VertexData.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: a2595a070e1f36f49862752d4a32580f
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {fileID: 2800000, guid: f1f543bbb761e234cbb384a09c3482cc, type: 3}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Utilities/FTail_Editor_Skinner.cs b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Utilities/FTail_Editor_Skinner.cs
new file mode 100644
index 000000000..ddb862de8
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Utilities/FTail_Editor_Skinner.cs
@@ -0,0 +1,454 @@
+#if UNITY_EDITOR
+
+using System.Collections.Generic;
+using UnityEditor;
+using UnityEngine;
+
+namespace FIMSpace.FTail
+{
+ ///
+ /// FCr: Implementation of Tail Animator Skinning Static Meshes API
+ /// Class to use only in editor, it creates bones with preview static mesh then skin it to skinned mesh renderer
+ ///
+ [ExecuteInEditMode]
+ [AddComponentMenu("FImpossible Creations/Tail Animator Utilities/Editor Tail Skinner")]
+ public class FTail_Editor_Skinner : MonoBehaviour
+ {
+
+ #region Inspector Variables
+
+ [FPD_Header("SKIN STATIC MESHES INSIDE UNITY", 3, 8, 8)]
+ [BackgroundColor(0.75f, 0.75f, 1.0f, 0.7f)]
+ public int AutoMarkersCount = 8;
+ public float DistanceValue = 0.3f;
+ public Vector3 positionOffset = new Vector3(0, 0f);
+ public Vector2 startDirection = new Vector2(-90, 0f);
+ public Vector2 rotationOffset = new Vector2(0f, 0f);
+
+ [Range(0f, 5f)]
+ public float HelpScaleValue = 1f;
+
+ [BackgroundColor(0.85f, 0.85f, 1.0f, 0.85f)]
+ public AnimationCurve DistancesFaloff = AnimationCurve.Linear(0f, 1f, 1f, 1f);
+ public AnimationCurve RotationsFaloff = AnimationCurve.Linear(0f, 1f, 1f, 1f);
+
+ [BackgroundColor(0.5f, 1f, 0.5f, 0.8f)]
+ [Space(10f, order = 0)]
+ [Header("Left empty if you don't use custom markers", order = 1)]
+ [Space(-7f, order = 2)]
+ [Header("Moving custom markers will not trigger realtime update", order = 3)]
+ public Transform[] CustomBoneMarkers;
+
+ [Space(7f, order = 0)]
+ [FPD_Header("Weights Spread Settings", 7, 4, 4)]
+ [Space(3f, order = 2)]
+ [Range(0f, 1f)]
+ public float SpreadValue = 0.8f;
+ [Range(0f, 1f)]
+ public float SpreadPower = .185f;
+ [Tooltip("Offsetting spreading area, For example 0,0,1 and recommended values from 0 to 2 not bigger")]
+ public Vector3 SpreadOffset = Vector3.zero;
+ [Range(1, 2)]
+ public int LimitBoneWeightCount = 2;
+
+ [BackgroundColor(0.4f, 0.8f, 0.8f, 0.8f)]
+ [FPD_Header("Additional Variables", 7, 4, 4)]
+ [Range(0f, 5f)]
+ public float GizmoSize = 0.1f;
+ [Range(0f, 1f)]
+ public float GizmoAlpha = .65f;
+
+ [BackgroundColor()]
+ [Tooltip("If your model have many vertices, turn it only when neccesary")]
+ public bool RealtimeUpdate = true;
+ public bool ShowPreview = true;
+ public bool DebugMode = false;
+
+ #endregion
+
+ #region Private variables
+
+ /// Base Mesh
+ private Mesh baseMesh;
+
+ [HideInInspector]
+ public List baseVertexColor;
+
+ private MeshRenderer meshRenderer;
+
+
+ /// Fake bones list before creating true skeleton for mesh
+ private Transform[] ghostBones;
+
+ /// Vertex datas used for setting weights precisely
+ private FTail_SkinningVertexData[] vertexDatas;
+
+ /// Generated marker points for automatic bone points
+ internal Transform[] autoMarkers;
+
+ // Hide in inspector because when variables are private, they're resetted to null every time code compiles
+ /// Because we can't destroy gameObjects in OnValidate, we do something similar to object pools
+ [HideInInspector]
+ public List allMarkersTransforms = new List();
+
+ /// Transform with components helping drawing how weights are spread on model
+ [HideInInspector]
+ public Transform weightPreviewTransform;
+
+ [HideInInspector]
+ public bool popupShown = false;
+
+ internal bool initValues = false;
+
+ #endregion
+
+
+ ///
+ /// When something changes in inspector, let's recalculate parameters
+ ///
+ private void OnValidate()
+ {
+ if (!initValues)
+ {
+ MeshRenderer m = GetComponent();
+ if (m) DistanceValue = m.bounds.extents.magnitude / 7f;
+ initValues = true;
+ }
+
+ if (AutoMarkersCount < 2) AutoMarkersCount = 2;
+
+ if (!GetBaseMesh()) return;
+
+ if (CustomBoneMarkers == null) CustomBoneMarkers = new Transform[0]; // Prevent error log when adding component
+
+ // Use only custom markers if they're assigned
+ if (CustomBoneMarkers.Length > 0)
+ ghostBones = CustomBoneMarkers;
+ else // Use auto markers
+ {
+ CalculateAutoMarkers();
+ ghostBones = autoMarkers;
+ }
+
+ if (RealtimeUpdate)
+ {
+ vertexDatas = FTail_Skinning.CalculateVertexWeightingData(
+ GetBaseMesh(), ghostBones, SpreadOffset, LimitBoneWeightCount, SpreadValue, SpreadPower);
+
+ UpdatePreviewMesh();
+ }
+ }
+
+
+ ///
+ /// Drawing helper stuff
+ ///
+ private void OnDrawGizmos()
+ {
+ if (CustomBoneMarkers == null)
+ CustomBoneMarkers = new Transform[0];
+
+ if (ghostBones[0] == null)
+ CalculateAutoMarkers();
+
+ if (CustomBoneMarkers.Length < 1)
+ DrawMarkers(autoMarkers);
+ else
+ DrawMarkers(CustomBoneMarkers);
+ }
+
+
+ ///
+ /// Calculating auto markers transforms
+ ///
+ private void CalculateAutoMarkers()
+ {
+ #region Creation of markers' transforms
+
+ if (autoMarkers == null) autoMarkers = new Transform[0];
+
+ if (allMarkersTransforms.Count < AutoMarkersCount)
+ {
+ for (int i = autoMarkers.Length; i < AutoMarkersCount; i++)
+ {
+ GameObject newMarker = new GameObject(name + "-SkinMarker " + i);
+ newMarker.transform.SetParent(transform, true);
+ allMarkersTransforms.Add(newMarker.transform);
+ }
+ }
+
+ if (autoMarkers.Length != AutoMarkersCount)
+ {
+ autoMarkers = new Transform[AutoMarkersCount];
+ for (int i = 0; i < AutoMarkersCount; i++)
+ {
+ autoMarkers[i] = allMarkersTransforms[i];
+ }
+ }
+
+ #endregion
+
+ autoMarkers[0].position = transform.position + positionOffset;
+ autoMarkers[0].rotation = Quaternion.Euler(startDirection + rotationOffset);
+
+ float step = 1f / (float)AutoMarkersCount;
+
+ for (int i = 1; i < AutoMarkersCount; i++)
+ {
+ float forwardMultiplier = DistanceValue;
+ forwardMultiplier *= DistancesFaloff.Evaluate(i * step);
+ forwardMultiplier *= HelpScaleValue;
+ Vector3 targetPosition = autoMarkers[i - 1].position + autoMarkers[i - 1].rotation * Vector3.forward * forwardMultiplier;
+
+ Vector3 newRot = startDirection + rotationOffset * (i + 1) * RotationsFaloff.Evaluate(i * step);
+
+ autoMarkers[i].position = targetPosition;
+ autoMarkers[i].rotation = Quaternion.Euler(newRot);
+ }
+ }
+
+
+ ///
+ /// Getting base mesh variable, depends if it's skinned mesh or static mesh
+ ///
+ private Mesh GetBaseMesh()
+ {
+ if (baseMesh == null)
+ {
+ meshRenderer = GetComponent();
+ MeshFilter meshFilter = GetComponent();
+ if (meshFilter) baseMesh = meshFilter.sharedMesh;
+ }
+ else return baseMesh;
+
+ if (!baseMesh)
+ {
+ if (!popupShown)
+ {
+ EditorUtility.DisplayDialog("Tail Skinner Error", "[Tail Skinner] No base mesh! (mesh filter and mesh renderer)", "Ok");
+ popupShown = true;
+ }
+
+ Debug.LogError("No BaseMesh!");
+ }
+
+ if (baseMesh)
+ {
+ if (baseVertexColor == null) baseVertexColor = new List();
+ if (baseVertexColor.Count != baseMesh.vertexCount)
+ {
+ baseVertexColor.Clear();
+ baseMesh.GetColors(baseVertexColor);
+ }
+ }
+
+ return baseMesh;
+ }
+
+
+ ///
+ /// Skinning mesh to new skinned mesh renderer with choosed weight markers settings
+ ///
+ public void SkinMesh(bool addTailAnimator, Vector3 newObjectOffset)
+ {
+ // Remembering data and preparing objects with components
+ List baseVertColors = new List();
+ GetBaseMesh().GetColors(baseVertColors);
+
+ // Doing skinning
+ vertexDatas = FTail_Skinning.CalculateVertexWeightingData(
+ GetBaseMesh(), ghostBones, SpreadOffset, LimitBoneWeightCount, SpreadValue, SpreadPower);
+
+ SkinnedMeshRenderer newSkinnedMesh = FTail_Skinning.SkinMesh(baseMesh, transform, ghostBones, vertexDatas);
+
+ if (newSkinnedMesh == null)
+ { Debug.LogError("[Tail Animator Skinning] Creating skinned mesh failed!"); return; }
+
+
+ // Skin renderer quality
+ switch (LimitBoneWeightCount)
+ {
+ case 1: newSkinnedMesh.quality = SkinQuality.Bone1; break;
+ case 2: newSkinnedMesh.quality = SkinQuality.Bone2; break;
+ case 4: newSkinnedMesh.quality = SkinQuality.Bone4; break;
+ default: newSkinnedMesh.quality = SkinQuality.Auto; break;
+ }
+
+ // Filling new mesh with materials
+ MeshRenderer meshRend = GetComponent();
+ if (meshRend)
+ {
+ newSkinnedMesh.materials = meshRend.sharedMaterials;
+ newSkinnedMesh.sharedMaterials = meshRend.sharedMaterials;
+ }
+
+ // Adding tail animator
+ if (addTailAnimator)
+ {
+ TailAnimator2 t = newSkinnedMesh.bones[0].gameObject.AddComponent();
+ t.StartBone = newSkinnedMesh.bones[0];
+ t.EndBone = newSkinnedMesh.bones[newSkinnedMesh.bones.Length - 1];
+ }
+
+ // Setting new object position to be next to current model
+ newSkinnedMesh.transform.position = transform.position + new Vector3(1f, 1f, 1f);
+
+ // Create asset for new model so it not disappear when we create prefab from this gameObject
+ string newMeshPath = System.IO.Path.GetDirectoryName(AssetDatabase.GetAssetPath(baseMesh));
+ AssetDatabase.CreateAsset(newSkinnedMesh.sharedMesh, newMeshPath + "/" + newSkinnedMesh.name + ".mesh");
+ AssetDatabase.SaveAssets();
+
+ Debug.Log("New skinned mesh '" + newSkinnedMesh.name + ".mesh" + "' saved under path: '" + newMeshPath + "'");
+ }
+
+
+ ///
+ /// Make sure everything which was created by this script is destroyed
+ ///
+ private void OnDestroy()
+ {
+ for (int i = 0; i < allMarkersTransforms.Count; i++) if (allMarkersTransforms[i] != null) DestroyImmediate(allMarkersTransforms[i].gameObject);
+ if (weightPreviewTransform != null) DestroyImmediate(weightPreviewTransform.gameObject);
+
+ if (baseMesh == null) return;
+ meshRenderer.enabled = true;
+ }
+
+
+ ///
+ /// Drawing markers to be visible in editor window to help place bones correctly
+ ///
+ public void DrawMarkers(Transform[] markers)
+ {
+ if (markers == null) return;
+
+ for (int i = 0; i < markers.Length; i++)
+ {
+ Gizmos.color = ChangeColorAlpha(GetBoneIndicatorColor(i, markers.Length), GizmoAlpha);
+
+ Vector3 targetPosition = markers[i].position;
+
+ Gizmos.DrawWireSphere(targetPosition, GizmoSize);
+
+ Gizmos.color = ChangeColorAlpha(GetBoneIndicatorColor(i, markers.Length, 1f, 1f), GizmoAlpha * 0.8f);
+ Gizmos.DrawSphere(targetPosition, GizmoSize * 0.7f);
+
+ Gizmos.DrawRay(targetPosition, markers[i].up * GizmoSize * 1.1f);
+ Gizmos.DrawRay(targetPosition, -markers[i].up * GizmoSize * 1.1f);
+ Gizmos.DrawRay(targetPosition, markers[i].right * GizmoSize * 1.1f);
+ Gizmos.DrawRay(targetPosition, -markers[i].right * GizmoSize * 1.1f);
+
+ Vector3 targetPoint;
+ if (i < markers.Length - 1) targetPoint = markers[i + 1].position;
+ else
+ targetPoint = markers[i].position + (markers[i].position - markers[i - 1].position);
+
+ Gizmos.DrawLine(targetPosition + markers[i].up * GizmoSize * 1.1f, targetPoint);
+ Gizmos.DrawLine(targetPosition - markers[i].up * GizmoSize * 1.1f, targetPoint);
+ Gizmos.DrawLine(targetPosition + markers[i].right * GizmoSize * 1.1f, targetPoint);
+ Gizmos.DrawLine(targetPosition - markers[i].right * GizmoSize * 1.1f, targetPoint);
+ }
+ }
+
+
+ ///
+ /// Updating preview mesh to view weights correctly
+ ///
+ private void UpdatePreviewMesh()
+ {
+ #region Creation of new preview mesh when needed
+
+ if (weightPreviewTransform == null)
+ {
+ weightPreviewTransform = new GameObject(name + "[preview mesh]").transform;
+ weightPreviewTransform.SetParent(transform);
+ weightPreviewTransform.localPosition = Vector3.zero;
+ weightPreviewTransform.localRotation = Quaternion.identity;
+ weightPreviewTransform.localScale = Vector3.one;
+
+ weightPreviewTransform.gameObject.AddComponent().mesh = baseMesh;
+
+ Material[] newMaterials = new Material[meshRenderer.sharedMaterials.Length];
+
+ for (int i = 0; i < newMaterials.Length; i++) newMaterials[i] = new Material(Shader.Find("Particles/FVertexLit Blended"));
+ weightPreviewTransform.gameObject.AddComponent().materials = newMaterials;
+ }
+
+ #endregion
+
+ if (ShowPreview)
+ {
+ meshRenderer.enabled = false;
+ weightPreviewTransform.gameObject.SetActive(true);
+ List vColors = new List();
+ for (int i = 0; i < vertexDatas.Length; i++) vColors.Add(vertexDatas[i].GetWeightColor());
+ baseMesh.SetColors(vColors);
+ weightPreviewTransform.gameObject.GetComponent().mesh = baseMesh;
+ }
+ else
+ {
+ meshRenderer.enabled = true;
+ if (baseVertexColor != null) if (baseMesh) if (baseMesh.vertexCount == baseVertexColor.Count) baseMesh.SetColors(baseVertexColor);
+ weightPreviewTransform.gameObject.SetActive(false);
+ }
+ }
+
+
+ private void OnDrawGizmosSelected()
+ {
+ if (!DebugMode) return;
+ if (vertexDatas == null) return;
+ if (vertexDatas.Length == 0) return;
+ if (vertexDatas[0].bonesIndexes == null) return;
+
+ for (int i = 0; i < vertexDatas.Length; i++)
+ {
+ Handles.color = GetBoneIndicatorColor(vertexDatas[i].bonesIndexes[0], vertexDatas[i].bonesIndexes.Length) * new Color(1f, 1f, 1f, GizmoAlpha);
+ Gizmos.color = Handles.color;
+
+ Handles.Label(transform.TransformPoint(vertexDatas[i].position), "[" + i + "]");
+ //Handles.Label(transform.TransformPoint(vertexDatas[i].position), "[" + i + "]\n" + Math.Round(vertexDatas[i].debugDists[0], 3) + "\n" + Math.Round(vertexDatas[i].debugDists[1], 3));
+ Gizmos.DrawSphere(transform.TransformPoint(vertexDatas[i].position), 0.125f * GizmoSize);
+ }
+ }
+
+
+ ///
+ /// Returning helper color for bone
+ ///
+ public static Color GetBoneIndicatorColor(int boneIndex, int bonesCount, float s = 0.9f, float v = 0.9f)
+ {
+ float h = ((float)(boneIndex) * 1.125f) / bonesCount;
+ h += 0.125f * boneIndex;
+ h += 0.3f;
+ h %= 1f;
+ return Color.HSVToRGB(h, s, v);
+ }
+
+
+ public static Color ChangeColorAlpha(Color color, float alpha)
+ { return new Color(color.r, color.g, color.b, alpha); }
+
+ }
+
+ ///
+ /// FM: Editor class component to enchance controll over component from inspector window
+ ///
+ [UnityEditor.CustomEditor(typeof(FTail_Editor_Skinner))]
+ public class FTail_Editor_SkinnerEditor : UnityEditor.Editor
+ {
+ public override void OnInspectorGUI()
+ {
+ FTail_Editor_Skinner targetScript = (FTail_Editor_Skinner)target;
+ DrawDefaultInspector();
+
+ GUILayout.Space(10f);
+
+ if (GUILayout.Button("Skin It")) targetScript.SkinMesh(false, Vector3.right);
+ if (GUILayout.Button("Skin and add Tail Animator")) targetScript.SkinMesh(true, Vector3.right);
+ }
+ }
+
+}
+
+#endif
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Utilities/FTail_Editor_Skinner.cs.meta b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Utilities/FTail_Editor_Skinner.cs.meta
new file mode 100644
index 000000000..e42c4ef24
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Utilities/FTail_Editor_Skinner.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 64150bf558082b8468d3f05b3e9d3b5a
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {fileID: 2800000, guid: 7958d01c62579034fa1ffbb911dd6b59, type: 3}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Utilities/TailAnimatorWind.cs b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Utilities/TailAnimatorWind.cs
new file mode 100644
index 000000000..c993e80f7
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Utilities/TailAnimatorWind.cs
@@ -0,0 +1,301 @@
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace FIMSpace.FTail
+{
+ ///
+ /// FC: Experimental class under developement
+ ///
+ [AddComponentMenu("FImpossible Creations/Tail Animator Utilities/Tail Animator Wind")]
+ public class TailAnimatorWind : MonoBehaviour, UnityEngine.EventSystems.IDropHandler, IFHierarchyIcon
+ {
+
+ #region Hierarchy Icon
+
+ public string EditorIconPath { get { return "Tail Animator/TailAnimatorWindIconSmall"; } }
+ public void OnDrop(UnityEngine.EventSystems.PointerEventData data) { }
+
+ #endregion
+
+
+ #region Singleton
+
+
+ public static TailAnimatorWind Instance { get; private set; } // { get { if (!_instance) GenerateWindComponentInstance(); return _instance; } }
+ //private static TailAnimatorWind _instance;
+
+ private void Awake()
+ {
+ if (!Application.isPlaying) return;
+ Instance = this;
+ if (persistThroughAllScenes) DontDestroyOnLoad(gameObject);
+ }
+
+ public void OnValidate()
+ {
+ Instance = this;
+ }
+
+ //private static void GenerateWindComponentInstance()
+ //{
+ // GameObject windObj = new GameObject("Tail Animator Wind");
+ // _instance = windObj.AddComponent();
+ //}
+
+
+ ///
+ /// Generating wind component if needed and adding tail animator component to wind affected components list
+ ///
+ //public static void Refresh(TailAnimator2 tail)
+ //{
+ // if (!_instance) GenerateWindComponentInstance();
+ // if (_instance.WindAffected == null) _instance.WindAffected = new List();
+ // if (tail != null) if (!_instance.WindAffected.Contains(tail)) _instance.WindAffected.Add(tail);
+ //}
+
+
+ #endregion
+
+
+ [Header("In playmode you will find this object in DontDestroyOnLoad")]
+ [FPD_Header("Main Wind Setings", 2, 4)]
+ public float power = 1f;
+ public float additionalTurbulence = 1f;
+ public float additionalTurbSpeed = 1f;
+
+ [Space(7)]
+ public WindZone SyncWithUnityWindZone;
+ public float UnityWindZonePowerMul = 2f;
+ public float UnityWindZoneTurbMul = 1f;
+
+ [Header("Overriding wind if value below different than 0,0,0")]
+ public Vector3 overrideWind = Vector3.zero;
+
+ [FPD_Header("Procedural Wind Settings (if not syncing and not overriding)", 6, 4)]
+ [Range(0.1f, 1f)]
+ public float rapidness = 0.95f;
+ [FPD_Suffix(0, 360, FPD_SuffixAttribute.SuffixMode.FromMinToMaxRounded, "°")]
+ public float changesPower = 90f;
+ [Header("Extra")]
+ [Range(0f, 10f)] public float turbulenceSpeed = 1f;
+
+ [FPD_Header("World Position Turbulence", 6, 4)]
+ [Tooltip("Increase to make objects next to each other wave in slightly different way")]
+ public float worldTurb = 1f;
+ [Tooltip("If higher no performance cost, it is just a number")]
+ public float worldTurbScale = 512;
+ public float worldTurbSpeed = 5f;
+
+ [FPD_Header("Tail Compoenents Related", 6, 4)]
+ [Tooltip("When tail is longer then power of wind should be higher")]
+ public bool powerDependOnTailLength = true;
+ [Tooltip("Don't destroy on load")]
+ public bool persistThroughAllScenes = false;
+ //[Tooltip("Finding all TailAnimato2 compoents at start")]
+ //public bool collectFromSceneAtStart = false;
+
+ //public List WindAffected;
+
+ private Vector3 targetWind = Vector3.zero;
+ private Vector3 smoothWind = Vector3.zero;
+ private Vector3 windVeloHelper = Vector3.zero;
+ private Quaternion windOrientation = Quaternion.identity;
+ private Quaternion smoothWindOrient = Quaternion.identity;
+ private Quaternion smoothWindOrientHelper = Quaternion.identity;
+
+ private float[] randNumbers;
+ private float[] randTimes;
+ private float[] randSpeeds;
+
+ private int frameOffset = 2;
+
+
+ void Update()
+ {
+ if (frameOffset > 0) { frameOffset--; return; }
+
+ //if (collectFromSceneAtStart)
+ //{
+ // collectFromSceneAtStart = false;
+ // GetTailAnimatorsFromScene();
+ //}
+
+ ComputeWind();
+
+ #region Hidden backup
+
+ //TailAnimator2 t;
+ //for (int i = 0; i < WindAffected.Count; i++)
+ //{
+ // t = WindAffected[i];
+
+ // if (!t.UseWind) continue;
+ // if (t.WindEffectPower <= 0f) continue;
+ // if (t.TailSegments.Count <= 0) continue;
+
+ // float lengthRatio = 1f;
+ // if (powerDependOnTailLength)
+ // {
+ // lengthRatio = (t._TC_TailLength * t.TailSegments[0].transform.lossyScale.z) / 5f;
+ // if (t.TailSegments.Count > 3) lengthRatio *= Mathf.Lerp(0.7f, 3f, t.TailSegments.Count / 14f);
+ // }
+
+ // if (t.WindWorldNoisePower > 0f)
+ // {
+ // float wTurb = worldTurbSpeed;
+ // if (SyncWithUnityWindZone) wTurb *= SyncWithUnityWindZone.windTurbulence * UnityWindZoneTurbMul;
+
+ // float worldPosTurbulence = (.5f + Mathf.Sin(Time.time * wTurb + t.TailSegments[0].ProceduralPosition.x * worldTurbScale) / 2f) + (.5f + Mathf.Cos(Time.time * wTurb + t.TailSegments[0].ProceduralPosition.z * worldTurbScale) / 2f);
+ // lengthRatio += worldPosTurbulence * worldTurb * t.WindWorldNoisePower;
+ // }
+
+ // lengthRatio *= t.WindEffectPower;
+
+ // if (t.WindTurbulencePower > 0f)
+ // t.WindEffect = new Vector3(targetWind.x * lengthRatio + finalAddTurbulence.x * t.WindTurbulencePower, targetWind.y * lengthRatio + finalAddTurbulence.y * t.WindTurbulencePower, targetWind.z * lengthRatio + finalAddTurbulence.z * t.WindTurbulencePower);
+ // else
+ // t.WindEffect = new Vector3(targetWind.x * lengthRatio, targetWind.y * lengthRatio, targetWind.z * lengthRatio);
+
+ //}
+
+ #endregion
+
+ }
+
+ public static void Refresh()
+ {
+ if (Instance == null)
+ {
+ UnityEngine.Debug.Log("[Tail Animator Wind] No Tail Animator Wind component on the scene!");
+ UnityEngine.Debug.LogWarning("[Tail Animator Wind] No Tail Animator Wind component on the scene!");
+ }
+ }
+
+ public void AffectTailWithWind(TailAnimator2 t)
+ {
+ if (!t.UseWind) return;
+ if (t.WindEffectPower <= 0f) return;
+ if (t.TailSegments.Count <= 0) return;
+
+ float lengthRatio = 1f;
+ if (powerDependOnTailLength)
+ {
+ lengthRatio = (t._TC_TailLength * t.TailSegments[0].transform.lossyScale.z) / 5f;
+ if (t.TailSegments.Count > 3) lengthRatio *= Mathf.Lerp(0.7f, 3f, t.TailSegments.Count / 14f);
+ }
+
+ if (t.WindWorldNoisePower > 0f)
+ {
+ float wTurb = worldTurbSpeed;
+ if (SyncWithUnityWindZone) wTurb *= SyncWithUnityWindZone.windTurbulence * UnityWindZoneTurbMul;
+
+ float worldPosTurbulence = (.5f + Mathf.Sin(Time.time * wTurb + t.TailSegments[0].ProceduralPosition.x * worldTurbScale) / 2f) + (.5f + Mathf.Cos(Time.time * wTurb + t.TailSegments[0].ProceduralPosition.z * worldTurbScale) / 2f);
+ lengthRatio += worldPosTurbulence * worldTurb * t.WindWorldNoisePower;
+ }
+
+ lengthRatio *= t.WindEffectPower;
+
+ if (t.WindTurbulencePower > 0f)
+ t.WindEffect = new Vector3(targetWind.x * lengthRatio + finalAddTurbulence.x * t.WindTurbulencePower, targetWind.y * lengthRatio + finalAddTurbulence.y * t.WindTurbulencePower, targetWind.z * lengthRatio + finalAddTurbulence.z * t.WindTurbulencePower);
+ else
+ t.WindEffect = new Vector3(targetWind.x * lengthRatio, targetWind.y * lengthRatio, targetWind.z * lengthRatio);
+ }
+
+
+ private void Start()
+ {
+ int numCount = 10;
+ randNumbers = new float[numCount];
+ randTimes = new float[numCount];
+ randSpeeds = new float[numCount];
+
+ for (int i = 0; i < 10; i++)
+ {
+ randNumbers[i] = Random.Range(-1000f, 1000f);
+ randTimes[i] = Random.Range(-1000f, 1000f);
+ randSpeeds[i] = Random.Range(0.18f, 0.7f);
+ }
+ }
+
+
+ void ComputeWind()
+ {
+
+ Vector3 newWind;
+
+ if (SyncWithUnityWindZone)
+ {
+ newWind = SyncWithUnityWindZone.transform.forward * SyncWithUnityWindZone.windMain * UnityWindZonePowerMul;
+ transform.rotation = SyncWithUnityWindZone.transform.rotation;
+ }
+ else
+ {
+ if (overrideWind != Vector3.zero) newWind = overrideWind;
+ else // Procedural wind
+ {
+ for (int i = 0; i < 4; i++)
+ randTimes[i] += Time.deltaTime * randSpeeds[i] * turbulenceSpeed;
+
+ Quaternion windDir = windOrientation;
+
+ float x = -1f + Mathf.PerlinNoise(randTimes[0], 256f + randTimes[1]) * 2f;
+ float y = -1f + Mathf.PerlinNoise(-randTimes[1], 55f + randTimes[2]) * 2f;
+ float z = -1f + Mathf.PerlinNoise(-randTimes[3], 55f + randTimes[0]) * 2f;
+ windDir *= Quaternion.Euler(new Vector3(0, y, 0) * changesPower);
+ windDir = Quaternion.Euler(x * (changesPower / 6f), windDir.eulerAngles.y, z * (changesPower / 6f));
+
+ smoothWindOrient = FEngineering.SmoothDampRotation(smoothWindOrient, windDir, ref smoothWindOrientHelper, 1f - rapidness, Time.deltaTime);
+
+ transform.rotation = smoothWindOrient;
+ newWind = smoothWindOrient * Vector3.forward;
+ }
+ }
+
+ // Additional turbulence
+ smoothAddTurbulence = Vector3.SmoothDamp(smoothAddTurbulence, GetAddTurbulence() * additionalTurbulence, ref addTurbHelper, 0.05f, Mathf.Infinity, Time.deltaTime);
+
+ // Smooth out
+ smoothWind = Vector3.SmoothDamp(smoothWind, newWind, ref windVeloHelper, 0.1f, Mathf.Infinity, Time.deltaTime);
+
+ for (int i = 7; i < 10; i++)
+ randTimes[i] += Time.deltaTime * randSpeeds[i] * turbulenceSpeed;
+
+ float turbulencedPower = power * 0.015f;
+ turbulencedPower *= 0.5f + Mathf.PerlinNoise(randTimes[7] * 2f, 25 + randTimes[8] * 0.5f);
+
+ finalAddTurbulence = smoothAddTurbulence * turbulencedPower;
+ targetWind = smoothWind * turbulencedPower;
+ }
+
+ Vector3 finalAddTurbulence = Vector3.zero;
+ Vector3 addTurbHelper = Vector3.zero;
+ private Vector3 GetAddTurbulence()
+ {
+ float turb = additionalTurbSpeed;
+ if (SyncWithUnityWindZone) turb *= (SyncWithUnityWindZone.windTurbulence * UnityWindZoneTurbMul);
+
+ for (int i = 4; i < 7; i++)
+ randTimes[i] += Time.deltaTime * randSpeeds[i] * turb;
+
+ float x = -1f + Mathf.PerlinNoise(randTimes[4] + 7.123f, -2.324f + Time.time * 0.24f) * 2f;
+ float y = -1f + Mathf.PerlinNoise(randTimes[5] - 4.7523f, -25.324f + Time.time * 0.54f) * 2f;
+ float z = -1f + Mathf.PerlinNoise(randTimes[6] + 1.123f, -63.324f + Time.time * -0.49f) * 2f;
+ return new Vector3(x, y, z);
+ }
+
+ Vector3 smoothAddTurbulence = Vector3.zero;
+
+
+ ///
+ /// Collecting tail animator components from scene (WARNING: Don't execute it every frame)
+ ///
+ //public void GetTailAnimatorsFromScene()
+ //{
+ // TailAnimator2[] tails = FindObjectsOfType();
+ // for (int i = 0; i < tails.Length; i++)
+ // {
+ // if (!WindAffected.Contains(tails[i])) WindAffected.Add(tails[i]);
+ // }
+ //}
+ }
+}
\ No newline at end of file
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Utilities/TailAnimatorWind.cs.meta b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Utilities/TailAnimatorWind.cs.meta
new file mode 100644
index 000000000..1484d174b
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Utilities/TailAnimatorWind.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: ca32c544193be8047ad129a8e7f52f78
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {fileID: 2800000, guid: 73e848e8b105ad4419739438d540ff07, type: 3}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Utilities/TailCollisionHelper.cs b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Utilities/TailCollisionHelper.cs
new file mode 100644
index 000000000..1f5705c07
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Utilities/TailCollisionHelper.cs
@@ -0,0 +1,173 @@
+using UnityEngine;
+#if UNITY_2019_4_OR_NEWER
+using UnityEngine.Tilemaps;
+#endif
+
+namespace FIMSpace.FTail
+{
+ ///
+ /// FM: Simple class sending collision events to main script
+ ///
+ [AddComponentMenu("FImpossible Creations/Hidden/Tail Collision Helper")]
+ public class TailCollisionHelper : MonoBehaviour
+ {
+ public TailAnimator2 ParentTail;
+ public Collider TailCollider;
+ public Collider2D TailCollider2D;
+ public int Index;
+
+ internal Rigidbody RigBody { get; private set; }
+ internal Rigidbody2D RigBody2D { get; private set; }
+ Transform previousCollision;
+
+ internal TailCollisionHelper Init(bool addRigidbody = true, float mass = 1f, bool kinematic = false)
+ {
+ if (TailCollider2D == null)
+ {
+ if (addRigidbody)
+ {
+ Rigidbody rig = GetComponent();
+ if (!rig) rig = gameObject.AddComponent();
+ rig.interpolation = RigidbodyInterpolation.Interpolate;
+ rig.useGravity = false;
+ rig.isKinematic = kinematic;
+ rig.constraints = RigidbodyConstraints.FreezeAll;
+ rig.mass = mass;
+ RigBody = rig;
+ }
+ else
+ {
+ RigBody = GetComponent();
+ if (RigBody) RigBody.mass = mass;
+ }
+ }
+ else
+ {
+ if (addRigidbody)
+ {
+ Rigidbody2D rig = GetComponent();
+ if (!rig) rig = gameObject.AddComponent();
+ rig.interpolation = RigidbodyInterpolation2D.Interpolate;
+ rig.gravityScale = 0f;
+ rig.isKinematic = kinematic;
+ rig.constraints = RigidbodyConstraints2D.FreezeAll;
+ rig.mass = mass;
+ RigBody2D = rig;
+ }
+ else
+ {
+ RigBody2D = GetComponent();
+ if (RigBody2D) RigBody2D.mass = mass;
+ }
+ }
+
+ return this;
+ }
+
+ void OnCollisionEnter(Collision collision)
+ {
+ if (ParentTail == null)
+ {
+ GameObject.Destroy(this);
+ return;
+ }
+
+ TailCollisionHelper helper = collision.transform.GetComponent();
+
+ if (helper)
+ {
+ if (ParentTail.CollideWithOtherTails == false) return;
+ if (helper.ParentTail == ParentTail) return;
+ }
+
+ if (ParentTail._TransformsGhostChain.Contains(collision.transform)) return;
+ if (ParentTail.IgnoredColliders.Contains(collision.collider)) return;
+
+ ParentTail.CollisionDetection(Index, collision);
+ previousCollision = collision.transform;
+ }
+
+
+ void OnCollisionExit(Collision collision)
+ {
+ if (collision.transform == previousCollision)
+ {
+ ParentTail.ExitCollision(Index);
+ previousCollision = null;
+ }
+ }
+
+
+ void OnTriggerEnter(Collider other)
+ {
+ if (other.isTrigger) return;
+
+ if (ParentTail.IgnoreMeshColliders)
+ if (other is MeshCollider) return;
+
+ if (other is CharacterController) return;
+
+
+ if (ParentTail._TransformsGhostChain.Contains(other.transform)) return;
+ if (ParentTail.IgnoredColliders.Contains(other)) return;
+
+ if (ParentTail.CollideWithOtherTails == false)
+ {
+ TailCollisionHelper helper = other.transform.GetComponent();
+ if (helper) return;
+ //if (ParentTail.CollideWithOtherTails == false) return;
+ //if (helper.ParentTail == ParentTail) return;
+ }
+
+ ParentTail.AddCollider(other);
+ }
+
+ void OnTriggerExit(Collider other)
+ {
+ if (ParentTail.IncludedColliders.Contains(other))
+ {
+ if (!ParentTail.DynamicAlwaysInclude.Contains(other))
+ ParentTail.IncludedColliders.Remove(other);
+ }
+ }
+
+
+ void OnTriggerEnter2D(Collider2D other)
+ {
+ if (other.isTrigger) return;
+
+ if (other is CompositeCollider2D) return;
+#if UNITY_2019_4_OR_NEWER
+ if (other is TilemapCollider2D) return;
+#endif
+ if (other is EdgeCollider2D) return;
+
+ if (ParentTail._TransformsGhostChain.Contains(other.transform)) return;
+ if (ParentTail.IgnoredColliders2D.Contains(other)) return;
+
+ //TailCollisionHelper helper = other.transform.GetComponent();
+ //if (helper)
+ //{
+ // if (ParentTail.CollideWithOtherTails == false) return;
+ // if (helper.ParentTail == ParentTail) return;
+ //}
+
+ if (ParentTail.CollideWithOtherTails == false)
+ {
+ TailCollisionHelper helper = other.transform.GetComponent();
+ if (helper) return;
+ }
+
+ ParentTail.AddCollider(other);
+ }
+
+ void OnTriggerExit2D(Collider2D other)
+ {
+ if (ParentTail.IncludedColliders2D.Contains(other))
+ {
+ if (!ParentTail.DynamicAlwaysInclude.Contains(other))
+ ParentTail.IncludedColliders2D.Remove(other);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Utilities/TailCollisionHelper.cs.meta b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Utilities/TailCollisionHelper.cs.meta
new file mode 100644
index 000000000..7f2f05a6c
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Animating/Tail Animator/Utilities/TailCollisionHelper.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: ea3bd5313553529418ec44a77ec6f94f
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {fileID: 2800000, guid: a05a4f2884a2af44eaeedea1ea5ca396, type: 3}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Shared/FBasic Assets/Behaviours/Cameras/FBasic_FreeCameraBehaviour.cs b/Assets/FImpossible Creations/Plugins - Shared/FBasic Assets/Behaviours/Cameras/FBasic_FreeCameraBehaviour.cs
index 9f7488922..7a96ff55e 100644
--- a/Assets/FImpossible Creations/Plugins - Shared/FBasic Assets/Behaviours/Cameras/FBasic_FreeCameraBehaviour.cs
+++ b/Assets/FImpossible Creations/Plugins - Shared/FBasic Assets/Behaviours/Cameras/FBasic_FreeCameraBehaviour.cs
@@ -19,6 +19,8 @@ namespace FIMSpace.Basics
/// Just multiplier for rotation
public float MouseSensitivity = 5f;
+ public bool NeedRMB = true;
+
/// Variables controlling turbo speed on shift key
private float turboModeMultiply = 5f;
@@ -45,6 +47,7 @@ namespace FIMSpace.Basics
void Update()
{
+
// Detecting key movement factors
float f = Input.GetAxis("Vertical");
float r = Input.GetAxis("Horizontal");
@@ -65,11 +68,14 @@ namespace FIMSpace.Basics
forward *= turbo;
right *= turbo;
- // Movement to sides with pressed rmb
- if (Input.GetMouseButton(1))
+ if (Cursor.lockState != CursorLockMode.None)
{
- rotation.x -= (Input.GetAxis("Mouse Y") * 1f * MouseSensitivity);
- rotation.y += (Input.GetAxis("Mouse X") * 1f * MouseSensitivity);
+ // Rotation with pressed rmb
+ if (Input.GetMouseButton(1) || !NeedRMB )
+ {
+ rotation.x -= (Input.GetAxis("Mouse Y") * 1f * MouseSensitivity);
+ rotation.y += (Input.GetAxis("Mouse X") * 1f * MouseSensitivity);
+ }
}
// Lerping speed variables for smooth effect
@@ -112,8 +118,11 @@ namespace FIMSpace.Basics
}
else
{
- Cursor.lockState = CursorLockMode.None;
- Cursor.visible = true;
+ if (NeedRMB)
+ {
+ Cursor.lockState = CursorLockMode.None;
+ Cursor.visible = true;
+ }
}
}
}
diff --git a/Assets/FImpossible Creations/Plugins - Shared/FBasic Assets/Shaders.meta b/Assets/FImpossible Creations/Plugins - Shared/FBasic Assets/Shaders.meta
new file mode 100644
index 000000000..189341182
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Shared/FBasic Assets/Shaders.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: a6c164d759783a64cab9addd022955d6
+folderAsset: yes
+timeCreated: 1562097466
+licenseType: Store
+DefaultImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Shared/FBasic Assets/Shaders/FDebugVertexColor.shader b/Assets/FImpossible Creations/Plugins - Shared/FBasic Assets/Shaders/FDebugVertexColor.shader
new file mode 100644
index 000000000..b50c6192f
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Shared/FBasic Assets/Shaders/FDebugVertexColor.shader
@@ -0,0 +1,41 @@
+// Made with Amplify Shader Editor
+// Available at the Unity Asset Store - http://u3d.as/y3X
+Shader "FImpossible/Debug Vertex Color"
+{
+ Properties
+ {
+ _SpecColor("Specular Color",Color)=(1,1,1,1)
+ [HideInInspector] __dirty( "", Int ) = 1
+ }
+
+ SubShader
+ {
+ Tags{ "RenderType" = "Opaque" "Queue" = "Geometry+0" }
+ Cull Back
+ CGPROGRAM
+ #pragma target 3.0
+ #pragma surface surf BlinnPhong keepalpha addshadow fullforwardshadows
+ struct Input
+ {
+ float4 vertexColor : COLOR;
+ };
+
+ void surf( Input i , inout SurfaceOutput o )
+ {
+ o.Albedo = i.vertexColor.rgb;
+ o.Alpha = 1;
+ }
+
+ ENDCG
+ }
+ Fallback "Diffuse"
+ CustomEditor "ASEMaterialInspector"
+}
+/*ASEBEGIN
+Version=17700
+196;400;1164;522;-1073.19;205.4677;1.316292;True;False
+Node;AmplifyShaderEditor.VertexColorNode;134;1778.882,152.0806;Inherit;False;0;5;COLOR;0;FLOAT;1;FLOAT;2;FLOAT;3;FLOAT;4
+Node;AmplifyShaderEditor.StandardSurfaceOutputNode;0;2007.661,79.56698;Float;False;True;-1;2;ASEMaterialInspector;0;0;BlinnPhong;FImpossible/Debug Vertex Color;False;False;False;False;False;False;False;False;False;False;False;False;False;False;False;False;False;False;False;False;False;Back;0;False;-1;0;False;-1;False;0;False;-1;0;False;-1;False;0;Opaque;0.5;True;True;0;False;Opaque;;Geometry;All;14;all;True;True;True;True;0;False;-1;False;0;False;-1;255;False;-1;255;False;-1;0;False;-1;0;False;-1;0;False;-1;0;False;-1;0;False;-1;0;False;-1;0;False;-1;0;False;-1;False;2;16.8;10;25;False;0.5;True;0;0;False;-1;0;False;-1;0;0;False;-1;0;False;-1;0;False;-1;0;False;-1;0;False;0;0,0,0,0;VertexOffset;True;False;Cylindrical;False;Relative;0;;-1;-1;-1;-1;0;False;0;0;False;-1;0;0;False;-1;0;0;0;False;0.1;False;-1;0;False;-1;15;0;FLOAT3;0,0,0;False;1;FLOAT3;0,0,0;False;2;FLOAT3;0,0,0;False;3;FLOAT;0;False;4;FLOAT;0;False;6;FLOAT3;0,0,0;False;7;FLOAT3;0,0,0;False;8;FLOAT;0;False;9;FLOAT;0;False;10;FLOAT;0;False;13;FLOAT3;0,0,0;False;11;FLOAT3;0,0,0;False;12;FLOAT3;0,0,0;False;14;FLOAT4;0,0,0,0;False;15;FLOAT3;0,0,0;False;0
+WireConnection;0;0;134;0
+ASEEND*/
+//CHKSM=EDA1B2F3D976C2A3E62B0FF40BFD5E6D54D79AB5
\ No newline at end of file
diff --git a/Assets/FImpossible Creations/Plugins - Shared/FBasic Assets/Shaders/FDebugVertexColor.shader.meta b/Assets/FImpossible Creations/Plugins - Shared/FBasic Assets/Shaders/FDebugVertexColor.shader.meta
new file mode 100644
index 000000000..dbf16391d
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Shared/FBasic Assets/Shaders/FDebugVertexColor.shader.meta
@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: eed2fa022e0342748a216ab9e75c992b
+timeCreated: 1565040098
+licenseType: Store
+ShaderImporter:
+ externalObjects: {}
+ defaultTextures: []
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Shared/FBasic Assets/Shaders/FParticle VertexLit Blended.shader b/Assets/FImpossible Creations/Plugins - Shared/FBasic Assets/Shaders/FParticle VertexLit Blended.shader
new file mode 100644
index 000000000..52210f303
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Shared/FBasic Assets/Shaders/FParticle VertexLit Blended.shader
@@ -0,0 +1,24 @@
+// Unity built-in shader source. Copyright (c) 2016 Unity Technologies. MIT license (see license.txt)
+
+Shader "Particles/FVertexLit Blended"
+{
+Properties {
+ _EmisColor ("Emissive Color", Color) = (.2,.2,.2,0)
+ _MainTex ("Particle Texture", 2D) = "white" {}
+}
+
+SubShader {
+ Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "PreviewType"="Plane" }
+ Tags { "LightMode" = "Vertex" }
+ Cull Off
+ Lighting On
+ Material { Emission [_EmisColor] }
+ ColorMaterial AmbientAndDiffuse
+ ZWrite Off
+ ColorMask RGB
+ Blend SrcAlpha OneMinusSrcAlpha
+ Pass {
+ SetTexture [_MainTex] { combine primary * texture }
+ }
+}
+}
diff --git a/Assets/FImpossible Creations/Plugins - Shared/FBasic Assets/Shaders/FParticle VertexLit Blended.shader.meta b/Assets/FImpossible Creations/Plugins - Shared/FBasic Assets/Shaders/FParticle VertexLit Blended.shader.meta
new file mode 100644
index 000000000..eaf5b1f14
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Shared/FBasic Assets/Shaders/FParticle VertexLit Blended.shader.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 29b94f23dc02e254dacf2ecc893790d3
+ShaderImporter:
+ externalObjects: {}
+ defaultTextures: []
+ nonModifiableTextures: []
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Shared/IK/CCD.meta b/Assets/FImpossible Creations/Plugins - Shared/IK/CCD.meta
new file mode 100644
index 000000000..e46875810
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Shared/IK/CCD.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 67fc378029898f8418cf4c8b4c7043bb
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Shared/IK/CCD/FIK_CCDProcessor.cs b/Assets/FImpossible Creations/Plugins - Shared/IK/CCD/FIK_CCDProcessor.cs
new file mode 100644
index 000000000..24b09bebf
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Shared/IK/CCD/FIK_CCDProcessor.cs
@@ -0,0 +1,510 @@
+using System;
+using UnityEngine;
+
+namespace FIMSpace.FTools
+{
+
+ ///
+ /// FC: Class for processing IK logics for multiple bones inverse kinematics
+ ///
+ [System.Serializable]
+ public class FIK_CCDProcessor : FIK_ProcessorBase
+ {
+ #region CCDIK Processor
+
+ public CCDIKBone[] IKBones; // { get; private set; }
+ public CCDIKBone StartIKBone { get { return IKBones[0]; } }
+ public CCDIKBone EndIKBone { get { return IKBones[IKBones.Length - 1]; } }
+
+ public bool ContinousSolving = true;
+ [Range( 0f, 1f )]
+ public float SyncWithAnimator = 1f;
+ [Range( 1, 12 )]
+ public int ReactionQuality = 2;
+ [Range( 0f, 1f )]
+ public float Smoothing = 0f;
+ [Range( 0f, 1.5f )]
+ public float StretchToTarget = 0f;
+ public AnimationCurve StretchCurve = AnimationCurve.EaseInOut( 0f, 0f, 1f, 1f );
+
+ public bool Use2D = false;
+ public bool Invert = false;
+
+ public float ActiveLength { get; private set; }
+
+ /// Assigning bones for IK processor with CCD IK logics (unlimited bone count)
+ public FIK_CCDProcessor( Transform[] bonesChain )
+ {
+ IKBones = new CCDIKBone[bonesChain.Length];
+ Bones = new CCDIKBone[IKBones.Length];
+
+ for( int i = 0; i < bonesChain.Length; i++ )
+ {
+ IKBones[i] = new CCDIKBone( bonesChain[i] );
+ Bones[i] = IKBones[i];
+ }
+
+ IKTargetPosition = EndBone.transform.position; IKTargetRotation = EndBone.transform.rotation;
+ }
+
+
+ public override void Init( Transform root )
+ {
+ if( Initialized ) return;
+
+ fullLength = 0f;
+ for( int i = 0; i < Bones.Length; i++ )
+ {
+ CCDIKBone b = IKBones[i];
+ CCDIKBone child = null, parent = null;
+
+ if( i > 0 ) parent = IKBones[i - 1];
+ if( i < Bones.Length - 1 )
+ {
+ child = IKBones[i + 1];
+ }
+
+
+ if( i < Bones.Length - 1 )
+ {
+ IKBones[i].Init( child, parent );
+ fullLength += b.BoneLength;
+ b.ForwardOrientation = Quaternion.Inverse( b.transform.rotation ) * ( IKBones[i + 1].transform.position - b.transform.position );
+ }
+ else
+ {
+ IKBones[i].Init( child, parent );
+ b.ForwardOrientation = Quaternion.Inverse( b.transform.rotation ) * ( IKBones[IKBones.Length - 1].transform.position - IKBones[0].transform.position );
+ }
+ }
+
+ Initialized = true;
+ }
+
+
+ #region Methods
+
+
+ /// Updating processor with n-bones oriented inverse kinematics
+ public override void Update()
+ {
+ if( !Initialized ) return;
+ if( IKWeight <= 0f ) return;
+ CCDIKBone wb = IKBones[0];
+
+ // Restoring previous IK progress for continous solving
+ if( ContinousSolving )
+ {
+ while( wb != null )
+ {
+ wb.LastKeyLocalRotation = wb.transform.localRotation;
+ wb.transform.localPosition = wb.LastIKLocPosition;
+ wb.transform.localRotation = wb.LastIKLocRotation;
+ wb = wb.IKChild;
+ }
+ }
+ else
+ {
+ if( SyncWithAnimator > 0f )
+ // Memory for animator syncing
+ while( wb != null )
+ {
+ wb.LastKeyLocalRotation = wb.transform.localRotation;
+ wb = wb.IKChild;
+ }
+ }
+
+ if( ReactionQuality < 0 ) ReactionQuality = 1;
+
+ Vector3 goalPivotOffset = Vector3.zero;
+ if( ReactionQuality > 1 ) goalPivotOffset = GetGoalPivotOffset();
+
+ for( int itr = 0; itr < ReactionQuality; itr++ )
+ {
+ // Restrictions for multiple interations
+ if( itr >= 1 )
+ if( goalPivotOffset.sqrMagnitude == 0 )
+ if( Smoothing > 0 )
+ if( GetVelocityDifference() < Smoothing * Smoothing ) break;
+
+ LastLocalDirection = RefreshLocalDirection();
+
+ Vector3 ikGoal = IKTargetPosition + goalPivotOffset;
+
+ // Going in iterations in reversed way, from pre end child to root parent
+ wb = IKBones[IKBones.Length - 2];
+
+ if( !Use2D ) // Full 3D space rotations calculations
+ {
+ if( !Invert )
+ {
+ while( wb != null )
+ {
+ float weight = wb.MotionWeight * IKWeight;
+
+ if( weight > 0f )
+ {
+ Quaternion targetRotation = Quaternion.FromToRotation( Bones[Bones.Length - 1].transform.position - wb.transform.position /*fromThisToEndChildBone*/, ikGoal - wb.transform.position /*fromThisToIKGoal*/) * wb.transform.rotation;
+ if( weight < 1f ) wb.transform.rotation = Quaternion.Lerp( wb.transform.rotation, targetRotation, weight );
+ else wb.transform.rotation = targetRotation;
+ }
+
+ wb.AngleLimiting();
+ wb = wb.IKParent;
+ }
+ }
+ else
+ {
+ while( wb != null )
+ {
+ wb.AngleLimiting();
+ wb = wb.IKParent;
+ }
+
+ wb = IKBones[0];
+
+ while( wb != null )
+ {
+ float weight = wb.MotionWeight * IKWeight;
+
+ if( weight > 0f )
+ {
+ Quaternion targetRotation = Quaternion.FromToRotation( Bones[Bones.Length - 1].transform.position - wb.transform.position /*fromThisToEndChildBone*/, ikGoal - wb.transform.position /*fromThisToIKGoal*/) * wb.transform.rotation;
+ if( weight < 1f ) wb.transform.rotation = Quaternion.Lerp( wb.transform.rotation, targetRotation, weight );
+ else wb.transform.rotation = targetRotation;
+ }
+
+ wb = wb.IKChild;
+ }
+ }
+ }
+ else
+ {
+ if( !Invert )
+ {
+ // Going in while() loop is 2x faster than for(i;i;i;) when there is more iterations
+ while( wb != null )
+ {
+ float weight = wb.MotionWeight * IKWeight;
+
+ if( weight > 0f )
+ {
+ Vector3 fromThisToEndChildBone = Bones[Bones.Length - 1].transform.position - wb.transform.position;
+ Vector3 fromThisToIKGoal = ikGoal - wb.transform.position;
+ wb.transform.rotation = Quaternion.AngleAxis( Mathf.DeltaAngle( Mathf.Atan2( fromThisToEndChildBone.x, fromThisToEndChildBone.y ) * Mathf.Rad2Deg /* Angle to last bone */, Mathf.Atan2( fromThisToIKGoal.x, fromThisToIKGoal.y ) * Mathf.Rad2Deg /* Angle to goal position */) * weight, Vector3.back ) * wb.transform.rotation;
+ }
+
+ wb.AngleLimiting();
+ wb = wb.IKParent;
+ }
+ }
+ else
+ {
+ while( wb != null )
+ {
+ wb.AngleLimiting();
+ wb = wb.IKParent;
+ }
+
+ wb = IKBones[0];
+
+ while( wb != null )
+ {
+ float weight = wb.MotionWeight * IKWeight;
+
+ if( weight > 0f )
+ {
+ Vector3 fromThisToEndChildBone = Bones[Bones.Length - 1].transform.position - wb.transform.position;
+ Vector3 fromThisToIKGoal = ikGoal - wb.transform.position;
+ wb.transform.rotation = Quaternion.AngleAxis( Mathf.DeltaAngle( Mathf.Atan2( fromThisToEndChildBone.x, fromThisToEndChildBone.y ) * Mathf.Rad2Deg /* Angle to last bone */, Mathf.Atan2( fromThisToIKGoal.x, fromThisToIKGoal.y ) * Mathf.Rad2Deg /* Angle to goal position */) * weight, Vector3.back ) * wb.transform.rotation;
+ }
+
+ wb = wb.IKChild;
+ }
+ }
+ }
+ }
+
+ LastLocalDirection = RefreshLocalDirection();
+
+ // Support for stretching
+ if( StretchToTarget > 0f )
+ {
+ float remainingDist = ( IKTargetPosition - EndIKBone.transform.position ).magnitude;
+
+ ActiveLength = Mathf.Epsilon;
+ wb = IKBones[0];
+ int ind = 0;
+ float boneMul = Mathf.Max( 1f, StretchToTarget );
+
+ while( wb.IKChild != null )
+ {
+ if( remainingDist <= 0f )
+ {
+ break;
+ }
+
+ Vector3 toTarget = ( IKTargetPosition - wb.transform.position );
+ Vector3 toTargetN = toTarget.normalized;
+
+ Vector3 prePos = wb.transform.position;
+ Vector3 preChildPos = wb.IKChild.transform.position;
+ Vector3 toNext = preChildPos - prePos;
+ Vector3 norm = toNext.normalized;
+
+ float dot = Vector3.Dot( norm, toTargetN );
+
+ if( dot > 0f )
+ {
+ float moveBy = wb.BoneLength * boneMul * dot;
+ if( moveBy > remainingDist ) moveBy = remainingDist;
+
+ Vector3 newChildPos = preChildPos + norm * ( moveBy );
+ wb.IKChild.transform.position = Vector3.Lerp( preChildPos, newChildPos, StretchToTarget );
+ wb.transform.rotation = wb.transform.rotation * Quaternion.FromToRotation( preChildPos - prePos, wb.Child.transform.position - wb.transform.position );
+
+ remainingDist -= Vector3.Distance( preChildPos, newChildPos );
+ }
+
+ wb = wb.IKChild;
+ ind += 1;
+ }
+
+ //if (stretch > 1f) for (int i = 1; i < IKBones.Length; ++i) IKBones[i].transform.position += (toGoal.normalized) * ((IKBones[i - 1].BoneLength ) * StretchCurve.Evaluate(-(1f - stretch)));
+ }
+
+
+ wb = IKBones[0];
+ while( wb != null )
+ {
+ // Storing final rotations for animator offset
+ wb.LastIKLocRotation = wb.transform.localRotation;
+ wb.LastIKLocPosition = wb.transform.localPosition;
+
+ // Offset based rotation sync with animator
+ Quaternion ikDiff = wb.LastIKLocRotation * Quaternion.Inverse( wb.InitialLocalRotation );
+ wb.transform.localRotation = Quaternion.Lerp( wb.LastIKLocRotation, ikDiff * wb.LastKeyLocalRotation, SyncWithAnimator );
+
+ if( IKWeight < 1f )
+ wb.transform.localRotation = Quaternion.Lerp( wb.LastKeyLocalRotation, wb.transform.localRotation, IKWeight );
+
+ wb = wb.IKChild;
+ }
+ }
+
+
+ protected Vector3 GetGoalPivotOffset()
+ {
+ if( !GoalPivotOffsetDetected() ) return Vector3.zero;
+
+ Vector3 IKDirection = ( IKTargetPosition - IKBones[0].transform.position ).normalized;
+ Vector3 secondaryDirection = new Vector3( IKDirection.y, IKDirection.z, IKDirection.x );
+
+ if( IKBones[IKBones.Length - 2].AngleLimit < 180 || IKBones[IKBones.Length - 2].TwistAngleLimit < 180 )
+ secondaryDirection = IKBones[IKBones.Length - 2].transform.rotation * IKBones[IKBones.Length - 2].ForwardOrientation;
+
+ return Vector3.Cross( IKDirection, secondaryDirection ) * IKBones[IKBones.Length - 2].BoneLength * 0.5f;
+ }
+
+ private bool GoalPivotOffsetDetected()
+ {
+ if( !Initialized ) return false;
+
+ Vector3 toLastDirection = Bones[Bones.Length - 1].transform.position - Bones[0].transform.position;
+ Vector3 toGoalDirection = IKTargetPosition - Bones[0].transform.position;
+
+ float toLastMagn = toLastDirection.magnitude;
+ float toGoalMagn = toGoalDirection.magnitude;
+
+ if( toGoalMagn == 0 ) return false;
+ if( toLastMagn == 0 ) return false;
+ if( toLastMagn < toGoalMagn ) return false;
+ if( toLastMagn < fullLength - ( Bones[Bones.Length - 2].BoneLength * 0.1f ) ) return false;
+ if( toGoalMagn > toLastMagn ) return false;
+
+ float dot = Vector3.Dot( toLastDirection / toLastMagn, toGoalDirection / toGoalMagn );
+ if( dot < 0.999f ) return false;
+
+ return true;
+ }
+
+ Vector3 RefreshLocalDirection()
+ {
+ LocalDirection = Bones[0].transform.InverseTransformDirection( Bones[Bones.Length - 1].transform.position - Bones[0].transform.position );
+ return LocalDirection;
+ }
+
+ float GetVelocityDifference()
+ { return Vector3.SqrMagnitude( LocalDirection - LastLocalDirection ); }
+
+
+
+ /// Limiting angle for all IK bones
+ public void AutoLimitAngle( float angleLimit = 60f, float twistAngleLimit = 50f )
+ {
+ if( IKBones == null ) return;
+
+ float step = 1f / (float)IKBones.Length;
+
+ if( Invert )
+ {
+ for( int i = 0; i < IKBones.Length; i++ )
+ {
+ IKBones[i].AngleLimit = angleLimit * Mathf.Min( 1f, ( 1f - ( ( i + 1 ) * step ) ) * 3f );
+ IKBones[i].TwistAngleLimit = twistAngleLimit * Mathf.Min( 1f, ( 1f - ( ( i + 1 ) * step ) ) * 4.5f );
+ }
+
+ return;
+ }
+
+ for( int i = 0; i < IKBones.Length; i++ )
+ {
+ IKBones[i].AngleLimit = angleLimit * Mathf.Min( 1f, ( i + 1 ) * step * 3f );
+ IKBones[i].TwistAngleLimit = twistAngleLimit * Mathf.Min( 1f, ( i + 1 ) * step * 4.5f );
+ }
+ }
+
+
+ /// Spreading weight over IK bones automatically
+ public void AutoWeightBones( float baseValue = 1f )
+ {
+ float step = baseValue / (float)( Bones.Length * 1.3f );
+
+ if( Invert )
+ {
+ for( int i = 0; i < Bones.Length; i++ )
+ {
+ Bones[i].MotionWeight = 1f - ( baseValue - step * i );
+ }
+
+ return;
+ }
+
+ for( int i = 0; i < Bones.Length; i++ )
+ {
+ Bones[i].MotionWeight = baseValue - step * i;
+ //Bones[i].MotionWeight *= Mathf.Min(1f, (i + 1) * step1 * 3f);
+ }
+ }
+
+
+ /// Spreading weight over IK bones with curve (Clamped01)
+ public void AutoWeightBones( AnimationCurve weightCurve )
+ {
+ if( Invert )
+ {
+ for( int i = 0; i < Bones.Length; i++ )
+ Bones[i].MotionWeight = Mathf.Clamp( 1f - weightCurve.Evaluate( (float)i / (float)Bones.Length ), 0f, 1f );
+ return;
+ }
+
+ for( int i = 0; i < Bones.Length; i++ )
+ Bones[i].MotionWeight = Mathf.Clamp( weightCurve.Evaluate( (float)i / (float)Bones.Length ), 0f, 1f );
+ }
+
+
+ #endregion
+
+ #endregion
+
+
+ [System.Serializable]
+ public class CCDIKBone : FIK_IKBoneBase
+ {
+ public CCDIKBone IKParent { get; private set; }
+ public CCDIKBone IKChild { get; private set; }
+
+ [Range( 0f, 180f )] public float AngleLimit = 45f;
+ [Range( 0f, 180f )] public float TwistAngleLimit = 5f;
+
+ /// Defined at Init() of CCD IK processor
+ public Vector3 ForwardOrientation;
+ public float FrameWorldLength = 1f;
+
+ public Vector2 HingeLimits = Vector2.zero;
+ public Quaternion PreviousHingeRotation;
+ public float PreviousHingeAngle;
+
+ public Vector3 LastIKLocPosition;
+ public Quaternion LastIKLocRotation;
+
+ public CCDIKBone( Transform t ) : base( t ) { }
+
+ public void Init( CCDIKBone child, CCDIKBone parent )
+ {
+ LastIKLocPosition = transform.localPosition;
+ IKParent = parent;
+ if( child != null ) SetChild( child );
+ IKChild = child;
+ }
+
+ public override void SetChild( FIK_IKBoneBase child )
+ {
+ base.SetChild( child );
+ }
+
+ #region CCD IK Methods
+
+ public void AngleLimiting()
+ {
+ Quaternion localRotation = Quaternion.Inverse( LastKeyLocalRotation ) * transform.localRotation;
+ Quaternion limitedRotation = localRotation;
+
+ if( FEngineering.VIsZero( HingeLimits ) )
+ {
+ if( AngleLimit < 180 ) limitedRotation = LimitSpherical( limitedRotation );
+ if( TwistAngleLimit < 180 ) limitedRotation = LimitZ( limitedRotation );
+ }
+ else limitedRotation = LimitHinge( limitedRotation );
+
+ if( FEngineering.QIsSame( limitedRotation, localRotation ) ) return;
+
+ transform.localRotation = LastKeyLocalRotation * limitedRotation;
+ }
+
+ private Quaternion LimitSpherical( Quaternion rotation )
+ {
+ if( FEngineering.QIsZero( rotation ) ) return rotation;
+ Vector3 currentForward = rotation * ForwardOrientation;
+ Quaternion limitAngle = Quaternion.RotateTowards( Quaternion.identity, Quaternion.FromToRotation( ForwardOrientation, currentForward ), AngleLimit );
+ return Quaternion.FromToRotation( currentForward, limitAngle * ForwardOrientation ) * rotation;
+ }
+
+ private Quaternion LimitZ( Quaternion currentRotation )
+ {
+ Vector3 orthoOrientation = new Vector3( ForwardOrientation.y, ForwardOrientation.z, ForwardOrientation.x );
+ Vector3 normal = currentRotation * ForwardOrientation;
+ Vector3 tangent = orthoOrientation;
+ Vector3.OrthoNormalize( ref normal, ref tangent );
+
+ orthoOrientation = currentRotation * orthoOrientation;
+ Vector3.OrthoNormalize( ref normal, ref orthoOrientation );
+
+ Quaternion limitRot = Quaternion.FromToRotation( orthoOrientation, tangent ) * currentRotation;
+ if( TwistAngleLimit <= 0 ) return limitRot;
+
+ return Quaternion.RotateTowards( limitRot, currentRotation, TwistAngleLimit );
+ }
+
+ private Quaternion LimitHinge( Quaternion rotation )
+ {
+ Quaternion addRotation = ( Quaternion.FromToRotation( rotation * ForwardOrientation, ForwardOrientation ) * rotation ) * Quaternion.Inverse( PreviousHingeRotation );
+ float addAngle = Quaternion.Angle( Quaternion.identity, addRotation );
+
+ Vector3 orthoOrientation = new Vector3( ForwardOrientation.z, ForwardOrientation.x, ForwardOrientation.y );
+ Vector3 cross = Vector3.Cross( orthoOrientation, ForwardOrientation );
+ if( Vector3.Dot( addRotation * orthoOrientation, cross ) > 0f ) addAngle = -addAngle;
+
+ PreviousHingeAngle = Mathf.Clamp( PreviousHingeAngle + addAngle, HingeLimits.x, HingeLimits.y );
+ PreviousHingeRotation = Quaternion.AngleAxis( PreviousHingeAngle, ForwardOrientation );
+ return PreviousHingeRotation;
+ }
+
+ #endregion
+
+ }
+
+ }
+
+
+}
diff --git a/Assets/FImpossible Creations/Plugins - Shared/IK/CCD/FIK_CCDProcessor.cs.meta b/Assets/FImpossible Creations/Plugins - Shared/IK/CCD/FIK_CCDProcessor.cs.meta
new file mode 100644
index 000000000..dd810248b
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Shared/IK/CCD/FIK_CCDProcessor.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: dad66f3b80f9f2a4fa589a5b9ab4da09
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Shared/Math Helpers/Animating.meta b/Assets/FImpossible Creations/Plugins - Shared/Math Helpers/Animating.meta
new file mode 100644
index 000000000..8a3620bcd
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Shared/Math Helpers/Animating.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: dbcd6612c7be2d247a034546e811150a
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Shared/Math Helpers/Animating/FAnimationClips.cs b/Assets/FImpossible Creations/Plugins - Shared/Math Helpers/Animating/FAnimationClips.cs
new file mode 100644
index 000000000..a6a08fdc8
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Shared/Math Helpers/Animating/FAnimationClips.cs
@@ -0,0 +1,316 @@
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace FIMSpace.Basics
+{
+ ///
+ /// FM: Basic class for holding animation clips as hashes inside dictionary and with some other handy methods
+ /// Add your animation clips with fAnimationClip.AddClip(animator, Idle) then use it by fAnimationClip["Idle"]
+ ///
+ public class FAnimationClips : Dictionary
+ {
+ /// Reference to Unity's Animator component
+ public readonly Animator Animator;
+
+ /// Lastest crossfaded from code animation clip name
+ public string CurrentAnimation { get; private set; }
+ /// Previously crossfaded from code animation clip name
+ public string PreviousAnimation { get; private set; }
+
+ public int Layer = 0;
+
+ ///
+ /// ADD ANIMATION CLIPS USING - AddClip() - method !!!
+ ///
+ public FAnimationClips(Animator animator)
+ {
+ this.Animator = animator;
+ CurrentAnimation = "";
+ PreviousAnimation = "";
+ }
+
+ ///
+ /// Checking if inside animator clipName state exist and with 'exactClipName' false it will check all variants of clipName, uppercase / lowercase etc.
+ ///
+ public void Add(string clipName, bool exactClipName = false)
+ {
+ AddClip(clipName, exactClipName);
+ }
+
+ ///
+ /// Checking if inside animator clipName state exist and with 'exactClipName' false it will check all variants of clipName, uppercase / lowercase etc.
+ ///
+ public void AddClip(string clipName, bool exactClipName = false)
+ {
+ AddClip(Animator, clipName, exactClipName);
+ }
+
+ ///
+ /// Checking if inside animator clipName state exist and with 'exactClipName' false it will check all variants of clipName, uppercase / lowercase etc.
+ ///
+ public void AddClip(Animator animator, string clipName, bool exactClipName = false)
+ {
+ if (!animator)
+ {
+ Debug.LogError("No animator!");
+ return;
+ }
+
+ string existing = "";
+
+ if (!exactClipName) // Checking if animation state exists with different variants for clipName word
+ {
+ if (FAnimatorMethods.StateExists(animator, clipName, Layer)) existing = clipName;
+ else
+ if (FAnimatorMethods.StateExists(animator, FStringMethods.CapitalizeFirstLetter(clipName))) existing = FStringMethods.CapitalizeFirstLetter(clipName);
+ else
+ if (FAnimatorMethods.StateExists(animator, clipName.ToLower(), Layer)) existing = clipName.ToLower();
+ else
+ if (FAnimatorMethods.StateExists(animator, clipName.ToUpper(), Layer)) existing = clipName.ToUpper();
+ }
+ else // Checking if state with provided exact name exists inside animator
+ {
+ if (FAnimatorMethods.StateExists(animator, clipName, Layer)) existing = clipName;
+ }
+
+ if (existing == "")
+ {
+ Debug.LogWarning("Clip with name " + clipName + " not exists in animator from game object " + animator.gameObject.name);
+ }
+ else // Adding clip hash to dictionary if it exists inside animator
+ {
+ if (!ContainsKey(clipName))
+ Add(clipName, Animator.StringToHash(existing));
+ }
+ }
+
+ ///
+ /// Transitioning to choosed animation by dictionary
+ ///
+ public void CrossFadeInFixedTime(string clip, float transitionTime = 0.25f, float timeOffset = 0f, bool startOver = false)
+ {
+ if (this.ContainsKey(clip))
+ {
+ RefreshClipMemory(clip);
+
+ if (startOver)
+ Animator.CrossFadeInFixedTime(this[clip], transitionTime, Layer, timeOffset);
+ else
+ if (!IsPlaying(clip))
+ Animator.CrossFadeInFixedTime(this[clip], transitionTime, Layer, timeOffset);
+ }
+ }
+
+ ///
+ /// Transitioning to choosed animation by dictionary
+ ///
+ public void CrossFade(string clip, float transitionTime = 0.25f, float timeOffset = 0f, bool startOver = false)
+ {
+ if (this.ContainsKey(clip))
+ {
+ RefreshClipMemory(clip);
+
+ if (startOver)
+ Animator.CrossFade(this[clip], transitionTime, Layer, timeOffset);
+ else
+ if (!IsPlaying(clip))
+ Animator.CrossFade(this[clip], transitionTime, Layer, timeOffset);
+ }
+ }
+
+ ///
+ /// Storing lately and currently played clip in variables
+ ///
+ private void RefreshClipMemory(string name)
+ {
+ if (name != CurrentAnimation)
+ {
+ PreviousAnimation = CurrentAnimation;
+ CurrentAnimation = name;
+ }
+ }
+
+ ///
+ /// Changing float parameter value smoothly (when speed value about 10, 60 is instant)
+ ///
+ public void SetFloat(string parameter, float value = 0f, float deltaSpeed = 60f)
+ {
+ float newValue = Animator.GetFloat(parameter);
+ if (deltaSpeed >= 60f) newValue = value; else newValue = FLogicMethods.FLerp(newValue, value, Time.deltaTime * deltaSpeed);
+ Animator.SetFloat(parameter, newValue);
+ }
+
+ ///
+ /// Changing float parameter value smoothly (when speed value about 10, 60 is instant)
+ ///
+ public void SetFloatUnscaledDelta(string parameter, float value = 0f, float deltaSpeed = 60f)
+ {
+ float newValue = Animator.GetFloat(parameter);
+ if (deltaSpeed >= 60f) newValue = value; else newValue = FLogicMethods.FLerp(newValue, value, Time.unscaledDeltaTime * deltaSpeed);
+ Animator.SetFloat(parameter, newValue);
+ }
+
+ ///
+ /// If animator is truly playing clip with given string id (added by you using clips.AddClip(name) )
+ ///
+ internal bool IsPlaying(string clip)
+ {
+ AnimatorStateInfo info;
+ if (Animator.IsInTransition(Layer))
+ {
+ info = Animator.GetNextAnimatorStateInfo(Layer);
+ if (info.shortNameHash == this[clip]) return true;
+ }
+ else
+ {
+ info = Animator.GetCurrentAnimatorStateInfo(Layer);
+ if (info.shortNameHash == this[clip]) return true;
+ }
+
+ return false;
+ }
+ }
+
+
+ public class FAnimator
+ {
+ /// Reference to Unity's Animator component
+ public readonly Animator Animator;
+
+ /// Lastest crossfaded from code animation clip name
+ public string CurrentAnimation { get; private set; }
+ /// Previously crossfaded from code animation clip name
+ public string PreviousAnimation { get; private set; }
+
+ public int Layer { get; private set; }
+
+ ///
+ /// ADD ANIMATION CLIPS USING - AddClip() - method !!!
+ ///
+ public FAnimator(Animator animator, int layer = 0)
+ {
+ this.Animator = animator;
+ CurrentAnimation = "";
+ PreviousAnimation = "";
+ Layer = layer;
+ }
+
+
+ ///
+ /// Checking if inside animator clipName state exist and with 'exactClipName' false it will check all variants of clipName, uppercase / lowercase etc.
+ ///
+ public bool ContainsClip(string clipName, bool exactClipName = false)
+ {
+ if (!Animator)
+ {
+ Debug.LogError("No animator!");
+ return false;
+ }
+
+ string existing = "";
+
+ if (!exactClipName) // Checking if animation state exists with different variants for clipName word
+ {
+ if (FAnimatorMethods.StateExists(Animator, clipName, Layer)) existing = clipName;
+ else
+ if (FAnimatorMethods.StateExists(Animator, FStringMethods.CapitalizeFirstLetter(clipName))) existing = FStringMethods.CapitalizeFirstLetter(clipName);
+ else
+ if (FAnimatorMethods.StateExists(Animator, clipName.ToLower(), Layer)) existing = clipName.ToLower();
+ else
+ if (FAnimatorMethods.StateExists(Animator, clipName.ToUpper(), Layer)) existing = clipName.ToUpper();
+ }
+ else // Checking if state with provided exact name exists inside animator
+ {
+ if (FAnimatorMethods.StateExists(Animator, clipName, Layer)) existing = clipName;
+ }
+
+ if (existing == "")
+ {
+ Debug.LogWarning("Clip with name " + clipName + " not exists in animator from game object " + Animator.gameObject.name);
+ return false;
+ }
+ else
+ return true;
+ }
+
+ ///
+ /// Transitioning to choosed animation by dictionary
+ ///
+ public void CrossFadeInFixedTime(string clip, float transitionTime = 0.25f, float timeOffset = 0f, bool startOver = false)
+ {
+ RefreshClipMemory(clip);
+
+ if (startOver)
+ Animator.CrossFadeInFixedTime(clip, transitionTime, Layer, timeOffset);
+ else
+ if (!IsPlaying(clip))
+ Animator.CrossFadeInFixedTime(clip, transitionTime, Layer, timeOffset);
+ }
+
+ ///
+ /// Transitioning to choosed animation by dictionary
+ ///
+ public void CrossFade(string clip, float transitionTime = 0.25f, float timeOffset = 0f, bool startOver = false)
+ {
+ RefreshClipMemory(clip);
+
+ if (startOver)
+ Animator.CrossFade(clip, transitionTime, Layer, timeOffset);
+ else
+ if (!IsPlaying(clip))
+ Animator.CrossFade(clip, transitionTime, Layer, timeOffset);
+ }
+
+ ///
+ /// Storing lately and currently played clip in variables
+ ///
+ private void RefreshClipMemory(string name)
+ {
+ if (name != CurrentAnimation)
+ {
+ PreviousAnimation = CurrentAnimation;
+ CurrentAnimation = name;
+ }
+ }
+
+ ///
+ /// Changing float parameter value smoothly (when speed value about 10, 60 is instant)
+ ///
+ public void SetFloat(string parameter, float value = 0f, float deltaSpeed = 60f)
+ {
+ float newValue = Animator.GetFloat(parameter);
+ if (deltaSpeed >= 60f) newValue = value; else newValue = FLogicMethods.FLerp(newValue, value, Time.deltaTime * deltaSpeed);
+ Animator.SetFloat(parameter, newValue);
+ }
+
+ ///
+ /// Changing float parameter value smoothly (when speed value about 10, 60 is instant)
+ ///
+ public void SetFloatUnscaledDelta(string parameter, float value = 0f, float deltaSpeed = 60f)
+ {
+ float newValue = Animator.GetFloat(parameter);
+ if (deltaSpeed >= 60f) newValue = value; else newValue = FLogicMethods.FLerp(newValue, value, Time.unscaledDeltaTime * deltaSpeed);
+ Animator.SetFloat(parameter, newValue);
+ }
+
+ ///
+ /// If animator is truly playing clip with given string id (added by you using clips.AddClip(name) )
+ ///
+ internal bool IsPlaying(string clip)
+ {
+ AnimatorStateInfo info;
+ if (Animator.IsInTransition(Layer))
+ {
+ info = Animator.GetNextAnimatorStateInfo(Layer);
+ if (info.shortNameHash == Animator.StringToHash(clip) ) return true;
+ }
+ else
+ {
+ info = Animator.GetCurrentAnimatorStateInfo(Layer);
+ if (info.shortNameHash == Animator.StringToHash(clip)) return true;
+ }
+
+ return false;
+ }
+ }
+}
diff --git a/Assets/FImpossible Creations/Plugins - Shared/Math Helpers/Animating/FAnimationClips.cs.meta b/Assets/FImpossible Creations/Plugins - Shared/Math Helpers/Animating/FAnimationClips.cs.meta
new file mode 100644
index 000000000..500cf0b09
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Shared/Math Helpers/Animating/FAnimationClips.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 7502876f3a7fc4648ac29443a7d6817a
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Shared/Math Helpers/Animating/FAnimatorMethods.cs b/Assets/FImpossible Creations/Plugins - Shared/Math Helpers/Animating/FAnimatorMethods.cs
new file mode 100644
index 000000000..72387a82d
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Shared/Math Helpers/Animating/FAnimatorMethods.cs
@@ -0,0 +1,91 @@
+using UnityEngine;
+
+namespace FIMSpace
+{
+ ///
+ /// FMoeglich: Class with methods which can be helpful when using unity Animator class
+ ///
+ public static class FAnimatorMethods
+ {
+
+ ///
+ /// Sets animator's float value with lerp
+ ///
+ public static void LerpFloatValue(this Animator animator, string name = "RunWalk", float value = 0f, float deltaSpeed = 8f)
+ {
+ float newValue = animator.GetFloat(name);
+ newValue = Mathf.Lerp(newValue, value, Time.deltaTime * deltaSpeed);
+ animator.SetFloat(name, newValue);
+ }
+
+
+ ///
+ /// Function called to detect if no-looped animation finish
+ ///
+ public static bool CheckAnimationEnd(this Animator animator, int layer = 0, bool reverse = false, bool checkAnimLoop = true)
+ {
+ AnimatorStateInfo info = animator.GetCurrentAnimatorStateInfo(layer);
+
+ if (!animator.IsInTransition(layer))
+ {
+ if (checkAnimLoop)
+ {
+ if (info.loop == false)
+ {
+ if (!reverse)
+ if (info.normalizedTime > 0.98f) return true;
+ else
+ if (info.normalizedTime < 0.02f) return true;
+ }
+ }
+ else /* Same operation as above but without checking if animation is looped in the source */
+ {
+ if (!reverse)
+ if (info.normalizedTime > 0.98f) return true;
+ else
+ if (info.normalizedTime < 0.02f) return true;
+ }
+ }
+
+ return false;
+ }
+
+
+ ///
+ /// Resetting all additional layers' weights to zero (lerp but reaching value)
+ ///
+ public static void ResetLayersWeights(this Animator animator, float speed = 10f)
+ {
+ for (int i = 1; i < animator.layerCount; i++)
+ {
+ animator.SetLayerWeight(i, animator.GetLayerWeight(i).Lerp(0f, Time.deltaTime * speed));
+ }
+ }
+
+
+ ///
+ /// Transitioning value of animator layer's weight to target with smooth effect
+ ///
+ public static void LerpLayerWeight(this Animator animator, int layer = 0, float newValue = 1f, float speed = 8f)
+ {
+ float newWeight = animator.GetLayerWeight(layer);
+ newWeight.Lerp(newValue, Time.deltaTime * speed);
+
+ if (newValue == 1f) if (newWeight > 0.999f) newWeight = 1f;
+ if (newValue == 0f) if (newWeight < 0.01f) newWeight = 0f;
+
+ animator.SetLayerWeight(layer, newWeight);
+ }
+
+
+ ///
+ /// Returning true if state exist
+ ///
+ public static bool StateExists(this Animator animator, string clipName, int layer = 0)
+ {
+ int animHash = Animator.StringToHash(clipName);
+ return animator.HasState(layer, animHash);
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/Assets/FImpossible Creations/Plugins - Shared/Math Helpers/Animating/FAnimatorMethods.cs.meta b/Assets/FImpossible Creations/Plugins - Shared/Math Helpers/Animating/FAnimatorMethods.cs.meta
new file mode 100644
index 000000000..751af19f2
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Shared/Math Helpers/Animating/FAnimatorMethods.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 2e38c053ed5086f49ab2f804edeed7c4
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Shared/Math Helpers/Helpers/FDebug.cs b/Assets/FImpossible Creations/Plugins - Shared/Math Helpers/Helpers/FDebug.cs
new file mode 100644
index 000000000..3f5406dab
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Shared/Math Helpers/Helpers/FDebug.cs
@@ -0,0 +1,133 @@
+using System;
+using UnityEngine;
+
+namespace FIMSpace
+{
+ ///
+ /// FMoeglich: Class with methods which can be helpful in using Unity Console.
+ /// Recommending to use some console extensions like Console Enchanced or other.
+ ///
+ public static class FDebug
+ {
+ public static void Log(string log)
+ {
+ Debug.Log("LOG: " + log);
+ }
+
+ public static void Log(string log, string category)
+ {
+ Debug.Log(MarkerColor("#1A6600") + "[" + category + "]" + EndColorMarker() + " " + log);
+ }
+
+ public static void LogRed(string log)
+ {
+ Debug.Log(MarkerColor("red") + log + EndColorMarker());
+ }
+
+ public static void LogOrange(string log)
+ {
+ Debug.Log(MarkerColor("#D1681D") + log + EndColorMarker());
+ }
+
+ public static void LogYellow(string log)
+ {
+ Debug.Log(MarkerColor("#E0D300") + log + EndColorMarker());
+ }
+
+ private static readonly System.Diagnostics.Stopwatch _debugWatch = new System.Diagnostics.Stopwatch();
+ public static void StartMeasure()
+ {
+ _debugWatch.Reset();
+ _debugWatch.Start();
+ }
+
+ public static void PauseMeasure()
+ {
+ _debugWatch.Stop();
+ }
+
+ public static void ResumeMeasure()
+ {
+ _debugWatch.Start();
+ }
+
+ public static void EndMeasureAndLog(string v)
+ {
+ _debugWatch.Stop();
+ _LastMeasureMilliseconds = _debugWatch.ElapsedMilliseconds;
+ _LastMeasureTicks = _debugWatch.ElapsedTicks;
+ UnityEngine.Debug.Log("Measure " + v + ": " + _debugWatch.ElapsedTicks + " ticks " + _debugWatch.ElapsedMilliseconds + "ms");
+ }
+
+ public static long EndMeasureAndGetTicks()
+ {
+ _debugWatch.Stop();
+ _LastMeasureMilliseconds = _debugWatch.ElapsedMilliseconds;
+ _LastMeasureTicks = _debugWatch.ElapsedTicks;
+ return _debugWatch.ElapsedTicks;
+ }
+
+ public static long _LastMeasureMilliseconds = 0;
+ public static long _LastMeasureTicks = 0;
+
+ ///
+ /// Rich text marker for color
+ ///
+ public static string MarkerColor(string color)
+ {
+ return "";
+ }
+
+ ///
+ /// close rich text marker for color
+ ///
+ public static string EndColorMarker()
+ {
+ return "";
+ }
+
+
+ public static void DrawBounds2D(this Bounds b, Color c, float y = 0f, float scale = 1f, float duration = 1.1f)
+ {
+ Vector3 fr1 = new Vector3(b.max.x, y, b.max.z) * scale;
+ Vector3 br1 = new Vector3(b.max.x, y, b.min.z) * scale;
+ Vector3 bl1 = new Vector3(b.min.x, y, b.min.z) * scale;
+ Vector3 fl1 = new Vector3(b.min.x, y, b.max.z) * scale;
+ Debug.DrawLine(fr1, br1, c, duration);
+ Debug.DrawLine(br1, bl1, c, duration);
+ Debug.DrawLine(br1, bl1, c, duration);
+ Debug.DrawLine(bl1, fl1, c, duration);
+ Debug.DrawLine(fl1, fr1, c, duration);
+ }
+
+ public static void DrawBounds3D(this Bounds b, Color c, float scale = 1f, float time = 1.01f)
+ {
+ Vector3 fr1 = new Vector3(b.max.x, b.min.y, b.max.z) * scale;
+ Vector3 br1 = new Vector3(b.max.x, b.min.y, b.min.z) * scale;
+ Vector3 bl1 = new Vector3(b.min.x, b.min.y, b.min.z) * scale;
+ Vector3 fl1 = new Vector3(b.min.x, b.min.y, b.max.z) * scale;
+ Debug.DrawLine(fr1, br1, c, time);
+ Debug.DrawLine(br1, bl1, c, time);
+ Debug.DrawLine(br1, bl1, c, time);
+ Debug.DrawLine(bl1, fl1, c, time);
+ Debug.DrawLine(fl1, fr1, c, time);
+
+ Vector3 fr = new Vector3(b.max.x, b.max.y, b.max.z) * scale;
+ Vector3 br = new Vector3(b.max.x, b.max.y, b.min.z) * scale;
+ Vector3 bl = new Vector3(b.min.x, b.max.y, b.min.z) * scale;
+ Vector3 fl = new Vector3(b.min.x, b.max.y, b.max.z) * scale;
+ Debug.DrawLine(fr, br, c, time);
+ Debug.DrawLine(br, bl, c, time);
+ Debug.DrawLine(br, bl, c, time);
+ Debug.DrawLine(bl, fl, c, time);
+ Debug.DrawLine(fl, fr, c, time);
+
+ Debug.DrawLine(fr1, fr1, c,time);
+ Debug.DrawLine(br, br1, c, time);
+ Debug.DrawLine(bl1, bl, c, time);
+ Debug.DrawLine(fl1, fl, c, time);
+ }
+
+
+ }
+}
\ No newline at end of file
diff --git a/Assets/FImpossible Creations/Plugins - Shared/Math Helpers/Helpers/FDebug.cs.meta b/Assets/FImpossible Creations/Plugins - Shared/Math Helpers/Helpers/FDebug.cs.meta
new file mode 100644
index 000000000..fb7ee08c9
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Shared/Math Helpers/Helpers/FDebug.cs.meta
@@ -0,0 +1,13 @@
+fileFormatVersion: 2
+guid: 1ddaf37d5aa608345adae3324d191ed6
+timeCreated: 1528881308
+licenseType: Store
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Shared/Math Helpers/Helpers/FStringMethods.cs b/Assets/FImpossible Creations/Plugins - Shared/Math Helpers/Helpers/FStringMethods.cs
new file mode 100644
index 000000000..19bb0e319
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Shared/Math Helpers/Helpers/FStringMethods.cs
@@ -0,0 +1,178 @@
+
+namespace FIMSpace
+{
+ ///
+ /// FM: Class which contains many helpful methods which operates
+ ///
+ public static class FStringMethods
+ {
+ ///
+ /// Converting int to strig
+ ///
+ /// value to show
+ /// How many signs, value = 8, signs = 3 -> 008
+ public static string IntToString(this int value, int signs)
+ {
+ string output = value.ToString();
+
+ int missingZeros = signs - output.Length;
+
+ if (missingZeros > 0)
+ {
+ string missing = "0";
+
+ for (int i = 1; i < missingZeros; i++)
+ {
+ missing += 0;
+ }
+
+ output = missing + output;
+ }
+
+ return output;
+ }
+
+ ///
+ /// Changing first letter to uppercase and rest to lowercase
+ ///
+ public static string CapitalizeOnlyFirstLetter(this string text)
+ {
+ if (string.IsNullOrEmpty(text)) return text;
+
+ return text[0].ToString().ToUpper() + (text.Length > 1 ? text.Substring(1) : "");
+ }
+
+ ///
+ /// Chanigng first letter to uppercase and rest without changes
+ ///
+ public static string CapitalizeFirstLetter(this string text)
+ {
+ if (string.IsNullOrEmpty(text)) return text;
+
+ return text[0].ToString().ToUpper() + text.Substring(1);
+ }
+
+ ///
+ /// Changing space signs to underline signs
+ ///
+ public static string ReplaceSpacesWithUnderline(this string text)
+ {
+ if (text.Contains(" "))
+ {
+ text = text.Replace(" ", "_");
+ }
+
+ return text;
+ }
+
+ ///
+ /// Returning string from end to the separator, for GetEndOfStringFromSeparator("ask/ddd/aaa", new char[] { '\\', '/' }) will return "aaa"
+ ///
+ /// Base string, from which you need only part of it
+ /// separators array to define, when stop checking new char[] { '\\', '/' }
+ /// how many occurences of separator should happen
+ /// start checking from end or from start of base string
+ ///
+ public static string GetEndOfStringFromSeparator(this string source, char[] separators, int which = 1, bool fromEnd = false)
+ {
+ bool separated = false;
+ int counter = 0;
+ int steps = 0;
+
+ int i = 0;
+
+ for (i = source.Length - 1; i >= 0; i--)
+ {
+ steps++;
+
+ for (int c = 0; c < separators.Length; c++)
+ {
+ if (source[i] == separators[c])
+ {
+ counter++;
+
+ if (counter == which)
+ {
+ i++;
+
+ separated = true;
+ break;
+ }
+ }
+ }
+
+ if (separated) break;
+ }
+
+ if (separated)
+ {
+ if (!fromEnd)
+ {
+ return source.Substring(0, source.Length - (steps));
+ }
+ else
+ {
+ return source.Substring(i, source.Length - i);
+ }
+ }
+ else
+ {
+ return "";
+ }
+ }
+
+ ///
+ /// Same as above GetEndOfStringFromSeparator() but here you define separators as strings, so for GetEndOfStringFromStringSeparator("ask/ddd/aaa", new string[] { "ask" }) will return "/ddd/aaa"
+ ///
+ public static string GetEndOfStringFromStringSeparator(this string source, string[] separators, int which = 1, bool rest = false)
+ {
+ bool separated = false;
+ int counter = 0;
+ int steps = 0;
+
+ int i = 0;
+ for (i = 0; i < source.Length; i++)
+ {
+ steps++;
+
+ for (int c = 0; c < separators.Length; c++)
+ {
+ if (i + separators[c].Length > source.Length) break;
+
+ if (source.Substring(i, separators[c].Length) == separators[c])
+ {
+ counter++;
+
+ if (counter == which)
+ {
+ i++;
+
+ i += separators[c].Length - 1;
+
+ separated = true;
+ break;
+ }
+ }
+ }
+
+ if (separated) break;
+ }
+
+ if (separated)
+ {
+ if (rest)
+ {
+ return source.Substring(0, source.Length - (steps));
+ }
+ else
+ {
+ return source.Substring(i, source.Length - i);
+ }
+ }
+ else
+ {
+ return "";
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/FImpossible Creations/Plugins - Shared/Math Helpers/Helpers/FStringMethods.cs.meta b/Assets/FImpossible Creations/Plugins - Shared/Math Helpers/Helpers/FStringMethods.cs.meta
new file mode 100644
index 000000000..225f3bd78
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Shared/Math Helpers/Helpers/FStringMethods.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 624de49f8d4dd534ba80e893e1269f46
+timeCreated: 1508272082
+licenseType: Store
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Shared/Math Helpers/Math/FEasing.cs b/Assets/FImpossible Creations/Plugins - Shared/Math Helpers/Math/FEasing.cs
new file mode 100644
index 000000000..898f66a73
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Shared/Math Helpers/Math/FEasing.cs
@@ -0,0 +1,230 @@
+using UnityEngine;
+
+///
+/// FM: Class containing few handy easing functions
+///
+public static class FEasing
+{
+ #region Example of how to use easings
+
+ ///
+ /// Example how to use easing function
+ ///
+ //static System.Collections.IEnumerator Example()
+ //{
+ // float timeInSecs = 3f;
+ // float elapsed = 0f;
+
+ // Vector3 from = new Vector3(-1f, 2f, 1f);
+ // Vector3 to = new Vector3(1f, 0f, 3f);
+
+ // // Simple example with hard defined easing function
+ // while (elapsed < timeInSecs)
+ // {
+ // float easeValue = EaseInOutCubic(0f, 1f, elapsed / timeInSecs);
+
+ // Vector3 easedTargetVector = Vector3.Lerp(from, to, easeValue);
+
+ // yield return null;
+ // }
+
+ // // Example with easing function to choose
+
+ // EFease easeType = EFease.EaseInOutElastic;
+
+ // float extraValue = 1.1f;
+
+ // while (elapsed < timeInSecs)
+ // {
+ // float easeValue = GetEasingFunction(easeType)(0f, 1f, elapsed / timeInSecs, extraValue);
+
+ // Vector3 easedTargetVector = Vector3.Lerp(from, to, easeValue);
+
+ // yield return null;
+ // }
+
+ //}
+
+ #endregion
+
+ public enum EFease
+ {
+ EaseInCubic,
+ EaseOutCubic,
+ EaseInOutCubic,
+
+ EaseInOutElastic,
+ EaseInElastic,
+ EaseOutElastic,
+
+ EaseInExpo,
+ EaseOutExpo,
+ EaseInOutExpo,
+
+ Linear,
+ }
+
+ #region Easing Methods
+
+ ///
+ /// Cubic smooth ease, ignore argument is for delegate to work with extra arguments
+ ///
+ public static float EaseInCubic(float start, float end, float value, float ignore = 1f)
+ {
+ end -= start;
+ return end * value * value * value + start;
+ }
+
+ public static float EaseOutCubic(float start, float end, float value, float ignore = 1f)
+ {
+ value -= 1;
+ end -= start;
+ return end * (value * value * value + 1) + start;
+ }
+
+
+ public static float EaseInOutCubic(float start, float end, float value, float ignore = 1f)
+ {
+ value /= .5f;
+ end -= start;
+
+ if (value < 1) return end * 0.5f * value * value * value + start;
+
+ value -= 2;
+
+ return end * 0.5f * (value * value * value + 2) + start;
+ }
+
+
+ public static float EaseOutElastic(float start, float end, float value, float rangeMul = 1f)
+ {
+ end -= start;
+
+ float d = 1f;
+ float p = d * .3f * rangeMul;
+ float s;
+ float a = 0;
+
+ if (value == 0) return start;
+
+ if ((value /= d) == 1) return start + end;
+
+ if (a == 0f || a < Mathf.Abs(end))
+ {
+ a = end;
+ s = p * 0.25f * rangeMul;
+ }
+ else
+ {
+ s = p / (2 * Mathf.PI) * Mathf.Asin(end / a);
+ }
+
+ return (a * Mathf.Pow(2, -10 * value * rangeMul) * Mathf.Sin((value * d - s) * (2 * Mathf.PI) / p) + end + start);
+ }
+
+
+ public static float EaseInElastic(float start, float end, float value, float rangeMul = 1f)
+ {
+ end -= start;
+
+ float d = 1f;
+ float p = d * .3f * rangeMul;
+ float s;
+ float a = 0;
+
+ if (value == 0) return start;
+
+ if ((value /= d) == 1) return start + end;
+
+ if (a == 0f || a < Mathf.Abs(end))
+ {
+ a = end;
+ s = (p / 4) * rangeMul;
+ }
+ else
+ {
+ s = p / (2 * Mathf.PI) * Mathf.Asin(end / a);
+ }
+
+ return -(a * Mathf.Pow(2, 10 * rangeMul * (value -= 1)) * Mathf.Sin((value * d - s) * (2 * Mathf.PI) / p)) + start;
+ }
+
+
+ public static float EaseInOutElastic(float start, float end, float value, float rangeMul = 1f)
+ {
+ end -= start;
+
+ float d = 1f;
+ float p = d * .3f * rangeMul;
+ float s;
+ float a = 0;
+
+ if (value == 0) return start;
+
+ if ((value /= d * 0.5f) == 2) return start + end;
+
+ if (a == 0f || a < Mathf.Abs(end))
+ {
+ a = end;
+ s = p / 4 * rangeMul;
+ }
+ else
+ {
+ s = p / (2 * Mathf.PI) * Mathf.Asin(end / a);
+ }
+
+ if (value < 1) return -0.5f * (a * Mathf.Pow(2, 10 * (value -= 1)) * Mathf.Sin((value * d - s) * (2 * Mathf.PI) / p)) + start;
+ return a * Mathf.Pow(2, -10 * rangeMul * (value -= 1)) * Mathf.Sin((value * d - s) * (2 * Mathf.PI) / p) * 0.5f + end + start;
+ }
+
+
+ public static float EaseInExpo(float start, float end, float value, float ignore = 1f)
+ {
+ end -= start;
+ return end * Mathf.Pow(2, 10 * (value - 1)) + start;
+ }
+
+ public static float EaseOutExpo(float start, float end, float value, float ignore = 1f)
+ {
+ end -= start;
+ return end * (-Mathf.Pow(2, -10 * value) + 1) + start;
+ }
+
+ public static float EaseInOutExpo(float start, float end, float value, float ignore = 1f)
+ {
+ value /= .5f;
+ end -= start;
+ if (value < 1) return end * 0.5f * Mathf.Pow(2, 10 * (value - 1)) + start;
+ value--;
+ return end * 0.5f * (-Mathf.Pow(2, -10 * value) + 2) + start;
+ }
+
+ public static float Linear(float start, float end, float value, float ignore = 1f)
+ {
+ return Mathf.Lerp(start, end, value);
+ }
+
+ #endregion
+
+ public delegate float Function(float s, float e, float v, float extraParameter = 1f);
+
+ public static Function GetEasingFunction(EFease easingFunction)
+ {
+ if (easingFunction == EFease.EaseInCubic) return EaseInCubic;
+ if (easingFunction == EFease.EaseOutCubic) return EaseOutCubic;
+ if (easingFunction == EFease.EaseInOutCubic) return EaseInOutCubic;
+
+ if (easingFunction == EFease.EaseInElastic) return EaseInElastic;
+ if (easingFunction == EFease.EaseOutElastic) return EaseOutElastic;
+ if (easingFunction == EFease.EaseInOutElastic) return EaseInOutElastic;
+
+ if (easingFunction == EFease.EaseInExpo) return EaseInExpo;
+ if (easingFunction == EFease.EaseOutExpo) return EaseOutExpo;
+ if (easingFunction == EFease.EaseInOutExpo) return EaseInOutExpo;
+
+ if (easingFunction == EFease.Linear) return Linear;
+
+ return null;
+ }
+}
+
diff --git a/Assets/FImpossible Creations/Plugins - Shared/Math Helpers/Math/FEasing.cs.meta b/Assets/FImpossible Creations/Plugins - Shared/Math Helpers/Math/FEasing.cs.meta
new file mode 100644
index 000000000..7796662a8
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Shared/Math Helpers/Math/FEasing.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: fc641929bb5b9dc468f81c4d80c0cda0
+timeCreated: 1607337550
+licenseType: Store
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Shared/Physics.meta b/Assets/FImpossible Creations/Plugins - Shared/Physics.meta
new file mode 100644
index 000000000..53fc48dee
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Shared/Physics.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: dda743092a136d0499b79fcc38fbc515
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Shared/Physics/FImp_ColliderData_Base.cs b/Assets/FImpossible Creations/Plugins - Shared/Physics/FImp_ColliderData_Base.cs
new file mode 100644
index 000000000..d279b8f7d
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Shared/Physics/FImp_ColliderData_Base.cs
@@ -0,0 +1,155 @@
+using UnityEngine;
+
+namespace FIMSpace
+{
+ /// V1.3.5
+ /// FM: Base class to hold calculations on colliders for fimpossible packages
+ ///
+ public abstract class FImp_ColliderData_Base
+ {
+ public Transform Transform { get; protected set; }
+ public Collider Collider { get; protected set; }
+ public Collider2D Collider2D { get; protected set; }
+ public bool Is2D = false;
+
+ public bool IsStatic { get; private set; }
+ public enum EFColliderType { Box, Sphere, Capsule, Mesh, Terrain }
+ public EFColliderType ColliderType { get; protected set; }
+
+ protected Vector3 previousPosition = Vector3.zero;
+ protected Quaternion previousRotation = Quaternion.identity;
+ protected Vector3 previousScale = Vector3.one;
+
+ ///
+ /// Generating class for given collider
+ ///
+ public static FImp_ColliderData_Base GetColliderDataFor(Collider collider)
+ {
+ SphereCollider s = collider as SphereCollider;
+
+ if (s)
+ return new FImp_ColliderData_Sphere(s);
+ else
+ {
+ CapsuleCollider c = collider as CapsuleCollider;
+ if (c)
+ return new FImp_ColliderData_Capsule(c);
+ else
+ {
+ BoxCollider b = collider as BoxCollider;
+ if (b)
+ return new FImp_ColliderData_Box(b);
+ else
+ {
+ MeshCollider m = collider as MeshCollider;
+ if (m)
+ return new FImp_ColliderData_Mesh(m);
+ else
+ {
+ TerrainCollider t = collider as TerrainCollider;
+ if (t)
+ return new FImp_ColliderData_Terrain(t);
+ else
+ {
+ CharacterController ch = collider as CharacterController;
+ if (ch)
+ return new FImp_ColliderData_CharacterCapsule(ch);
+ }
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
+
+ ///
+ /// Generating class for given collider
+ ///
+ public static FImp_ColliderData_Base GetColliderDataFor(Collider2D collider)
+ {
+ CircleCollider2D s = collider as CircleCollider2D;
+
+ if (s)
+ return new FImp_ColliderData_Sphere(s);
+ else
+ {
+ CapsuleCollider2D c = collider as CapsuleCollider2D;
+ if (c)
+ return new FImp_ColliderData_Capsule(c);
+ else
+ {
+ BoxCollider2D b = collider as BoxCollider2D;
+ if (b)
+ return new FImp_ColliderData_Box(b);
+ else
+ {
+ PolygonCollider2D m = collider as PolygonCollider2D;
+ if (m)
+ return new FImp_ColliderData_Mesh(m);
+ //else
+ //{
+ // EdgeCollider2D e = collider as EdgeCollider2D;
+ // if (e)
+ // return new FImp_ColliderData_Mesh(e);
+ // else
+ // {
+ // TilemapCollider2D t = collider as TilemapCollider2D;
+ // if (t)
+ // return new FImp_ColliderData_Mesh(t);
+ // else
+ // {
+ // CompositeCollider2D cps = collider as CompositeCollider2D;
+ // if (cps)
+ // return new FImp_ColliderData_Mesh(cps);
+ // }
+ // }
+ //}
+ }
+ }
+ }
+
+ return null;
+ }
+
+
+ ///
+ /// When collider moves / rotates / scales this method should be called
+ ///
+ public virtual void RefreshColliderData()
+ {
+ if (Transform.gameObject.isStatic) IsStatic = true; else IsStatic = false;
+ }
+
+
+ ///
+ /// Detecting if given point (sphere) is inside collider or colliding with (for mesh collider)
+ /// and projecting it onto collider's surface
+ ///
+ /// Position of colliding sphere which will be pushed out
+ /// Radius of colliding sphere
+ /// Offset in position of colliding sphere
+ ///
+ public virtual bool PushIfInside(ref Vector3 point, float pointRadius, Vector3 pointOffset)
+ {
+ if ( Collider as SphereCollider )
+ Debug.Log("It shouldn't appear");
+ return false;
+ }
+
+ ///
+ /// If not implemented 3D algorithm will be applied
+ ///
+ public virtual bool PushIfInside2D(ref Vector3 point, float pointRadius, Vector3 pointOffset)
+ {
+ return PushIfInside(ref point, pointRadius, pointOffset);
+ }
+
+
+ public static bool VIsSame(Vector3 vec1, Vector3 vec2)
+ {
+ if (vec1.x != vec2.x) return false; if (vec1.y != vec2.y) return false; if (vec1.z != vec2.z) return false; return true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/FImpossible Creations/Plugins - Shared/Physics/FImp_ColliderData_Base.cs.meta b/Assets/FImpossible Creations/Plugins - Shared/Physics/FImp_ColliderData_Base.cs.meta
new file mode 100644
index 000000000..f85b68681
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Shared/Physics/FImp_ColliderData_Base.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 2eae3be7652c13f4badbace952b305ea
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {fileID: 2800000, guid: 4ba1f7a7d53fd274c98bdce0c9242640, type: 3}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Shared/Physics/FImp_ColliderData_Box.cs b/Assets/FImpossible Creations/Plugins - Shared/Physics/FImp_ColliderData_Box.cs
new file mode 100644
index 000000000..83d3bb4ad
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Shared/Physics/FImp_ColliderData_Box.cs
@@ -0,0 +1,719 @@
+using UnityEngine;
+
+namespace FIMSpace
+{
+ public class FImp_ColliderData_Box : FImp_ColliderData_Base
+ {
+ public BoxCollider Box { get; private set; }
+ public BoxCollider2D Box2D { get; private set; }
+
+ private Vector3 boxCenter;
+
+ private Vector3 right;
+ private Vector3 up;
+ private Vector3 forward;
+
+ private Vector3 rightN;
+ private Vector3 upN;
+ private Vector3 forwardN;
+
+ private Vector3 scales;
+
+ // For 3D
+ public FImp_ColliderData_Box(BoxCollider collider)
+ {
+ Is2D = false;
+ Collider = collider;
+ Transform = collider.transform;
+ Box = collider;
+ ColliderType = EFColliderType.Box;
+ RefreshColliderData();
+ previousPosition = Transform.position + Vector3.forward * Mathf.Epsilon;
+ }
+
+ // For 2D
+ public FImp_ColliderData_Box(BoxCollider2D collider2D)
+ {
+ Is2D = true;
+ Collider2D = collider2D;
+ Transform = collider2D.transform;
+ Box2D = collider2D;
+ ColliderType = EFColliderType.Box;
+ RefreshColliderData();
+ previousPosition = Transform.position + Vector3.forward * Mathf.Epsilon;
+ }
+
+
+ #region Refreshing Data
+
+
+ public override void RefreshColliderData()
+ {
+ if (IsStatic) return; // No need to refresh collider data if it is static
+
+ if (Collider2D == null) // 3D Refresh
+ {
+ bool diff = false;
+
+ if (!FEngineering.VIsSame(Transform.position, previousPosition)) diff = true;
+ else
+ if (!FEngineering.QIsSame(Transform.rotation, previousRotation)) diff = true;
+
+ if (diff)
+ {
+ right = Box.transform.TransformVector((Vector3.right / 2f) * Box.size.x);
+ up = Box.transform.TransformVector((Vector3.up / 2f) * Box.size.y);
+ forward = Box.transform.TransformVector((Vector3.forward / 2f) * Box.size.z);
+
+ rightN = right.normalized;
+ upN = up.normalized;
+ forwardN = forward.normalized;
+
+ boxCenter = GetBoxCenter(Box);
+
+ scales = Vector3.Scale(Box.size, Box.transform.lossyScale);
+ scales.Normalize();
+ }
+ }
+ else // 2D Refresh
+ {
+ bool diff = false;
+
+ if (Vector2.Distance(Transform.position, previousPosition) > Mathf.Epsilon) { diff = true; }
+ else
+ if (!FEngineering.QIsSame(Transform.rotation, previousRotation)) { diff = true; }
+
+ if (diff)
+ {
+ right = Box2D.transform.TransformVector((Vector3.right / 2f) * Box2D.size.x);
+ up = Box2D.transform.TransformVector((Vector3.up / 2f) * Box2D.size.y);
+
+ rightN = right.normalized;
+ upN = up.normalized;
+
+ boxCenter = GetBoxCenter(Box2D);
+ boxCenter.z = 0f;
+
+ Vector3 scale = Transform.lossyScale; scale.z = 1f;
+ scales = Vector3.Scale(Box2D.size, scale);
+ scales.Normalize();
+ }
+ }
+
+ base.RefreshColliderData();
+
+ previousPosition = Transform.position;
+ previousRotation = Transform.rotation;
+ }
+
+
+ #endregion
+
+
+ public override bool PushIfInside(ref Vector3 segmentPosition, float segmentRadius, Vector3 segmentOffset)
+ {
+ int inOrInt = 0;
+ Vector3 interPlane = Vector3.zero;
+ Vector3 segmentOffsetted = segmentPosition + segmentOffset;
+ float planeDistance = PlaneDistance(boxCenter + up, upN, segmentOffsetted);
+ if (SphereInsidePlane(planeDistance, segmentRadius)) inOrInt++; else if (SphereIntersectsPlane(planeDistance, segmentRadius)) { inOrInt++; interPlane = up; }
+
+ planeDistance = PlaneDistance(boxCenter - up, -upN, segmentOffsetted);
+ if (SphereInsidePlane(planeDistance, segmentRadius)) inOrInt++; else if (SphereIntersectsPlane(planeDistance, segmentRadius)) { inOrInt++; interPlane = -up; }
+
+ planeDistance = PlaneDistance(boxCenter - right, -rightN, segmentOffsetted);
+ if (SphereInsidePlane(planeDistance, segmentRadius)) inOrInt++; else if (SphereIntersectsPlane(planeDistance, segmentRadius)) { inOrInt++; interPlane = -right; }
+
+ planeDistance = PlaneDistance(boxCenter + right, rightN, segmentOffsetted);
+ if (SphereInsidePlane(planeDistance, segmentRadius)) inOrInt++; else if (SphereIntersectsPlane(planeDistance, segmentRadius)) { inOrInt++; interPlane = right; }
+
+ bool insideOrIntersects = false;
+
+ if (Collider2D == null)
+ {
+ planeDistance = PlaneDistance(boxCenter + forward, forwardN, segmentOffsetted);
+ if (SphereInsidePlane(planeDistance, segmentRadius)) inOrInt++; else if (SphereIntersectsPlane(planeDistance, segmentRadius)) { inOrInt++; interPlane = forward; }
+
+ planeDistance = PlaneDistance(boxCenter - forward, -forwardN, segmentOffsetted);
+ if (SphereInsidePlane(planeDistance, segmentRadius)) inOrInt++; else if (SphereIntersectsPlane(planeDistance, segmentRadius)) { inOrInt++; interPlane = -forward; }
+
+ if (inOrInt == 6) insideOrIntersects = true;
+ }
+ else if (inOrInt == 4) insideOrIntersects = true;
+
+ if (insideOrIntersects)
+ {
+ bool inside = false;
+ //Vector3 rayDirection;
+
+ if (interPlane.sqrMagnitude == 0f) // sphere is inside the box
+ {
+ //if ( Collider2D == null)
+ // interPlane = -GetTargetPlaneNormal(Box, segmentOffsetted, right, up, forward, scales);
+ //else
+ // interPlane = -GetTargetPlaneNormal(Box2D, segmentOffsetted, right, up, scales);
+ inside = true;
+ //rayDirection = (interPlane).normalized; // poprawić przy przeskalowanych boxach
+ }
+ else // sphere is intersecting box
+ {
+ //rayDirection = (segmentOffsetted - boxCenter).normalized;
+ if (Collider2D == null)
+ { if (IsInsideBoxCollider(Box, segmentOffsetted)) inside = true; }
+ else if (IsInsideBoxCollider(Box2D, segmentOffsetted)) inside = true;
+ }
+
+ Vector3 pointOnPlane = GetNearestPoint(segmentOffsetted);
+ Vector3 toNormal = pointOnPlane - segmentOffsetted;
+
+ if (inside) toNormal += toNormal.normalized * segmentRadius; else toNormal -= toNormal.normalized * segmentRadius;
+ //Debug.DrawRay(pointOnPlane, toNormal);
+
+ if (inside)
+ {
+ segmentPosition = segmentPosition + toNormal;
+ }
+ else
+ if (toNormal.sqrMagnitude > 0) segmentPosition = segmentPosition + toNormal;
+
+ return true;
+ }
+
+ return false;
+ }
+
+
+ public static void PushOutFromBoxCollider(BoxCollider box, Collision collision, float segmentColliderRadius, ref Vector3 segmentPosition, bool is2D = false)
+ {
+ Vector3 right = box.transform.TransformVector((Vector3.right / 2f) * box.size.x + box.center.x * Vector3.right);
+ Vector3 up = box.transform.TransformVector((Vector3.up / 2f) * box.size.y + box.center.y * Vector3.up);
+ Vector3 forward = box.transform.TransformVector((Vector3.forward / 2f) * box.size.z + box.center.z * Vector3.forward);
+
+ Vector3 scales = Vector3.Scale(box.size, box.transform.lossyScale);
+ scales.Normalize();
+
+ PushOutFromBoxCollider(box, collision, segmentColliderRadius, ref segmentPosition, right, up, forward, scales, is2D);
+ }
+
+ public static void PushOutFromBoxCollider(BoxCollider box, float segmentColliderRadius, ref Vector3 segmentPosition, bool is2D = false)
+ {
+ Vector3 right = box.transform.TransformVector((Vector3.right / 2f) * box.size.x + box.center.x * Vector3.right);
+ Vector3 up = box.transform.TransformVector((Vector3.up / 2f) * box.size.y + box.center.y * Vector3.up);
+ Vector3 forward = box.transform.TransformVector((Vector3.forward / 2f) * box.size.z + box.center.z * Vector3.forward);
+
+ Vector3 scales = Vector3.Scale(box.size, box.transform.lossyScale);
+ scales.Normalize();
+
+ Vector3 boxCenter = GetBoxCenter(box);
+
+ float pointRadius = segmentColliderRadius;
+ Vector3 upN = up.normalized; Vector3 rightN = right.normalized; Vector3 forwardN = forward.normalized;
+
+ int inOrInt = 0;
+ Vector3 interPlane = Vector3.zero;
+ float planeDistance = PlaneDistance(boxCenter + up, upN, segmentPosition);
+ if (SphereInsidePlane(planeDistance, pointRadius)) inOrInt++; else if (SphereIntersectsPlane(planeDistance, pointRadius)) { inOrInt++; interPlane = up; }
+
+ planeDistance = PlaneDistance(boxCenter - up, -upN, segmentPosition);
+ if (SphereInsidePlane(planeDistance, pointRadius)) inOrInt++; else if (SphereIntersectsPlane(planeDistance, pointRadius)) { inOrInt++; interPlane = -up; }
+
+ planeDistance = PlaneDistance(boxCenter - right, -rightN, segmentPosition);
+ if (SphereInsidePlane(planeDistance, pointRadius)) inOrInt++; else if (SphereIntersectsPlane(planeDistance, pointRadius)) { inOrInt++; interPlane = -right; }
+
+ planeDistance = PlaneDistance(boxCenter + right, rightN, segmentPosition);
+ if (SphereInsidePlane(planeDistance, pointRadius)) inOrInt++; else if (SphereIntersectsPlane(planeDistance, pointRadius)) { inOrInt++; interPlane = right; }
+
+ planeDistance = PlaneDistance(boxCenter + forward, forwardN, segmentPosition);
+ if (SphereInsidePlane(planeDistance, pointRadius)) inOrInt++; else if (SphereIntersectsPlane(planeDistance, pointRadius)) { inOrInt++; interPlane = forward; }
+
+ planeDistance = PlaneDistance(boxCenter - forward, -forwardN, segmentPosition);
+ if (SphereInsidePlane(planeDistance, pointRadius)) inOrInt++; else if (SphereIntersectsPlane(planeDistance, pointRadius)) { inOrInt++; interPlane = -forward; }
+
+ // Collision occured - sphere intersecting box shape volume or is inside of it
+ if (inOrInt == 6)
+ {
+ bool inside = false;
+ //Vector3 rayDirection;
+
+ if (interPlane.sqrMagnitude == 0f) // sphere is inside the box
+ {
+ //interPlane = -GetTargetPlaneNormal(box, segmentPosition, right, up, forward, scales, is2D);
+ inside = true;
+ //rayDirection = (interPlane).normalized; // poprawić przy przeskalowanych boxach
+ }
+ else // sphere is intersecting box
+ {
+ //rayDirection = (segmentPosition - boxCenter).normalized;
+ if (IsInsideBoxCollider(box, segmentPosition)) inside = true;
+ }
+
+ Vector3 pointOnPlane = GetNearestPoint(segmentPosition, boxCenter, right, up, forward, is2D);
+
+ Vector3 toNormal = pointOnPlane - segmentPosition;
+ if (inside) toNormal += toNormal.normalized * pointRadius * 1.01f; else toNormal -= toNormal.normalized * pointRadius * 1.01f;
+
+ if (inside)
+ {
+ segmentPosition = segmentPosition + toNormal;
+ }
+ else
+ if (toNormal.sqrMagnitude > 0)
+ {
+ segmentPosition = segmentPosition + toNormal;
+ }
+ }
+ }
+
+
+ public static void PushOutFromBoxCollider(BoxCollider box, Collision collision, float segmentColliderRadius, ref Vector3 pos, Vector3 right, Vector3 up, Vector3 forward, Vector3 scales, bool is2D = false)
+ {
+ Vector3 collisionPoint = collision.contacts[0].point;
+ Vector3 pushNormal = pos - collisionPoint;
+ Vector3 boxCenter = GetBoxCenter(box);
+ if (pushNormal.sqrMagnitude == 0f) pushNormal = pos - boxCenter;
+
+ float insideMul = 1f;
+ if (IsInsideBoxCollider(box, pos))
+ {
+ // Finding intersection point on the box from the inside
+ float castFactor = GetBoxAverageScale(box);
+ Vector3 fittingNormal = GetTargetPlaneNormal(box, pos, right, up, forward, scales);
+ Vector3 fittingNormalNorm = fittingNormal.normalized;
+
+ RaycastHit info;
+ // Doing cheap boxCollider's raycast from outside to hit surface
+ if (box.Raycast(new Ray(pos - fittingNormalNorm * castFactor * 3f, fittingNormalNorm), out info, castFactor * 4))
+ {
+ collisionPoint = info.point;
+ }
+ else
+ collisionPoint = GetIntersectOnBoxFromInside(box, boxCenter, pos, fittingNormal);
+
+ pushNormal = collisionPoint - pos;
+ insideMul = 100f;
+ }
+
+ Vector3 toNormal = pos - ((pushNormal / insideMul + pushNormal.normalized * 1.15f) / 2f) * (segmentColliderRadius);
+ toNormal = collisionPoint - toNormal;
+
+ float pushMagn = toNormal.sqrMagnitude;
+ if (pushMagn > 0 && pushMagn < segmentColliderRadius * segmentColliderRadius * insideMul) pos = pos + toNormal;
+ }
+
+ #region Push out from box 2D
+
+ public static void PushOutFromBoxCollider(BoxCollider2D box2D, float segmentColliderRadius, ref Vector3 segmentPosition)
+ {
+ Vector2 right = box2D.transform.TransformVector((Vector3.right / 2f) * box2D.size.x + box2D.offset.x * Vector3.right);
+ Vector2 up = box2D.transform.TransformVector((Vector3.up / 2f) * box2D.size.y + box2D.offset.y * Vector3.up);
+
+ Vector3 scale2D = box2D.transform.lossyScale; scale2D.z = 1f;
+ Vector2 scales = Vector3.Scale(box2D.size, scale2D);
+ scales.Normalize();
+
+ Vector2 boxCenter = GetBoxCenter(box2D);
+
+ float pointRadius = segmentColliderRadius;
+ Vector2 upN = up.normalized; Vector2 rightN = right.normalized;
+
+ int inOrInt = 0;
+ Vector3 interPlane = Vector3.zero;
+ float planeDistance = PlaneDistance(boxCenter + up, upN, segmentPosition);
+ if (SphereInsidePlane(planeDistance, pointRadius)) inOrInt++; else if (SphereIntersectsPlane(planeDistance, pointRadius)) { inOrInt++; interPlane = up; }
+
+ planeDistance = PlaneDistance(boxCenter - up, -upN, segmentPosition);
+ if (SphereInsidePlane(planeDistance, pointRadius)) inOrInt++; else if (SphereIntersectsPlane(planeDistance, pointRadius)) { inOrInt++; interPlane = -up; }
+
+ planeDistance = PlaneDistance(boxCenter - right, -rightN, segmentPosition);
+ if (SphereInsidePlane(planeDistance, pointRadius)) inOrInt++; else if (SphereIntersectsPlane(planeDistance, pointRadius)) { inOrInt++; interPlane = -right; }
+
+ planeDistance = PlaneDistance(boxCenter + right, rightN, segmentPosition);
+ if (SphereInsidePlane(planeDistance, pointRadius)) inOrInt++; else if (SphereIntersectsPlane(planeDistance, pointRadius)) { inOrInt++; interPlane = right; }
+
+ // Collision occured - sphere intersecting box shape volume or is inside of it
+ if (inOrInt == 4)
+ {
+ bool inside = false;
+
+ if (interPlane.sqrMagnitude == 0f) // sphere is inside the box
+ {
+ //interPlane = -GetTargetPlaneNormal(box2D, segmentPosition, right, up, scales);
+ inside = true;
+ }
+ else // sphere is intersecting box
+ {
+ if (IsInsideBoxCollider(box2D, segmentPosition)) inside = true;
+ }
+
+ Vector3 pointOnPlane = GetNearestPoint2D(segmentPosition, boxCenter, right, up);
+
+ Vector3 toNormal = pointOnPlane - segmentPosition;
+ if (inside) toNormal += toNormal.normalized * pointRadius * 1.01f; else toNormal -= toNormal.normalized * pointRadius * 1.01f;
+
+ if (inside)
+ segmentPosition = segmentPosition + toNormal;
+ else
+ if (toNormal.sqrMagnitude > 0) segmentPosition = segmentPosition + toNormal;
+ }
+ }
+
+
+ #endregion
+
+
+ #region Box Calculations Helpers
+
+
+ ///
+ /// Getting nearest plane normal fitting to given point position
+ ///
+ private Vector3 GetNearestPoint(Vector3 point)
+ {
+ Vector3 pointOnBox = point;
+
+ Vector3 distancesPositive = Vector3.one;
+ distancesPositive.x = PlaneDistance(boxCenter + right, rightN, point);
+ distancesPositive.y = PlaneDistance(boxCenter + up, upN, point);
+ if (Collider2D == null) distancesPositive.z = PlaneDistance(boxCenter + forward, forwardN, point);
+
+ Vector3 distancesNegative = Vector3.one;
+ distancesNegative.x = PlaneDistance(boxCenter - right, -rightN, point);
+ distancesNegative.y = PlaneDistance(boxCenter - up, -upN, point);
+ if (Collider2D == null) distancesNegative.z = PlaneDistance(boxCenter - forward, -forwardN, point);
+
+ float nearestX, nearestY, nearestZ;
+ float negX = 1f, negY = 1f, negZ = 1f;
+
+ if (distancesPositive.x > distancesNegative.x) { nearestX = distancesPositive.x; negX = -1f; } else { nearestX = distancesNegative.x; negX = 1f; }
+ if (distancesPositive.y > distancesNegative.y) { nearestY = distancesPositive.y; negY = -1f; } else { nearestY = distancesNegative.y; negY = 1f; }
+
+ if (Collider2D == null)
+ {
+ if (distancesPositive.z > distancesNegative.z) { nearestZ = distancesPositive.z; negZ = -1f; } else { nearestZ = distancesNegative.z; negZ = 1f; }
+ if (nearestX > nearestZ)
+ {
+ if (nearestX > nearestY) { pointOnBox = ProjectPointOnPlane(right * negX, point, nearestX); }
+ else
+ pointOnBox = ProjectPointOnPlane(up * negY, point, nearestY);
+ }
+ else
+ {
+ if (nearestZ > nearestY) { pointOnBox = ProjectPointOnPlane(forward * negZ, point, nearestZ); }
+ else
+ pointOnBox = ProjectPointOnPlane(up * negY, point, nearestY);
+ }
+ }
+ else
+ {
+ if (nearestX > nearestY) { pointOnBox = ProjectPointOnPlane(right * negX, point, nearestX); }
+ else
+ pointOnBox = ProjectPointOnPlane(up * negY, point, nearestY);
+ }
+
+
+ return pointOnBox;
+ }
+
+ ///
+ /// Getting nearest plane normal fitting to given point position
+ ///
+ private static Vector3 GetNearestPoint(Vector3 point, Vector3 boxCenter, Vector3 right, Vector3 up, Vector3 forward, bool is2D = false)
+ {
+ Vector3 pointOnBox = point;
+
+ Vector3 distancesPositive = Vector3.one;
+ distancesPositive.x = PlaneDistance(boxCenter + right, right.normalized, point);
+ distancesPositive.y = PlaneDistance(boxCenter + up, up.normalized, point);
+ if (is2D == false) distancesPositive.z = PlaneDistance(boxCenter + forward, forward.normalized, point);
+
+ Vector3 distancesNegative = Vector3.one;
+ distancesNegative.x = PlaneDistance(boxCenter - right, -right.normalized, point);
+ distancesNegative.y = PlaneDistance(boxCenter - up, -up.normalized, point);
+ if (is2D == false) distancesNegative.z = PlaneDistance(boxCenter - forward, -forward.normalized, point);
+
+ float nearestX, nearestY, nearestZ;
+ float negX = 1f, negY = 1f, negZ = 1f;
+
+ if (distancesPositive.x > distancesNegative.x) { nearestX = distancesPositive.x; negX = -1f; } else { nearestX = distancesNegative.x; negX = 1f; }
+ if (distancesPositive.y > distancesNegative.y) { nearestY = distancesPositive.y; negY = -1f; } else { nearestY = distancesNegative.y; negY = 1f; }
+
+ if (is2D == false)
+ {
+ if (distancesPositive.z > distancesNegative.z) { nearestZ = distancesPositive.z; negZ = -1f; } else { nearestZ = distancesNegative.z; negZ = 1f; }
+
+ if (nearestX > nearestZ)
+ {
+ if (nearestX > nearestY) { pointOnBox = ProjectPointOnPlane(right * negX, point, nearestX); }
+ else
+ pointOnBox = ProjectPointOnPlane(up * negY, point, nearestY);
+ }
+ else
+ {
+ if (nearestZ > nearestY) { pointOnBox = ProjectPointOnPlane(forward * negZ, point, nearestZ); }
+ else
+ pointOnBox = ProjectPointOnPlane(up * negY, point, nearestY);
+ }
+ }
+ else
+ {
+ if (nearestX > nearestY) { pointOnBox = ProjectPointOnPlane(right * negX, point, nearestX); }
+ else
+ pointOnBox = ProjectPointOnPlane(up * negY, point, nearestY);
+ }
+
+ return pointOnBox;
+ }
+
+ ///
+ /// Getting nearest plane normal fitting to given point position
+ ///
+ private static Vector3 GetNearestPoint2D(Vector2 point, Vector2 boxCenter, Vector2 right, Vector2 up)
+ {
+ Vector3 pointOnBox = point;
+
+ Vector3 distancesPositive = Vector3.one;
+ distancesPositive.x = PlaneDistance(boxCenter + right, right.normalized, point);
+ distancesPositive.y = PlaneDistance(boxCenter + up, up.normalized, point);
+
+ Vector3 distancesNegative = Vector3.one;
+ distancesNegative.x = PlaneDistance(boxCenter - right, -right.normalized, point);
+ distancesNegative.y = PlaneDistance(boxCenter - up, -up.normalized, point);
+
+ float nearestX, nearestY;
+ float negX = 1f, negY = 1f;
+
+ if (distancesPositive.x > distancesNegative.x) { nearestX = distancesPositive.x; negX = -1f; } else { nearestX = distancesNegative.x; negX = 1f; }
+ if (distancesPositive.y > distancesNegative.y) { nearestY = distancesPositive.y; negY = -1f; } else { nearestY = distancesNegative.y; negY = 1f; }
+
+ if (nearestX > nearestY) { pointOnBox = ProjectPointOnPlane(right * negX, point, nearestX); }
+ else
+ pointOnBox = ProjectPointOnPlane(up * negY, point, nearestY);
+
+ return pointOnBox;
+ }
+
+
+ ///
+ /// Getting nearest plane point on box collider
+ ///
+ public static Vector3 GetNearestPointOnBox(BoxCollider boxCollider, Vector3 point, bool is2D = false)
+ {
+ Vector3 right = boxCollider.transform.TransformVector(Vector3.right / 2f);
+ Vector3 up = boxCollider.transform.TransformVector(Vector3.up / 2f);
+ Vector3 forward = Vector3.forward; if (is2D == false) forward = boxCollider.transform.TransformVector(Vector3.forward / 2f);
+
+ Vector3 pointOnBox = point;
+ Vector3 center = GetBoxCenter(boxCollider);
+
+ Vector3 rightN = right.normalized;
+ Vector3 upN = up.normalized;
+ Vector3 forwardN = forward.normalized;
+
+ Vector3 distancesPositive = Vector3.one;
+ distancesPositive.x = PlaneDistance(center + right, rightN, point);
+ distancesPositive.y = PlaneDistance(center + up, upN, point);
+ if (is2D == false) distancesPositive.z = PlaneDistance(center + forward, forwardN, point);
+
+ Vector3 distancesNegative = Vector3.one;
+ distancesNegative.x = PlaneDistance(center - right, -rightN, point);
+ distancesNegative.y = PlaneDistance(center - up, -upN, point);
+ if (is2D == false) distancesNegative.z = PlaneDistance(center - forward, -forwardN, point);
+
+ float nearestX, nearestY, nearestZ;
+ float negX = 1f, negY = 1f, negZ = 1f;
+
+ if (distancesPositive.x > distancesNegative.x) { nearestX = distancesPositive.x; negX = -1f; } else { nearestX = distancesNegative.x; negX = 1f; }
+ if (distancesPositive.y > distancesNegative.y) { nearestY = distancesPositive.y; negY = -1f; } else { nearestY = distancesNegative.y; negY = 1f; }
+
+ if (is2D == false)
+ {
+ if (distancesPositive.z > distancesNegative.z) { nearestZ = distancesPositive.z; negZ = -1f; } else { nearestZ = distancesNegative.z; negZ = 1f; }
+
+ if (nearestX > nearestZ)
+ {
+ if (nearestX > nearestY) { pointOnBox = ProjectPointOnPlane(right * negX, point, nearestX); }
+ else
+ pointOnBox = ProjectPointOnPlane(up * negY, point, nearestY);
+ }
+ else
+ {
+ if (nearestZ > nearestY) { pointOnBox = ProjectPointOnPlane(forward * negZ, point, nearestZ); }
+ else
+ pointOnBox = ProjectPointOnPlane(up * negY, point, nearestY);
+ }
+ }
+ else
+ {
+ if (nearestX > nearestY) { pointOnBox = ProjectPointOnPlane(right * negX, point, nearestX); }
+ else
+ pointOnBox = ProjectPointOnPlane(up * negY, point, nearestY);
+ }
+
+
+ return pointOnBox;
+ }
+
+
+ private static float PlaneDistance(Vector3 planeCenter, Vector3 planeNormal, Vector3 point)
+ {
+ return Vector3.Dot(point - planeCenter, planeNormal);
+ }
+
+ private static Vector3 ProjectPointOnPlane(Vector3 planeNormal, Vector3 point, float distance)
+ {
+ Vector3 translationVector = planeNormal.normalized * distance;
+ return point + translationVector;
+ }
+
+ private static bool SphereInsidePlane(float planeDistance, float pointRadius) { return -planeDistance > pointRadius; }
+ private static bool SphereOutsidePlane(float planeDistance, float pointRadius) { return planeDistance > pointRadius; }
+ private static bool SphereIntersectsPlane(float planeDistance, float pointRadius) { return Mathf.Abs(planeDistance) <= pointRadius; }
+
+
+ public static bool IsInsideBoxCollider(BoxCollider collider, Vector3 point, bool is2D = false)
+ {
+ point = collider.transform.InverseTransformPoint(point) - collider.center;
+
+ float xExtend = (collider.size.x * 0.5f);
+ float yExtend = (collider.size.y * 0.5f);
+ float zExtend = (collider.size.z * 0.5f);
+ return (point.x < xExtend && point.x > -xExtend && point.y < yExtend && point.y > -yExtend && point.z < zExtend && point.z > -zExtend);
+ }
+
+ // 2D Version
+ public static bool IsInsideBoxCollider(BoxCollider2D collider, Vector3 point)
+ {
+ point = (Vector2)collider.transform.InverseTransformPoint(point) - collider.offset;
+
+ float xExtend = (collider.size.x * 0.5f);
+ float yExtend = (collider.size.y * 0.5f);
+
+ return (point.x < xExtend && point.x > -xExtend && point.y < yExtend && point.y > -yExtend);
+ }
+
+
+ ///
+ /// Getting average scale of box's dimensions
+ ///
+ protected static float GetBoxAverageScale(BoxCollider box)
+ {
+ Vector3 scales = box.transform.lossyScale;
+ scales = Vector3.Scale(scales, box.size);
+ return (scales.x + scales.y + scales.z) / 3f;
+ }
+
+ protected static Vector3 GetBoxCenter(BoxCollider box)
+ {
+ return box.transform.position + box.transform.TransformVector(box.center);
+ }
+
+ protected static Vector3 GetBoxCenter(BoxCollider2D box)
+ {
+ return box.transform.position + box.transform.TransformVector(box.offset);
+ }
+
+ protected static Vector3 GetTargetPlaneNormal(BoxCollider boxCollider, Vector3 point, bool is2D = false)
+ {
+ Vector3 right = boxCollider.transform.TransformVector((Vector3.right / 2f) * boxCollider.size.x);
+ Vector3 up = boxCollider.transform.TransformVector((Vector3.up / 2f) * boxCollider.size.y);
+ Vector3 forward = Vector3.forward; if (is2D == false) forward = boxCollider.transform.TransformVector((Vector3.forward / 2f) * boxCollider.size.z);
+
+ Vector3 scales = Vector3.Scale(boxCollider.size, boxCollider.transform.lossyScale);
+ scales.Normalize();
+
+ return GetTargetPlaneNormal(boxCollider, point, right, up, forward, scales, is2D);
+ }
+
+ ///
+ /// Getting nearest plane normal fitting to given point position
+ ///
+ protected static Vector3 GetTargetPlaneNormal(BoxCollider boxCollider, Vector3 point, Vector3 right, Vector3 up, Vector3 forward, Vector3 scales, bool is2D = false)
+ {
+ Vector3 rayDirection = (GetBoxCenter(boxCollider) - point).normalized;
+
+ // Finding proper box's plane
+ Vector3 dots;
+ dots.x = Vector3.Dot(rayDirection, right.normalized);
+ dots.y = Vector3.Dot(rayDirection, up.normalized);
+ dots.x = dots.x * scales.y * scales.z;
+ dots.y = dots.y * scales.x * scales.z;
+
+ if (is2D == false)
+ {
+ dots.z = Vector3.Dot(rayDirection, forward.normalized);
+ dots.z = dots.z * scales.y * scales.x;
+ }
+ else dots.z = 0;
+
+ dots.Normalize();
+
+ Vector3 dotsAbs = dots;
+ if (dots.x < 0) dotsAbs.x = -dots.x;
+ if (dots.y < 0) dotsAbs.y = -dots.y;
+ if (dots.z < 0) dotsAbs.z = -dots.z;
+
+ Vector3 planeNormal;
+ if (dotsAbs.x > dotsAbs.y)
+ {
+ if (dotsAbs.x > dotsAbs.z || is2D) planeNormal = right * Mathf.Sign(dots.x); else planeNormal = forward * Mathf.Sign(dots.z);
+ }
+ else
+ {
+ if (dotsAbs.y > dotsAbs.z || is2D) planeNormal = up * Mathf.Sign(dots.y); else planeNormal = forward * Mathf.Sign(dots.z);
+ }
+
+ return planeNormal;
+ }
+
+
+ // 2D Version
+ protected static Vector3 GetTargetPlaneNormal(BoxCollider2D boxCollider, Vector2 point, Vector2 right, Vector2 up, Vector2 scales)
+ {
+ Vector2 rayDirection = ((Vector2)GetBoxCenter(boxCollider) - point).normalized;
+
+ // Finding proper box's plane
+ Vector2 dots;
+ dots.x = Vector3.Dot(rayDirection, right.normalized);
+ dots.y = Vector3.Dot(rayDirection, up.normalized);
+ dots.x = dots.x * scales.y;
+ dots.y = dots.y * scales.x;
+
+ dots.Normalize();
+
+ Vector2 dotsAbs = dots;
+ if (dots.x < 0) dotsAbs.x = -dots.x;
+ if (dots.y < 0) dotsAbs.y = -dots.y;
+
+ Vector3 planeNormal;
+ if (dotsAbs.x > dotsAbs.y) planeNormal = right * Mathf.Sign(dots.x);
+ else
+ planeNormal = up * Mathf.Sign(dots.y);
+
+ return planeNormal;
+ }
+
+
+ ///
+ /// Calculating cheap ray on box plane to detect position from inside
+ ///
+ protected static Vector3 GetIntersectOnBoxFromInside(BoxCollider boxCollider, Vector3 from, Vector3 to, Vector3 planeNormal)
+ {
+ Vector3 rayDirection = (to - from);
+
+ // Creating box's plane and casting cheap ray on it to detect intersection position
+ Plane plane = new Plane(-planeNormal, GetBoxCenter(boxCollider) + planeNormal);
+ Vector3 intersectionPoint = to;
+
+ float enter = 0f;
+ Ray ray = new Ray(from, rayDirection);
+ if (plane.Raycast(ray, out enter)) intersectionPoint = ray.GetPoint(enter);
+
+ return intersectionPoint;
+ }
+
+
+
+ #endregion
+
+ }
+}
diff --git a/Assets/FImpossible Creations/Plugins - Shared/Physics/FImp_ColliderData_Box.cs.meta b/Assets/FImpossible Creations/Plugins - Shared/Physics/FImp_ColliderData_Box.cs.meta
new file mode 100644
index 000000000..627efe2b7
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Shared/Physics/FImp_ColliderData_Box.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 2d88eaa8955b2dd4fa35f5005531a210
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {fileID: 2800000, guid: 4ba1f7a7d53fd274c98bdce0c9242640, type: 3}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Shared/Physics/FImp_ColliderData_Capsule.cs b/Assets/FImpossible Creations/Plugins - Shared/Physics/FImp_ColliderData_Capsule.cs
new file mode 100644
index 000000000..2d783f803
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Shared/Physics/FImp_ColliderData_Capsule.cs
@@ -0,0 +1,241 @@
+using UnityEngine;
+
+namespace FIMSpace
+{
+ public class FImp_ColliderData_Capsule : FImp_ColliderData_Base
+ {
+ public CapsuleCollider Capsule { get; private set; }
+ public CapsuleCollider2D Capsule2D { get; private set; }
+ private Vector3 Top;
+ private Vector3 Bottom;
+ private Vector3 Direction;
+ private float radius;
+ private float scaleFactor;
+ private float preRadius;
+
+ public FImp_ColliderData_Capsule(CapsuleCollider collider)
+ {
+ Is2D = false;
+ Transform = collider.transform;
+ Collider = collider;
+ Transform = collider.transform;
+ Capsule = collider;
+ ColliderType = EFColliderType.Capsule;
+ CalculateCapsuleParameters(Capsule, ref Direction, ref radius, ref scaleFactor);
+ RefreshColliderData();
+ }
+
+ public FImp_ColliderData_Capsule(CapsuleCollider2D collider)
+ {
+ Is2D = true;
+ Transform = collider.transform;
+ Collider2D = collider;
+ Transform = collider.transform;
+ Capsule2D = collider;
+ ColliderType = EFColliderType.Capsule;
+ CalculateCapsuleParameters(Capsule2D, ref Direction, ref radius, ref scaleFactor);
+ RefreshColliderData();
+ }
+
+ public override void RefreshColliderData()
+ {
+ if (IsStatic) return; // No need to refresh collider data if it is static
+
+ bool diff = false;
+
+ if (!FEngineering.VIsSame(previousPosition, Transform.position)) diff = true;
+ else
+ if (!FEngineering.QIsSame(Transform.rotation, previousRotation)) diff = true;
+ else
+ {
+ if (Is2D == false)
+ {
+ if (preRadius != Capsule.radius || !FEngineering.VIsSame(previousScale, Transform.lossyScale))
+ CalculateCapsuleParameters(Capsule, ref Direction, ref radius, ref scaleFactor);
+ }
+ else
+ {
+ if (preRadius != GetCapsule2DRadius(Capsule2D) || !FEngineering.VIsSame(previousScale, Transform.lossyScale))
+ CalculateCapsuleParameters(Capsule2D, ref Direction, ref radius, ref scaleFactor);
+ }
+ }
+
+ if (diff)
+ {
+ if (Is2D == false)
+ GetCapsuleHeadsPositions(Capsule, ref Top, ref Bottom, Direction, radius, scaleFactor);
+ else
+ GetCapsuleHeadsPositions(Capsule2D, ref Top, ref Bottom, Direction, radius, scaleFactor);
+ }
+
+ base.RefreshColliderData();
+
+ previousPosition = Transform.position;
+ previousRotation = Transform.rotation;
+ previousScale = Transform.lossyScale;
+
+ if (Is2D == false) preRadius = Capsule.radius; else preRadius = GetCapsule2DRadius(Capsule2D);
+ }
+
+ public override bool PushIfInside(ref Vector3 point, float pointRadius, Vector3 pointOffset)
+ {
+ return PushOutFromCapsuleCollider(pointRadius, ref point, Top, Bottom, radius, pointOffset, Is2D);
+ }
+
+
+ public static bool PushOutFromCapsuleCollider(CapsuleCollider capsule, float segmentColliderRadius, ref Vector3 pos, Vector3 segmentOffset)
+ {
+ Vector3 direction = Vector3.zero; float capsuleRadius = capsule.radius, scalerFactor = 1f;
+ CalculateCapsuleParameters(capsule, ref direction, ref capsuleRadius, ref scalerFactor);
+ Vector3 up = Vector3.zero, bottom = Vector3.zero;
+ GetCapsuleHeadsPositions(capsule, ref up, ref bottom, direction, capsuleRadius, scalerFactor);
+ return PushOutFromCapsuleCollider(segmentColliderRadius, ref pos, up, bottom, capsuleRadius, segmentOffset);
+ }
+
+ public static bool PushOutFromCapsuleCollider(float segmentColliderRadius, ref Vector3 segmentPos, Vector3 capSphereCenter1, Vector3 capSphereCenter2, float capsuleRadius, Vector3 segmentOffset, bool is2D = false)
+ {
+ float radius = capsuleRadius + segmentColliderRadius;
+ Vector3 capsuleUp = capSphereCenter2 - capSphereCenter1;
+ Vector3 fromCenter = (segmentPos + segmentOffset) - capSphereCenter1;
+
+ if (is2D)
+ {
+ capsuleUp.z = 0;
+ fromCenter.z = 0;
+ }
+
+ float orientationDot = Vector3.Dot(fromCenter, capsuleUp);
+
+ if (orientationDot <= 0) // Main Sphere Cap
+ {
+ float sphereRefDistMagn = fromCenter.sqrMagnitude;
+
+ if (sphereRefDistMagn > 0 && sphereRefDistMagn < radius * radius)
+ {
+ segmentPos = capSphereCenter1 - segmentOffset + fromCenter * (radius / Mathf.Sqrt(sphereRefDistMagn));
+ return true;
+ }
+ }
+ else
+ {
+ float upRefMagn = capsuleUp.sqrMagnitude;
+ if (orientationDot >= upRefMagn) // Counter Sphere Cap
+ {
+ fromCenter = (segmentPos + segmentOffset) - capSphereCenter2;
+ float sphereRefDistMagn = fromCenter.sqrMagnitude;
+
+ if (sphereRefDistMagn > 0 && sphereRefDistMagn < radius * radius)
+ {
+ segmentPos = capSphereCenter2 - segmentOffset + fromCenter * (radius / Mathf.Sqrt(sphereRefDistMagn));
+ return true;
+ }
+ }
+ else if (upRefMagn > 0) // Cylinder Volume
+ {
+ fromCenter -= capsuleUp * (orientationDot / upRefMagn);
+ float sphericalRefDistMagn = fromCenter.sqrMagnitude;
+
+ if (sphericalRefDistMagn > 0 && sphericalRefDistMagn < radius * radius)
+ {
+ float projectedDistance = Mathf.Sqrt(sphericalRefDistMagn);
+ segmentPos += fromCenter * ((radius - projectedDistance) / projectedDistance);
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+
+
+ #region Capsule Calculations Helpers
+
+ ///
+ /// Calculating capsule's centers of up and down sphere which are fitting unity capsule collider with all collider's transformations
+ ///
+ protected static void CalculateCapsuleParameters(CapsuleCollider capsule, ref Vector3 direction, ref float trueRadius, ref float scalerFactor)
+ {
+ Transform cTransform = capsule.transform;
+
+ float radiusScaler;
+
+ if (capsule.direction == 1)
+ { /* Y */
+ direction = Vector3.up; scalerFactor = cTransform.lossyScale.y;
+ radiusScaler = cTransform.lossyScale.x > cTransform.lossyScale.z ? cTransform.lossyScale.x : cTransform.lossyScale.z;
+ }
+ else if (capsule.direction == 0)
+ { /* X */
+ direction = Vector3.right; scalerFactor = cTransform.lossyScale.x;
+ radiusScaler = cTransform.lossyScale.y > cTransform.lossyScale.z ? cTransform.lossyScale.y : cTransform.lossyScale.z;
+ }
+ else
+ { /* Z */
+ direction = Vector3.forward; scalerFactor = cTransform.lossyScale.z;
+ radiusScaler = cTransform.lossyScale.y > cTransform.lossyScale.x ? cTransform.lossyScale.y : cTransform.lossyScale.x;
+ }
+
+ trueRadius = capsule.radius * radiusScaler;
+ }
+
+ private static float GetCapsule2DRadius(CapsuleCollider2D capsule)
+ {
+ if (capsule.direction == CapsuleDirection2D.Vertical)
+ return capsule.size.x / 2f;
+ else
+ return capsule.size.y / 2f;
+ }
+
+ private static float GetCapsule2DHeight(CapsuleCollider2D capsule)
+ {
+ if (capsule.direction == CapsuleDirection2D.Vertical)
+ return capsule.size.y / 2f;
+ else
+ return capsule.size.x / 2f;
+ }
+
+ protected static void CalculateCapsuleParameters(CapsuleCollider2D capsule, ref Vector3 direction, ref float trueRadius, ref float scalerFactor)
+ {
+ Transform cTransform = capsule.transform;
+
+ float radiusScaler;
+
+ if (capsule.direction == CapsuleDirection2D.Vertical)
+ { /* Y */
+ direction = Vector3.up; scalerFactor = cTransform.lossyScale.y;
+ radiusScaler = cTransform.lossyScale.x > cTransform.lossyScale.z ? cTransform.lossyScale.x : cTransform.lossyScale.z;
+ trueRadius = (capsule.size.x / 2f) * radiusScaler;
+ }
+ else if (capsule.direction == CapsuleDirection2D.Horizontal)
+ { /* X */
+ direction = Vector3.right; scalerFactor = cTransform.lossyScale.x;
+ radiusScaler = cTransform.lossyScale.y > cTransform.lossyScale.z ? cTransform.lossyScale.y : cTransform.lossyScale.z;
+ trueRadius = (capsule.size.y / 2f) * radiusScaler;
+ }
+ }
+
+ protected static void GetCapsuleHeadsPositions(CapsuleCollider capsule, ref Vector3 upper, ref Vector3 bottom, Vector3 direction, float radius, float scalerFactor)
+ {
+ Vector3 upCapCenter = direction * ((capsule.height / 2) * scalerFactor - radius); // Local Space Position
+ upper = capsule.transform.position + capsule.transform.TransformDirection(upCapCenter) + capsule.transform.TransformVector(capsule.center); // World Space
+
+ Vector3 downCapCenter = -direction * ((capsule.height / 2) * scalerFactor - radius);
+ bottom = capsule.transform.position + capsule.transform.TransformDirection(downCapCenter) + capsule.transform.TransformVector(capsule.center);
+ }
+
+ protected static void GetCapsuleHeadsPositions(CapsuleCollider2D capsule, ref Vector3 upper, ref Vector3 bottom, Vector3 direction, float radius, float scalerFactor)
+ {
+ Vector3 upCapCenter = direction * (GetCapsule2DHeight(capsule) * scalerFactor - radius); // Local Space Position
+ upper = capsule.transform.position + capsule.transform.TransformDirection(upCapCenter) + capsule.transform.TransformVector(capsule.offset); // World Space
+ upper.z = 0f;
+
+ Vector3 downCapCenter = -direction * (GetCapsule2DHeight(capsule) * scalerFactor - radius);
+ bottom = capsule.transform.position + capsule.transform.TransformDirection(downCapCenter) + capsule.transform.TransformVector(capsule.offset);
+ bottom.z = 0f;
+ }
+
+ #endregion
+
+ }
+}
diff --git a/Assets/FImpossible Creations/Plugins - Shared/Physics/FImp_ColliderData_Capsule.cs.meta b/Assets/FImpossible Creations/Plugins - Shared/Physics/FImp_ColliderData_Capsule.cs.meta
new file mode 100644
index 000000000..184292c31
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Shared/Physics/FImp_ColliderData_Capsule.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 3ffcc9ee773aad94b9214d78942d8fd4
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {fileID: 2800000, guid: 4ba1f7a7d53fd274c98bdce0c9242640, type: 3}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Shared/Physics/FImp_ColliderData_CharacterCapsule.cs b/Assets/FImpossible Creations/Plugins - Shared/Physics/FImp_ColliderData_CharacterCapsule.cs
new file mode 100644
index 000000000..3e9903162
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Shared/Physics/FImp_ColliderData_CharacterCapsule.cs
@@ -0,0 +1,141 @@
+using UnityEngine;
+
+namespace FIMSpace
+{
+ public class FImp_ColliderData_CharacterCapsule : FImp_ColliderData_Base
+ {
+ public CharacterController Capsule { get; private set; }
+ private Vector3 Top;
+ private Vector3 Bottom;
+ private Vector3 Direction;
+ private float radius;
+ private float scaleFactor;
+ private float preRadius;
+
+ public FImp_ColliderData_CharacterCapsule(CharacterController collider)
+ {
+ Is2D = false;
+ Transform = collider.transform;
+ Collider = collider;
+ Transform = collider.transform;
+ Capsule = collider;
+ ColliderType = EFColliderType.Capsule;
+ CalculateCapsuleParameters(Capsule, ref Direction, ref radius, ref scaleFactor);
+ RefreshColliderData();
+ }
+
+ public override void RefreshColliderData()
+ {
+ if (IsStatic) return; // No need to refresh collider data if it is static
+
+ bool diff = false;
+
+ if (!FEngineering.VIsSame(previousPosition, Transform.position)) diff = true;
+ else
+ if (!FEngineering.QIsSame(Transform.rotation, previousRotation)) diff = true;
+ else
+ {
+ if (preRadius != Capsule.radius || !FEngineering.VIsSame(previousScale, Transform.lossyScale))
+ CalculateCapsuleParameters(Capsule, ref Direction, ref radius, ref scaleFactor);
+ }
+
+ if (diff)
+ {
+ GetCapsuleHeadsPositions(Capsule, ref Top, ref Bottom, Direction, radius, scaleFactor);
+ }
+
+ base.RefreshColliderData();
+
+ previousPosition = Transform.position;
+ previousRotation = Transform.rotation;
+ previousScale = Transform.lossyScale;
+
+ preRadius = Capsule.radius;
+ }
+
+ public override bool PushIfInside(ref Vector3 point, float pointRadius, Vector3 pointOffset)
+ {
+ return PushOutFromCapsuleCollider(pointRadius, ref point, Top, Bottom, radius, pointOffset, false);
+ }
+
+ public static bool PushOutFromCapsuleCollider(float segmentColliderRadius, ref Vector3 segmentPos, Vector3 capSphereCenter1, Vector3 capSphereCenter2, float capsuleRadius, Vector3 segmentOffset, bool is2D = false)
+ {
+ float radius = capsuleRadius + segmentColliderRadius;
+ Vector3 capsuleUp = capSphereCenter2 - capSphereCenter1;
+ Vector3 fromCenter = (segmentPos + segmentOffset) - capSphereCenter1;
+
+ float orientationDot = Vector3.Dot(fromCenter, capsuleUp);
+
+ if (orientationDot <= 0) // Main Sphere Cap
+ {
+ float sphereRefDistMagn = fromCenter.sqrMagnitude;
+
+ if (sphereRefDistMagn > 0 && sphereRefDistMagn < radius * radius)
+ {
+ segmentPos = capSphereCenter1 - segmentOffset + fromCenter * (radius / Mathf.Sqrt(sphereRefDistMagn));
+ return true;
+ }
+ }
+ else
+ {
+ float upRefMagn = capsuleUp.sqrMagnitude;
+ if (orientationDot >= upRefMagn) // Counter Sphere Cap
+ {
+ fromCenter = (segmentPos + segmentOffset) - capSphereCenter2;
+ float sphereRefDistMagn = fromCenter.sqrMagnitude;
+
+ if (sphereRefDistMagn > 0 && sphereRefDistMagn < radius * radius)
+ {
+ segmentPos = capSphereCenter2 - segmentOffset + fromCenter * (radius / Mathf.Sqrt(sphereRefDistMagn));
+ return true;
+ }
+ }
+ else if (upRefMagn > 0) // Cylinder Volume
+ {
+ fromCenter -= capsuleUp * (orientationDot / upRefMagn);
+ float sphericalRefDistMagn = fromCenter.sqrMagnitude;
+
+ if (sphericalRefDistMagn > 0 && sphericalRefDistMagn < radius * radius)
+ {
+ float projectedDistance = Mathf.Sqrt(sphericalRefDistMagn);
+ segmentPos += fromCenter * ((radius - projectedDistance) / projectedDistance);
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+
+
+ #region Capsule Calculations Helpers
+
+ ///
+ /// Calculating capsule's centers of up and down sphere which are fitting unity capsule collider with all collider's transformations
+ ///
+ protected static void CalculateCapsuleParameters(CharacterController capsule, ref Vector3 direction, ref float trueRadius, ref float scalerFactor)
+ {
+ Transform cTransform = capsule.transform;
+
+ float radiusScaler;
+
+ direction = Vector3.up; scalerFactor = cTransform.lossyScale.y;
+ radiusScaler = cTransform.lossyScale.x > cTransform.lossyScale.z ? cTransform.lossyScale.x : cTransform.lossyScale.z;
+
+ trueRadius = capsule.radius * radiusScaler;
+ }
+
+ protected static void GetCapsuleHeadsPositions(CharacterController capsule, ref Vector3 upper, ref Vector3 bottom, Vector3 direction, float radius, float scalerFactor)
+ {
+ Vector3 upCapCenter = direction * ((capsule.height / 2) * scalerFactor - radius); // Local Space Position
+ upper = capsule.transform.position + capsule.transform.TransformDirection(upCapCenter) + capsule.transform.TransformVector(capsule.center); // World Space
+
+ Vector3 downCapCenter = -direction * ((capsule.height / 2) * scalerFactor - radius);
+ bottom = capsule.transform.position + capsule.transform.TransformDirection(downCapCenter) + capsule.transform.TransformVector(capsule.center);
+ }
+
+ #endregion
+
+ }
+}
diff --git a/Assets/FImpossible Creations/Plugins - Shared/Physics/FImp_ColliderData_CharacterCapsule.cs.meta b/Assets/FImpossible Creations/Plugins - Shared/Physics/FImp_ColliderData_CharacterCapsule.cs.meta
new file mode 100644
index 000000000..f3e0bafc0
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Shared/Physics/FImp_ColliderData_CharacterCapsule.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: c29c49f32c3d59546973844bb3f495d8
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {fileID: 2800000, guid: 4ba1f7a7d53fd274c98bdce0c9242640, type: 3}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Shared/Physics/FImp_ColliderData_Mesh.cs b/Assets/FImpossible Creations/Plugins - Shared/Physics/FImp_ColliderData_Mesh.cs
new file mode 100644
index 000000000..1f280f2b3
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Shared/Physics/FImp_ColliderData_Mesh.cs
@@ -0,0 +1,235 @@
+using UnityEngine;
+
+namespace FIMSpace
+{
+ public class FImp_ColliderData_Mesh : FImp_ColliderData_Base
+ {
+ public MeshCollider Mesh { get; private set; }
+ public PolygonCollider2D Poly2D { get; private set; }
+ private ContactFilter2D filter;
+
+ public FImp_ColliderData_Mesh(MeshCollider collider)
+ {
+ Is2D = false;
+ Transform = collider.transform;
+ Collider = collider;
+ Mesh = collider;
+ ColliderType = EFColliderType.Mesh;
+ }
+
+ public FImp_ColliderData_Mesh(PolygonCollider2D collider)
+ {
+ Is2D = true;
+ Transform = collider.transform;
+ Poly2D = collider;
+ Collider2D = collider;
+ ColliderType = EFColliderType.Mesh;
+ filter = new ContactFilter2D();
+ filter.useTriggers = false;
+ filter.useDepth = false;
+ r = new RaycastHit2D[1];
+ }
+
+ private RaycastHit2D[] r;
+ public override bool PushIfInside(ref Vector3 segmentPosition, float segmentRadius, Vector3 segmentOffset)
+ {
+ if (Is2D == false)
+ {
+ if (Mesh.convex)
+ {
+ Vector3 closest;
+ Vector3 positionOffsetted = segmentPosition + segmentOffset;
+ float castMul = 1f;
+
+ closest = Physics.ClosestPoint(positionOffsetted, Mesh, Mesh.transform.position, Mesh.transform.rotation);
+ if (Vector3.Distance(closest, positionOffsetted) > segmentRadius * 1.01f) return false;
+
+ Vector3 dir = (closest - positionOffsetted);
+ if (dir == Vector3.zero) return false;
+
+ RaycastHit meshHit;
+ Mesh.Raycast(new Ray(positionOffsetted, dir.normalized), out meshHit, segmentRadius * castMul);
+
+ if (meshHit.transform)
+ {
+ segmentPosition = meshHit.point + meshHit.normal * segmentRadius;
+ return true;
+ }
+ }
+ else
+ {
+ Vector3 closest;
+ float plus = 0f;
+
+ Vector3 positionOffsetted = segmentPosition + segmentOffset;
+
+ closest = Mesh.ClosestPointOnBounds(positionOffsetted);
+ plus = (closest - Mesh.transform.position).magnitude;
+
+ bool inside = false;
+ float insideMul = 1f;
+
+ if (closest == positionOffsetted)
+ {
+ inside = true;
+ insideMul = 7f;
+ closest = Mesh.transform.position;
+ }
+
+ Vector3 targeting = closest - positionOffsetted;
+ Vector3 rayDirection = targeting.normalized;
+ Vector3 rayOrigin = positionOffsetted - rayDirection * (segmentRadius * 2f + Mesh.bounds.extents.magnitude);
+
+ float rayDistance = targeting.magnitude + segmentRadius * 2f + plus + Mesh.bounds.extents.magnitude;
+
+ if ((positionOffsetted - closest).magnitude < segmentRadius * insideMul)
+ {
+ Ray ray = new Ray(rayOrigin, rayDirection);
+
+ RaycastHit hit;
+ if (Mesh.Raycast(ray, out hit, rayDistance))
+ {
+ float hitToPointDist = (positionOffsetted - hit.point).magnitude;
+
+ if (hitToPointDist < segmentRadius * insideMul)
+ {
+
+ Vector3 toNormal = hit.point - positionOffsetted;
+ Vector3 pushNormal;
+
+ if (inside) pushNormal = toNormal + toNormal.normalized * segmentRadius; else pushNormal = toNormal - toNormal.normalized * segmentRadius;
+
+ float dot = Vector3.Dot((hit.point - positionOffsetted).normalized, rayDirection);
+ if (inside && dot > 0f) pushNormal = toNormal - toNormal.normalized * segmentRadius;
+
+ segmentPosition = segmentPosition + pushNormal;
+
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+ }
+ else
+ {
+#if UNITY_2019_1_OR_NEWER
+ Vector2 positionOffsetted = segmentPosition + segmentOffset;
+ Vector2 closest;
+
+ if (Poly2D.OverlapPoint(positionOffsetted))
+ {
+ // Collider inside polygon collider!
+ Vector3 indir = Poly2D.bounds.center - (Vector3)positionOffsetted; indir.z = 0f;
+ Ray r = new Ray(Poly2D.bounds.center - indir * Poly2D.bounds.max.magnitude, indir);
+ float dist = 0f;
+ Poly2D.bounds.IntersectRay(r, out dist); // We've got partially correct point
+ if (dist > 0f)
+ closest = Poly2D.ClosestPoint(r.GetPoint(dist));
+ else
+ closest = Poly2D.ClosestPoint(positionOffsetted);
+ }
+ else
+ closest = Poly2D.ClosestPoint(positionOffsetted);
+
+ Vector2 dir = (closest - positionOffsetted).normalized;
+ int hits = Physics2D.Raycast(positionOffsetted, dir, filter, r, segmentRadius);
+
+ if (hits > 0)
+ {
+ if (r[0].transform == Transform)
+ {
+ segmentPosition = closest + r[0].normal * segmentRadius;
+ return true;
+ }
+ }
+#else
+ return false;
+#endif
+ }
+
+ return false;
+ }
+
+
+
+ public static void PushOutFromMeshCollider(MeshCollider mesh, Collision collision, float segmentColliderRadius, ref Vector3 pos)
+ {
+ Vector3 collisionPoint = collision.contacts[0].point;
+ Vector3 pushNormal = collision.contacts[0].normal;
+
+ RaycastHit info;
+ // Doing cheap mesh raycast from outside to hit surface
+ if (mesh.Raycast(new Ray(pos + pushNormal * segmentColliderRadius * 2f, -pushNormal), out info, segmentColliderRadius * 5))
+ {
+ pushNormal = info.point - pos;
+ float pushMagn = pushNormal.sqrMagnitude;
+ if (pushMagn > 0 && pushMagn < segmentColliderRadius * segmentColliderRadius) pos = info.point - pushNormal * (segmentColliderRadius / Mathf.Sqrt(pushMagn)) * 0.9f;
+ }
+ else
+ {
+ pushNormal = collisionPoint - pos;
+ float pushMagn = pushNormal.sqrMagnitude;
+ if (pushMagn > 0 && pushMagn < segmentColliderRadius * segmentColliderRadius) pos = collisionPoint - pushNormal * (segmentColliderRadius / Mathf.Sqrt(pushMagn)) * 0.9f;
+ }
+ }
+
+
+
+ public static void PushOutFromMesh(MeshCollider mesh, Collision collision, float pointRadius, ref Vector3 point)
+ {
+ Vector3 closest;
+ float plus = 0f;
+
+ closest = mesh.ClosestPointOnBounds(point);
+ plus = (closest - mesh.transform.position).magnitude;
+
+ bool inside = false;
+ float insideMul = 1f;
+
+ if (closest == point)
+ {
+ inside = true;
+ insideMul = 7f;
+ closest = mesh.transform.position;
+ }
+
+ Vector3 targeting = closest - point;
+ Vector3 rayDirection = targeting.normalized;
+ Vector3 rayOrigin = point - rayDirection * (pointRadius * 2f + mesh.bounds.extents.magnitude);
+
+ float rayDistance = targeting.magnitude + pointRadius * 2f + plus + mesh.bounds.extents.magnitude;
+
+ if ((point - closest).magnitude < pointRadius * insideMul)
+ {
+ Vector3 collisionPoint;
+
+ if (!inside)
+ collisionPoint = collision.contacts[0].point;
+ else
+ {
+ Ray ray = new Ray(rayOrigin, rayDirection);
+ RaycastHit hit;
+ if (mesh.Raycast(ray, out hit, rayDistance)) collisionPoint = hit.point; else collisionPoint = collision.contacts[0].point;
+ }
+
+ float hitToPointDist = (point - collisionPoint).magnitude;
+
+ if (hitToPointDist < pointRadius * insideMul)
+ {
+ Vector3 toNormal = collisionPoint - point;
+ Vector3 pushNormal;
+
+ if (inside) pushNormal = toNormal + toNormal.normalized * pointRadius; else pushNormal = toNormal - toNormal.normalized * pointRadius;
+
+ float dot = Vector3.Dot((collisionPoint - point).normalized, rayDirection);
+ if (inside && dot > 0f) pushNormal = toNormal - toNormal.normalized * pointRadius;
+
+ point = point + pushNormal;
+ }
+ }
+ }
+
+ }
+}
diff --git a/Assets/FImpossible Creations/Plugins - Shared/Physics/FImp_ColliderData_Mesh.cs.meta b/Assets/FImpossible Creations/Plugins - Shared/Physics/FImp_ColliderData_Mesh.cs.meta
new file mode 100644
index 000000000..02039a190
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Shared/Physics/FImp_ColliderData_Mesh.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: bde60ae57f06f434ebd27fc9589b8ff7
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {fileID: 2800000, guid: 4ba1f7a7d53fd274c98bdce0c9242640, type: 3}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Shared/Physics/FImp_ColliderData_Sphere.cs b/Assets/FImpossible Creations/Plugins - Shared/Physics/FImp_ColliderData_Sphere.cs
new file mode 100644
index 000000000..1d5fefe63
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Shared/Physics/FImp_ColliderData_Sphere.cs
@@ -0,0 +1,138 @@
+using UnityEngine;
+
+namespace FIMSpace
+{
+ public class FImp_ColliderData_Sphere : FImp_ColliderData_Base
+ {
+ public SphereCollider Sphere { get; private set; }
+ public CircleCollider2D Sphere2D { get; private set; }
+ private float SphereRadius;
+
+ public FImp_ColliderData_Sphere(SphereCollider collider)
+ {
+ Is2D = false;
+ Transform = collider.transform;
+ Collider = collider;
+ Sphere = collider;
+ ColliderType = EFColliderType.Sphere;
+ RefreshColliderData();
+ }
+
+ public FImp_ColliderData_Sphere(CircleCollider2D collider)
+ {
+ Is2D = true;
+ Transform = collider.transform;
+ Collider2D = collider;
+ Sphere2D = collider;
+ ColliderType = EFColliderType.Sphere;
+ RefreshColliderData();
+ }
+
+ public override void RefreshColliderData()
+ {
+ if (IsStatic) return; // No need to refresh collider data if it is static
+
+ if (Sphere2D == null)
+ {
+ SphereRadius = CalculateTrueRadiusOfSphereCollider(Sphere.transform, Sphere.radius);
+ base.RefreshColliderData();
+ }
+ else
+ {
+ SphereRadius = CalculateTrueRadiusOfSphereCollider(Sphere2D.transform, Sphere2D.radius);
+ base.RefreshColliderData();
+ }
+ }
+
+ public override bool PushIfInside(ref Vector3 point, float pointRadius, Vector3 pointOffset)
+ {
+ if ( Is2D == false)
+ return PushOutFromSphereCollider(Sphere, pointRadius, ref point, SphereRadius, pointOffset);
+ else
+ return PushOutFromSphereCollider(Sphere2D, pointRadius, ref point, SphereRadius, pointOffset);
+ }
+
+
+ public static bool PushOutFromSphereCollider(SphereCollider sphere, float segmentColliderRadius, ref Vector3 segmentPos, Vector3 segmentOffset)
+ {
+ return PushOutFromSphereCollider(sphere, segmentColliderRadius, ref segmentPos, CalculateTrueRadiusOfSphereCollider(sphere), segmentOffset);
+ }
+
+
+ public static bool PushOutFromSphereCollider(SphereCollider sphere, float segmentColliderRadius, ref Vector3 segmentPos, float collidingSphereRadius, Vector3 segmentOffset)
+ {
+ Vector3 sphereCenter = sphere.transform.position + sphere.transform.TransformVector(sphere.center);
+ float radius = collidingSphereRadius + segmentColliderRadius;
+
+ Vector3 pushNormal = (segmentPos + segmentOffset) - sphereCenter;
+ float squaredPushMagn = pushNormal.sqrMagnitude;
+
+ if (squaredPushMagn > 0 && squaredPushMagn < radius * radius)
+ {
+ segmentPos = sphereCenter - segmentOffset + pushNormal * (radius / Mathf.Sqrt(squaredPushMagn));
+ return true;
+ }
+
+ return false;
+ }
+
+ public static bool PushOutFromSphereCollider(CircleCollider2D sphere, float segmentColliderRadius, ref Vector3 segmentPos, float collidingSphereRadius, Vector3 segmentOffset)
+ {
+ Vector3 sphereCenter = sphere.transform.position + sphere.transform.TransformVector(sphere.offset);
+ sphereCenter.z = 0f;
+ float radius = collidingSphereRadius + segmentColliderRadius;
+
+ Vector3 pos2D = segmentPos; pos2D.z = 0f;
+ Vector3 pushNormal = (pos2D + segmentOffset) - sphereCenter;
+ float squaredPushMagn = pushNormal.sqrMagnitude;
+
+ if (squaredPushMagn > 0 && squaredPushMagn < radius * radius)
+ {
+ segmentPos = sphereCenter - segmentOffset + pushNormal * (radius / Mathf.Sqrt(squaredPushMagn));
+ return true;
+ }
+
+ return false;
+ }
+
+ #region Sphere Calculation Helpers
+
+ ///
+ /// Calculating radius of sphere collider including sphere collider's transform scalling
+ ///
+ public static float CalculateTrueRadiusOfSphereCollider(SphereCollider sphere)
+ {
+ return CalculateTrueRadiusOfSphereCollider(sphere.transform, sphere.radius);
+ }
+
+ public static float CalculateTrueRadiusOfSphereCollider(CircleCollider2D sphere)
+ {
+ return CalculateTrueRadiusOfSphereCollider(sphere.transform, sphere.radius);
+ }
+
+ ///
+ /// Calculating radius of sphere collider including sphere collider's transform scalling
+ ///
+ public static float CalculateTrueRadiusOfSphereCollider(Transform transform, float componentRadius)
+ {
+ float radius = componentRadius;
+
+ if (transform.lossyScale.x > transform.lossyScale.y)
+ {
+ if (transform.lossyScale.x > transform.lossyScale.z) radius *= transform.lossyScale.x;
+ else
+ radius *= transform.lossyScale.z;
+ }
+ else
+ {
+ if (transform.lossyScale.y > transform.lossyScale.z) radius *= transform.lossyScale.y;
+ else
+ radius *= transform.lossyScale.z;
+ }
+
+ return radius;
+ }
+
+ #endregion
+ }
+}
diff --git a/Assets/FImpossible Creations/Plugins - Shared/Physics/FImp_ColliderData_Sphere.cs.meta b/Assets/FImpossible Creations/Plugins - Shared/Physics/FImp_ColliderData_Sphere.cs.meta
new file mode 100644
index 000000000..73a23a919
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Shared/Physics/FImp_ColliderData_Sphere.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: bba586e4c6fd54349ad44a2c387d49bf
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {fileID: 2800000, guid: 4ba1f7a7d53fd274c98bdce0c9242640, type: 3}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Plugins - Shared/Physics/FImp_ColliderData_Terrain.cs b/Assets/FImpossible Creations/Plugins - Shared/Physics/FImp_ColliderData_Terrain.cs
new file mode 100644
index 000000000..7095f9979
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Shared/Physics/FImp_ColliderData_Terrain.cs
@@ -0,0 +1,94 @@
+using UnityEngine;
+
+namespace FIMSpace
+{
+ public class FImp_ColliderData_Terrain : FImp_ColliderData_Base
+ {
+ public TerrainCollider TerrCollider { get; private set; }
+ public Terrain TerrainComponent { get; private set; }
+
+ public FImp_ColliderData_Terrain(TerrainCollider collider)
+ {
+ Collider = collider;
+ Transform = collider.transform;
+ TerrCollider = collider;
+ ColliderType = EFColliderType.Terrain;
+ TerrainComponent = collider.GetComponent();
+ }
+
+ public override bool PushIfInside(ref Vector3 segmentPosition, float segmentRadius, Vector3 segmentOffset)
+ {
+ // Checking if segment is inside box shape of terrain
+ if (segmentPosition.x + segmentRadius < TerrainComponent.GetPosition().x - segmentRadius || segmentPosition.x > TerrainComponent.GetPosition().x + TerrainComponent.terrainData.size.x ||
+ segmentPosition.z + segmentRadius < TerrainComponent.GetPosition().z - segmentRadius || segmentPosition.z > TerrainComponent.GetPosition().z + TerrainComponent.terrainData.size.z)
+ return false;
+
+ Vector3 offsettedPosition = segmentPosition + segmentOffset;
+ Vector3 terrPoint = offsettedPosition;
+ terrPoint.y = TerrCollider.transform.position.y + TerrainComponent.SampleHeight(offsettedPosition);
+
+
+ float hitToPointDist = (offsettedPosition - terrPoint).magnitude;
+ float underMul = 1f;
+
+ if (offsettedPosition.y < terrPoint.y)
+ {
+ underMul = 4f;
+ }
+ else
+ if (offsettedPosition.y + segmentRadius * 2f < terrPoint.y)
+ {
+ underMul = 8f;
+ }
+
+ if (hitToPointDist < segmentRadius * underMul)
+ {
+ Vector3 toNormal = terrPoint - offsettedPosition;
+
+ Vector3 pushNormal;
+ if (underMul > 1f) pushNormal = toNormal + toNormal.normalized * segmentRadius; else pushNormal = toNormal - toNormal.normalized * segmentRadius;
+ segmentPosition = segmentPosition + pushNormal;
+
+ return true;
+ }
+
+ return false;
+ }
+
+ public static void PushOutFromTerrain(TerrainCollider terrainCollider, float segmentRadius, ref Vector3 point)
+ {
+ Terrain terrain = terrainCollider.GetComponent();
+
+ Vector3 rayOrigin = point;
+ rayOrigin.y = terrainCollider.transform.position.y + terrain.SampleHeight(point) + segmentRadius;
+
+ Ray ray = new Ray(rayOrigin, Vector3.down);
+
+ RaycastHit hit;
+ if (terrainCollider.Raycast(ray, out hit, segmentRadius * 2f))
+ {
+ float hitToPointDist = (point - hit.point).magnitude;
+
+ float underMul = 1f;
+ if (hit.point.y > point.y + segmentRadius * 0.9f)
+ {
+ underMul = 8f;
+ }
+ else
+ if (hit.point.y > point.y)
+ {
+ underMul = 4f;
+ }
+
+ if (hitToPointDist < segmentRadius * underMul)
+ {
+ Vector3 toNormal = hit.point - point;
+ Vector3 pushNormal;
+
+ if (underMul > 1f) pushNormal = toNormal + toNormal.normalized * segmentRadius; else pushNormal = toNormal - toNormal.normalized * segmentRadius;
+ point = point + pushNormal;
+ }
+ }
+ }
+ }
+}
diff --git a/Assets/FImpossible Creations/Plugins - Shared/Physics/FImp_ColliderData_Terrain.cs.meta b/Assets/FImpossible Creations/Plugins - Shared/Physics/FImp_ColliderData_Terrain.cs.meta
new file mode 100644
index 000000000..70937aa6d
--- /dev/null
+++ b/Assets/FImpossible Creations/Plugins - Shared/Physics/FImp_ColliderData_Terrain.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: f194fa206da32744ab55e530d336095a
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {fileID: 2800000, guid: 4ba1f7a7d53fd274c98bdce0c9242640, type: 3}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Shared Tools/Editor Tools/Inspector And Scene Tools/FEditor_Handles.cs b/Assets/FImpossible Creations/Shared Tools/Editor Tools/Inspector And Scene Tools/FEditor_Handles.cs
index a7706cf3b..6ad5e980a 100644
--- a/Assets/FImpossible Creations/Shared Tools/Editor Tools/Inspector And Scene Tools/FEditor_Handles.cs
+++ b/Assets/FImpossible Creations/Shared Tools/Editor Tools/Inspector And Scene Tools/FEditor_Handles.cs
@@ -13,16 +13,16 @@ public static class FEditor_TransformHandles
/// [To be executed in OnSceneGUI()]
/// Drawing sphere handle in scene view with controll ability
///
- public static Vector3 DrawAndSetPositionForHandle( Vector3 position, Transform rootReference )
+ public static Vector3 DrawAndSetPositionForHandle(Vector3 position, Transform rootReference)
{
EditorGUI.BeginChangeCheck();
Handles.color = Color.green;
- Quaternion rotation = ( UnityEditor.Tools.pivotRotation != UnityEditor.PivotRotation.Local ) ? Quaternion.identity : rootReference.rotation;
+ Quaternion rotation = (UnityEditor.Tools.pivotRotation != UnityEditor.PivotRotation.Local) ? Quaternion.identity : rootReference.rotation;
- float size = HandleUtility.GetHandleSize( position ) * 0.125f;
- Handles.SphereHandleCap( 0, position, rotation, size, UnityEngine.EventType.Repaint );
- Vector3 pos = Handles.PositionHandle( position, rotation );
+ float size = HandleUtility.GetHandleSize(position) * 0.125f;
+ Handles.SphereHandleCap(0, position, rotation, size, UnityEngine.EventType.Repaint);
+ Vector3 pos = Handles.PositionHandle(position, rotation);
return pos;
}
@@ -32,17 +32,17 @@ public static class FEditor_TransformHandles
/// Drawing sphere handle in scene view without option to controll it but clickable
/// Returns true if mouse clicked on handle
///
- public static bool DrawSphereHandle( Vector3 position, string text = "" )
+ public static bool DrawSphereHandle(Vector3 position, string text = "")
{
bool clicked = false;
- if( Event.current.button != 1 )
+ if (Event.current.button != 1)
{
Handles.color = Color.white;
- float size = HandleUtility.GetHandleSize( position ) * 0.2f;
+ float size = HandleUtility.GetHandleSize(position) * 0.2f;
- if( Handles.Button( position, Quaternion.identity, size, size, Handles.SphereHandleCap ) )
+ if (Handles.Button(position, Quaternion.identity, size, size, Handles.SphereHandleCap))
{
clicked = true;
InternalEditorUtility.RepaintAllViews();
@@ -50,17 +50,17 @@ public static class FEditor_TransformHandles
Handles.BeginGUI();
- Vector2 labelSize = new Vector2( EditorGUIUtility.singleLineHeight * 2, EditorGUIUtility.singleLineHeight );
- Vector2 labelPos = HandleUtility.WorldToGUIPoint( position );
+ Vector2 labelSize = new Vector2(EditorGUIUtility.singleLineHeight * 2, EditorGUIUtility.singleLineHeight);
+ Vector2 labelPos = HandleUtility.WorldToGUIPoint(position);
labelPos.y -= labelSize.y / 2;
labelPos.x -= labelSize.x / 2;
- GUILayout.BeginArea( new Rect( labelPos, labelSize ) );
+ GUILayout.BeginArea(new Rect(labelPos, labelSize));
GUIStyle style = new GUIStyle();
style.normal.textColor = Color.black;
style.alignment = UnityEngine.TextAnchor.MiddleCenter;
- GUILayout.Label( new GUIContent( text ), style );
+ GUILayout.Label(new GUIContent(text), style);
GUILayout.EndArea();
Handles.EndGUI();
@@ -72,70 +72,45 @@ public static class FEditor_TransformHandles
- public static Quaternion RotationHandle( Quaternion rotation, Vector3 position, float size = 1f, bool worldScale = false )
+ public static Quaternion RotationHandle(Quaternion rotation, Vector3 position, float size = 1f, bool worldScale = false)
{
float handleSize = size;
- if( worldScale ) handleSize = HandleUtility.GetHandleSize( position ) * size;
+ if (worldScale) handleSize = HandleUtility.GetHandleSize(position) * size;
Color color = Handles.color;
Handles.color = Handles.xAxisColor;
- rotation = Handles.Disc( rotation, position, rotation * Vector3.right, handleSize, true, 1f );
+ rotation = Handles.Disc(rotation, position, rotation * Vector3.right, handleSize, true, 1f);
Handles.color = Handles.yAxisColor;
- rotation = Handles.Disc( rotation, position, rotation * Vector3.up, handleSize, true, 1f );
+ rotation = Handles.Disc(rotation, position, rotation * Vector3.up, handleSize, true, 1f);
Handles.color = Handles.zAxisColor;
- rotation = Handles.Disc( rotation, position, rotation * Vector3.forward, handleSize, true, 1f );
+ rotation = Handles.Disc(rotation, position, rotation * Vector3.forward, handleSize, true, 1f);
Handles.color = Handles.centerColor;
- rotation = Handles.Disc( rotation, position, Camera.current.transform.forward, handleSize * 1.1f, false, 0f );
- rotation = Handles.FreeRotateHandle( rotation, position, handleSize );
+ rotation = Handles.Disc(rotation, position, Camera.current.transform.forward, handleSize * 1.1f, false, 0f);
+ rotation = Handles.FreeRotateHandle(rotation, position, handleSize);
Handles.color = color;
return rotation;
}
- public static Vector3 ScaleHandle( Vector3 scale, Vector3 position, Quaternion rotation, float size, bool scaleAll = false, bool worldScale = false, bool drawX = true, bool drawY = true, bool drawZ = true, bool allowNegative = false )
+ public static Vector3 ScaleHandle(Vector3 scale, Vector3 position, Quaternion rotation, float size, bool scaleAll = false, bool worldScale = false)
{
float handleSize = size;
- if( worldScale ) handleSize = HandleUtility.GetHandleSize( position ) * size;
+ if (worldScale) handleSize = HandleUtility.GetHandleSize(position) * size;
- Vector3 preScale = scale;
-
- if( !scaleAll )
+ if (!scaleAll)
{
- if( drawX )
- {
- Handles.color = Handles.xAxisColor;
- scale.x = Handles.ScaleSlider( scale.x, position, rotation * Vector3.right, rotation, handleSize, 0.001f );
-
- if (!allowNegative) if( Mathf.Sign( scale.x ) != Mathf.Sign( preScale.x ) ) scale.x = preScale.x * handleSize * 0.001f;
- }
-
- if( drawY )
- {
- Handles.color = Handles.yAxisColor;
- scale.y = Handles.ScaleSlider( scale.y, position, rotation * Vector3.up, rotation, handleSize, 0.001f );
-
- if( !allowNegative ) if( Mathf.Sign( scale.y ) != Mathf.Sign( preScale.y ) ) scale.y = preScale.y * handleSize * 0.001f;
- }
-
- if( drawZ )
- {
- Handles.color = Handles.zAxisColor;
- scale.z = Handles.ScaleSlider( scale.z, position, rotation * Vector3.forward, rotation, handleSize, 0.001f );
-
- if( !allowNegative ) if( Mathf.Sign( scale.z ) != Mathf.Sign( preScale.z ) ) scale.z = preScale.z * handleSize * 0.001f;
- }
+ Handles.color = Handles.xAxisColor;
+ scale.x = Handles.ScaleSlider(scale.x, position, rotation * Vector3.right, rotation, handleSize, 0.001f);
+ Handles.color = Handles.yAxisColor;
+ scale.y = Handles.ScaleSlider(scale.y, position, rotation * Vector3.up, rotation, handleSize, 0.001f);
+ Handles.color = Handles.zAxisColor;
+ scale.z = Handles.ScaleSlider(scale.z, position, rotation * Vector3.forward, rotation, handleSize, 0.001f);
}
Handles.color = Handles.centerColor;
EditorGUI.BeginChangeCheck();
- float num1 = Handles.ScaleValueHandle( scale.x, position, rotation, handleSize, Handles.CubeHandleCap, 0.001f );
+ float num1 = Handles.ScaleValueHandle(scale.x, position, rotation, handleSize, Handles.CubeHandleCap, 0.001f);
- if( Mathf.Sign( num1 ) != Mathf.Sign( preScale.x ) )
- {
- num1 = preScale.x * handleSize * 0.001f;
- if( !allowNegative ) if( Mathf.Abs( num1 ) < 0.001f ) num1 = 0.001f * Mathf.Sign( preScale.x );
- }
-
- if( EditorGUI.EndChangeCheck() )
+ if (EditorGUI.EndChangeCheck())
{
float num2 = num1 / scale.x;
scale.x = num1;
@@ -146,24 +121,24 @@ public static class FEditor_TransformHandles
return scale;
}
- public static Vector3 PositionHandle( Vector3 position, Quaternion rotation, float size = 1f, bool worldScale = false, bool freeHandle = true, bool colorize = true )
+ public static Vector3 PositionHandle(Vector3 position, Quaternion rotation, float size = 1f, bool worldScale = false, bool freeHandle = true, bool colorize = true)
{
float handleSize = size;
- if( worldScale ) handleSize = HandleUtility.GetHandleSize( position ) * size;
+ if (worldScale) handleSize = HandleUtility.GetHandleSize(position) * size;
Color color = Handles.color;
- if( colorize ) Handles.color = Handles.xAxisColor;
- position = Handles.Slider( position, rotation * Vector3.right, handleSize, Handles.ArrowHandleCap, 0.001f );
- if( colorize ) Handles.color = Handles.yAxisColor;
- position = Handles.Slider( position, rotation * Vector3.up, handleSize, Handles.ArrowHandleCap, 0.001f );
- if( colorize ) Handles.color = Handles.zAxisColor;
- position = Handles.Slider( position, rotation * Vector3.forward, handleSize, Handles.ArrowHandleCap, 0.001f );
+ if (colorize) Handles.color = Handles.xAxisColor;
+ position = Handles.Slider(position, rotation * Vector3.right, handleSize, Handles.ArrowHandleCap, 0.001f);
+ if (colorize) Handles.color = Handles.yAxisColor;
+ position = Handles.Slider(position, rotation * Vector3.up, handleSize, Handles.ArrowHandleCap, 0.001f);
+ if (colorize) Handles.color = Handles.zAxisColor;
+ position = Handles.Slider(position, rotation * Vector3.forward, handleSize, Handles.ArrowHandleCap, 0.001f);
- if( freeHandle )
+ if (freeHandle)
{
Handles.color = Handles.centerColor;
- position = Handles.FreeMoveHandle( position, handleSize * 0.15f, Vector3.one * 0.001f, Handles.RectangleHandleCap );
+ position = Handles.FreeMoveHandle(position, rotation, handleSize * 0.15f, Vector3.one * 0.001f, Handles.RectangleHandleCap);
}
Handles.color = color;
diff --git a/Assets/FImpossible Creations/Shared Tools/Editor Tools/Property Attributes/FPD_MiscAttributes.cs b/Assets/FImpossible Creations/Shared Tools/Editor Tools/Property Attributes/FPD_MiscAttributes.cs
new file mode 100644
index 000000000..dfb3f7ba4
--- /dev/null
+++ b/Assets/FImpossible Creations/Shared Tools/Editor Tools/Property Attributes/FPD_MiscAttributes.cs
@@ -0,0 +1,84 @@
+using UnityEngine;
+
+
+public class FPD_OverridableFloatAttribute : PropertyAttribute
+{
+ public string BoolVarName;
+ public string TargetVarName;
+ public int LabelWidth;
+
+ public FPD_OverridableFloatAttribute(string boolVariableName, string targetVariableName, int labelWidth = 90)
+ {
+ BoolVarName = boolVariableName;
+ TargetVarName = targetVariableName;
+ LabelWidth = labelWidth;
+ }
+}
+
+
+// -------------------------- Next F Property Drawer -------------------------- \\
+
+
+public class BackgroundColorAttribute : PropertyAttribute
+{
+ public float r;
+ public float g;
+ public float b;
+ public float a;
+
+ public BackgroundColorAttribute()
+ {
+ r = g = b = a = 1f;
+ }
+
+ public BackgroundColorAttribute(float aR, float aG, float aB, float aA)
+ {
+ r = aR;
+ g = aG;
+ b = aB;
+ a = aA;
+ }
+
+ public Color Color { get { return new Color(r, g, b, a); } }
+}
+
+
+// -------------------------- Next F Property Drawer -------------------------- \\
+
+public class FPD_WidthAttribute : PropertyAttribute
+{
+ public float LabelWidth;
+
+ public FPD_WidthAttribute(int labelWidth)
+ {
+ LabelWidth = labelWidth;
+ }
+}
+
+// -------------------------- Next F Property Drawer -------------------------- \\
+
+public class FPD_IndentAttribute : PropertyAttribute
+{
+ public int IndentCount = 1;
+ public int LabelsWidth = 0;
+ public int SpaceAfter = 0;
+
+ public FPD_IndentAttribute(int indent = 1, int labelsWidth = 0, int spaceAfter = 0)
+ {
+ IndentCount = indent;
+ LabelsWidth = labelsWidth;
+ SpaceAfter = spaceAfter;
+ }
+}
+
+// -------------------------- Next F Property Drawer -------------------------- \\
+
+public class FPD_HorizontalLineAttribute : PropertyAttribute
+{
+ public Color color;
+
+ public FPD_HorizontalLineAttribute(float r = 0.55f, float g = 0.55f, float b = 0.55f, float a = 0.7f)
+ {
+ color = new Color(r, g, b, a);
+ }
+}
\ No newline at end of file
diff --git a/Assets/FImpossible Creations/Shared Tools/Editor Tools/Property Attributes/FPD_MiscAttributes.cs.meta b/Assets/FImpossible Creations/Shared Tools/Editor Tools/Property Attributes/FPD_MiscAttributes.cs.meta
new file mode 100644
index 000000000..8d55a815a
--- /dev/null
+++ b/Assets/FImpossible Creations/Shared Tools/Editor Tools/Property Attributes/FPD_MiscAttributes.cs.meta
@@ -0,0 +1,13 @@
+fileFormatVersion: 2
+guid: dc27395774a5c5b49b7a62f316a65486
+timeCreated: 1554395276
+licenseType: Store
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Shared Tools/Editor/Editor Tools.meta b/Assets/FImpossible Creations/Shared Tools/Editor/Editor Tools.meta
new file mode 100644
index 000000000..77ec5084a
--- /dev/null
+++ b/Assets/FImpossible Creations/Shared Tools/Editor/Editor Tools.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 33dc52977f400d3419d2774a68a798c1
+folderAsset: yes
+timeCreated: 1602707605
+licenseType: Store
+DefaultImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Shared Tools/Editor/Editor Tools/FPropDrawers_DrawScriptable.cs b/Assets/FImpossible Creations/Shared Tools/Editor/Editor Tools/FPropDrawers_DrawScriptable.cs
new file mode 100644
index 000000000..ba8f2ecc3
--- /dev/null
+++ b/Assets/FImpossible Creations/Shared Tools/Editor/Editor Tools/FPropDrawers_DrawScriptable.cs
@@ -0,0 +1,105 @@
+using UnityEditor;
+using UnityEngine;
+
+namespace FIMSpace.FEditor
+{
+ [CustomPropertyDrawer(typeof(FPropDrawers_DrawScriptableAttribute))]
+ public class FPropDrawers_DrawScriptableDrawer : PropertyDrawer
+ {
+ bool showProperty = false;
+ float DrawerHeight = 0;
+ string button = "►";
+
+ // Draw the property inside the given rect
+ public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
+ {
+ var e = Editor.CreateEditor(property.objectReferenceValue);
+ var indent = EditorGUI.indentLevel;
+ Rect temp = new Rect(position.x, position.y, 20, 16);
+
+ if (GUI.Button(temp, button))
+ if (showProperty)
+ {
+ showProperty = false;
+ button = "►";
+ }
+ else
+ {
+ showProperty = true;
+ button = "▼";
+ }
+
+ DrawerHeight = 0;
+ position.height = 16;
+ position.x += 20;
+ position.width -= 20;
+ EditorGUI.PropertyField(position, property);
+ position.width += 20;
+ position.x -= 20;
+ position.y += 20;
+
+ if (!showProperty) return;
+ if (e != null)
+ {
+ position.x += 20;
+ position.width -= 40;
+
+ var so = e.serializedObject;
+ so.Update();
+
+ var prop = so.GetIterator();
+ prop.NextVisible(true);
+
+ int depthChilden = 0;
+ bool showChilden = false;
+
+ while (prop.NextVisible(true))
+ {
+ if (prop.depth == 0) { showChilden = false; depthChilden = 0; }
+
+ if (showChilden && prop.depth > depthChilden)
+ {
+ continue;
+ }
+
+ position.height = 16;
+ EditorGUI.indentLevel = indent + prop.depth;
+ if (EditorGUI.PropertyField(position, prop))
+ {
+ showChilden = false;
+ }
+ else
+ {
+ showChilden = true;
+ depthChilden = prop.depth;
+ }
+
+ position.y += 20;
+ SetDrawerHeight(20);
+ }
+
+ if (GUI.changed)
+ {
+ so.ApplyModifiedProperties();
+ }
+ }
+ }
+
+ public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
+ {
+ float height = base.GetPropertyHeight(property, label);
+ height += DrawerHeight;
+ return height;
+ }
+
+ void SetDrawerHeight(float height)
+ {
+ DrawerHeight += height;
+ }
+ }
+
+ public class FPropDrawers_DrawScriptableAttribute : PropertyAttribute
+ {
+
+ }
+}
\ No newline at end of file
diff --git a/Assets/FImpossible Creations/Shared Tools/Editor/Editor Tools/FPropDrawers_DrawScriptable.cs.meta b/Assets/FImpossible Creations/Shared Tools/Editor/Editor Tools/FPropDrawers_DrawScriptable.cs.meta
new file mode 100644
index 000000000..744f1009e
--- /dev/null
+++ b/Assets/FImpossible Creations/Shared Tools/Editor/Editor Tools/FPropDrawers_DrawScriptable.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 517ef6dd0c387d848abb63a8ed55882a
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Shared Tools/Editor/Property Drawers/FPD_MiscDrawers.cs b/Assets/FImpossible Creations/Shared Tools/Editor/Property Drawers/FPD_MiscDrawers.cs
new file mode 100644
index 000000000..6ae9070ef
--- /dev/null
+++ b/Assets/FImpossible Creations/Shared Tools/Editor/Property Drawers/FPD_MiscDrawers.cs
@@ -0,0 +1,107 @@
+using UnityEditor;
+using UnityEngine;
+
+namespace FIMSpace.FEditor
+{
+ [CustomPropertyDrawer(typeof(FPD_OverridableFloatAttribute))]
+ public class FPD_OverridableFloat : PropertyDrawer
+ {
+ FPD_OverridableFloatAttribute Attribute { get { return ((FPD_OverridableFloatAttribute)base.attribute); } }
+
+ public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
+ {
+ var boolProp = property.serializedObject.FindProperty(Attribute.BoolVarName);
+ var valProp = property.serializedObject.FindProperty(Attribute.TargetVarName);
+
+ Color disabled = new Color(0.8f, 0.8f, 0.8f, 0.6f);
+ Color preCol = GUI.color;
+ if (!boolProp.boolValue) GUI.color = disabled; else GUI.color = preCol;
+
+ EditorGUI.BeginProperty(position, label, property);
+
+ var boolRect = new Rect(position.x, position.y, Attribute.LabelWidth + 15f, position.height);
+
+ EditorGUIUtility.labelWidth = Attribute.LabelWidth;
+ EditorGUI.PrefixLabel(position, label);
+ EditorGUI.PropertyField(boolRect, boolProp);
+
+ EditorGUIUtility.labelWidth = 14;
+ var valRect = new Rect(position.x + Attribute.LabelWidth + 15, position.y, position.width - (Attribute.LabelWidth + 15), position.height);
+ EditorGUI.PropertyField(valRect, valProp, new GUIContent(" "));
+
+ EditorGUIUtility.labelWidth = 0;
+
+ GUI.color = preCol;
+ EditorGUI.EndProperty();
+ }
+ }
+
+
+
+ // -------------------------- Next F Property Drawer -------------------------- \\
+
+
+
+ [CustomPropertyDrawer(typeof(BackgroundColorAttribute))]
+ public class BackgroundColorDecorator : DecoratorDrawer
+ {
+ BackgroundColorAttribute Attribute { get { return ((BackgroundColorAttribute)base.attribute); } }
+ public override float GetHeight() { return 0; }
+
+ public override void OnGUI(Rect position)
+ {
+ GUI.backgroundColor = Attribute.Color;
+ }
+ }
+
+
+ // -------------------------- Next F Property Drawer -------------------------- \\
+
+
+ [CustomPropertyDrawer(typeof(FPD_WidthAttribute))]
+ public class FPD_Width : PropertyDrawer
+ {
+ FPD_WidthAttribute Attribute { get { return ((FPD_WidthAttribute)base.attribute); } }
+
+ public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
+ {
+ EditorGUIUtility.labelWidth = Attribute.LabelWidth;
+ EditorGUI.PrefixLabel(position, label);
+ EditorGUI.PropertyField(position, property);
+ EditorGUIUtility.labelWidth = 0;
+ }
+ }
+
+ // -------------------------- Next F Property Drawer -------------------------- \\
+
+ [CustomPropertyDrawer(typeof(FPD_IndentAttribute))]
+ public class FPD_Indent : PropertyDrawer
+ {
+ FPD_IndentAttribute Attribute { get { return ((FPD_IndentAttribute)base.attribute); } }
+
+ public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
+ {
+ EditorGUIUtility.labelWidth = Attribute.LabelsWidth;
+ for (int i = 0; i < Attribute.IndentCount; i++) EditorGUI.indentLevel++;
+ EditorGUI.PrefixLabel(position, label);
+ EditorGUI.PropertyField(position, property);
+ for (int i = 0; i < Attribute.IndentCount; i++) EditorGUI.indentLevel--;
+ EditorGUIUtility.labelWidth = 0;
+ GUILayout.Space(Attribute.SpaceAfter);
+ }
+ }
+
+ // -------------------------- Next F Property Drawer -------------------------- \\
+
+ [CustomPropertyDrawer(typeof(FPD_HorizontalLineAttribute))]
+ public class FPD_HorizontalLine : PropertyDrawer
+ {
+ FPD_HorizontalLineAttribute Attribute { get { return ((FPD_HorizontalLineAttribute)base.attribute); } }
+
+ public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
+ {
+ FGUI_Inspector.DrawUILine(Attribute.color);
+ }
+ }
+}
+
diff --git a/Assets/FImpossible Creations/Shared Tools/Editor/Property Drawers/FPD_MiscDrawers.cs.meta b/Assets/FImpossible Creations/Shared Tools/Editor/Property Drawers/FPD_MiscDrawers.cs.meta
new file mode 100644
index 000000000..1712c41d7
--- /dev/null
+++ b/Assets/FImpossible Creations/Shared Tools/Editor/Property Drawers/FPD_MiscDrawers.cs.meta
@@ -0,0 +1,13 @@
+fileFormatVersion: 2
+guid: b65c850de06f12c4aa781383b5a038cd
+timeCreated: 1543091521
+licenseType: Store
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FImpossible Creations/Shared Tools/GUI Helpers/FGUI_Inspector.cs b/Assets/FImpossible Creations/Shared Tools/GUI Helpers/FGUI_Inspector.cs
index 2fabdbaaa..a7609a347 100644
--- a/Assets/FImpossible Creations/Shared Tools/GUI Helpers/FGUI_Inspector.cs
+++ b/Assets/FImpossible Creations/Shared Tools/GUI Helpers/FGUI_Inspector.cs
@@ -21,29 +21,6 @@ namespace FIMSpace.FEditor
public static Object LastObjSelected;
public static GameObject LastGameObjectSelected;
-
- /// Since remembering in which EditorGUI, EditorGUILayout, or EditorGUIUtility, or GUILayoutUtility ahhh... in which if these classes you will find the desired variable is so confusing ¯\_(ツ)_/¯ each time when trying finding it, ending in googling for forums post with it
- public static float InspectorViewWidth()
- {
-#if UNITY_EDITOR
- return EditorGUIUtility.currentViewWidth;
-#else
- return 0f;
-#endif
-
- }
-
- public static bool IsRightMouseButton()
- {
- if (UnityEngine.Event.current == null) return false;
-
- if (UnityEngine.Event.current.type == UnityEngine.EventType.Used)
- if (UnityEngine.Event.current.button == 1 || UnityEngine.Event.current.control)
- return true;
-
- return false;
- }
-
public static void HeaderBox(ref bool foldout, string title, bool frame, Texture icon = null, int height = 20, int iconsSize = 19, bool big = false)
{
if (frame) EditorGUILayout.BeginHorizontal(FGUI_Resources.HeaderBoxStyle); else EditorGUILayout.BeginHorizontal();
@@ -201,7 +178,7 @@ namespace FIMSpace.FEditor
public static GUIStyle Style(Color bgColor, int off = -1)
{
GUIStyle newStyle = new GUIStyle(GUI.skin.box);
- if (off < 0) { if (Screen.dpi != 120) newStyle.border = new RectOffset(off, off, off, off); else if (!displayedDPIWarning) { /*Debug.Log("[HEY! UNITY DEVELOPER!] It seems you have setted up incorrect DPI settings for unity editor. Check Unity.exe -> Properties -> Compatibility -> Change DPI Settings -> Replace Scaling -> System / System (Upgraded) And restart Unity Editor.");*/ displayedDPIWarning = true; } }
+ if (off < 0) { if (Screen.dpi != 120) newStyle.border = new RectOffset(off, off, off, off); else if (!displayedDPIWarning) { Debug.Log("[HEY! UNITY DEVELOPER!] It seems you have setted up incorrect DPI settings for unity editor. Check Unity.exe -> Properties -> Compatibility -> Change DPI Settings -> Replace Scaling -> System / System (Upgraded) And restart Unity Editor."); displayedDPIWarning = true; } }
else newStyle.border = new RectOffset(off, off, off, off);
Color[] solidColor = new Color[1] { bgColor };
diff --git a/Assets/FImpossible Creations/Shared Tools/GUI Helpers/FGUI_Resources.cs b/Assets/FImpossible Creations/Shared Tools/GUI Helpers/FGUI_Resources.cs
index c75934730..a14a46c3c 100644
--- a/Assets/FImpossible Creations/Shared Tools/GUI Helpers/FGUI_Resources.cs
+++ b/Assets/FImpossible Creations/Shared Tools/GUI Helpers/FGUI_Resources.cs
@@ -12,75 +12,50 @@ namespace FIMSpace.FEditor
public static GUIStyle HeaderBoxStyle { get { if (__headerBoxStyle != null) return __headerBoxStyle; __headerBoxStyle = new GUIStyle(EditorStyles.helpBox); Texture2D bg = Resources.Load("Fimp/Backgrounds/FHelpBox"); __headerBoxStyle.normal.background = bg; __headerBoxStyle.border = new RectOffset(6, 6, 6, 6); return __headerBoxStyle; } }
private static GUIStyle __headerBoxStyle = null;
- private static GUIStyle GenerateButtonStyle(string bg, string hover, string press, int lr = 3, int ud = 2)
+ private static GUIStyle GenerateButtonStyle( string bg, string hover, string press, int lr = 3, int ud = 2 )
{
- var s = new GUIStyle(EditorStyles.label);
+ var s = new GUIStyle( EditorStyles.label );
s.fixedHeight = 0;
s.imagePosition = ImagePosition.ImageLeft;
s.alignment = TextAnchor.MiddleCenter;
- s.border = new RectOffset(lr, lr, ud, ud);
- s.padding = new RectOffset(1, 1, 3, 3);
- s.margin = new RectOffset(0, 0, 0, 0);
- s.normal.background = Resources.Load(bg);
- s.hover.background = Resources.Load(hover);
+ s.border = new RectOffset( lr, lr, ud, ud );
+ s.padding = new RectOffset( 1, 1, 3, 3 );
+ s.margin = new RectOffset( 0, 0, 0, 0 );
+ s.normal.background = Resources.Load( bg );
+ s.hover.background = Resources.Load( hover );
s.focused.background = s.hover.background;
- s.active.background = Resources.Load(press);
+ s.active.background = Resources.Load( press );
return s;
}
- public static GUIStyle BUTTON1Style
- {
- get
+ public static GUIStyle BUTTON2Style
+ {
+ get
{
- if (__bt2s != null) return __bt2s;
-
- __bt2s = new GUIStyle(EditorStyles.label);
+ __bt2s = new GUIStyle( EditorStyles.label );
__bt2s.alignment = TextAnchor.MiddleCenter;
__bt2s.fixedHeight = 0;
- __bt2s.normal.background = Resources.Load("Fimp/Backgrounds/FBG1");
+ __bt2s.normal.background = Resources.Load( "Fimp/Backgrounds/FBG1" );
__bt2s.onNormal.background = __bt2s.normal.background;
- __bt2s.active.background = Resources.Load("Fimp/Backgrounds/FBG1P");
+ __bt2s.active.background = Resources.Load( "Fimp/Backgrounds/FBG1P" );
__bt2s.onActive.background = __bt2s.active.background;
- __bt2s.hover.background = Resources.Load("Fimp/Backgrounds/FBG1H");
+ __bt2s.hover.background = Resources.Load( "Fimp/Backgrounds/FBG1H" );
__bt2s.onHover.background = __bt2s.hover.background;
- __bt2s.border = new RectOffset(2, 2, 2, 2);
- __bt2s.contentOffset = new Vector2(0, 0);
+ __bt2s.border = new RectOffset( 1, 1, 1, 1 );
+ __bt2s.contentOffset = new Vector2( 0, 1 );
return __bt2s;
- }
- }
-
-
- public static GUIStyle BUTTON2Style
- {
- get
- {
- if (__bt2s != null) return __bt2s;
-
- __bt2s = new GUIStyle(EditorStyles.label);
- __bt2s.alignment = TextAnchor.MiddleCenter;
-
- __bt2s.fixedHeight = 0;
- __bt2s.normal.background = Resources.Load("Fimp/Backgrounds/FBG1");
- __bt2s.onNormal.background = __bt2s.normal.background;
- __bt2s.active.background = Resources.Load("Fimp/Backgrounds/FBG1P");
- __bt2s.onActive.background = __bt2s.active.background;
- __bt2s.hover.background = Resources.Load("Fimp/Backgrounds/FBG1H");
- __bt2s.onHover.background = __bt2s.hover.background;
- __bt2s.border = new RectOffset(1, 1, 1, 1);
- __bt2s.contentOffset = new Vector2(0, 1);
- return __bt2s;
- }
+ }
}
public static GUIStyle BUTTON2StyleU
{
get
{
- if (__bt2su != null) return __bt2su;
- __bt2su = new GUIStyle(BUTTON2Style);
+ if( __bt2su != null ) return __bt2su;
+ __bt2su = new GUIStyle( BUTTON2Style );
__bt2su.imagePosition = ImagePosition.ImageAbove;
- __bt2su.contentOffset = new Vector2(0, 2);
+ __bt2su.contentOffset = new Vector2(0,2);
return __bt2su;
}
}
@@ -89,29 +64,17 @@ namespace FIMSpace.FEditor
{
get
{
- if (__bt3s != null) return __bt3s; __bt3s = new GUIStyle(EditorStyles.label);
+ if( __bt3s != null ) return __bt3s; __bt3s = new GUIStyle( EditorStyles.label );
__bt3s.alignment = TextAnchor.MiddleCenter;
__bt3s.fixedHeight = 0;
- __bt3s.normal.background = Resources.Load("Fimp/Backgrounds/FBG2");
- __bt3s.border = new RectOffset(0, 0, 0, 0);
- __bt3s.contentOffset = new Vector2(0, 0);
+ __bt3s.normal.background = Resources.Load( "Fimp/Backgrounds/FBG2" );
+ __bt3s.border = new RectOffset( 0, 0, 0, 0 );
+ __bt3s.contentOffset = new Vector2( 0, 0 );
return __bt3s;
}
}
- public static GUIStyle BUTTONStyleU
- {
- get
- {
- if (__bt2su != null) return __bt2su;
- __bt2su = new GUIStyle(ButtonStyle);
- __bt2su.imagePosition = ImagePosition.ImageAbove;
- __bt2su.contentOffset = new Vector2(0, 1);
- return __bt2su;
- }
- }
-
private static GUIStyle __bt2s = null;
private static GUIStyle __bt2su = null;
@@ -138,14 +101,14 @@ namespace FIMSpace.FEditor
{
get
{
- if (__buttStyle != null) return __buttStyle;
- __buttStyle = GenerateButtonStyle("Fimp/Backgrounds/Fbutton", "Fimp/Backgrounds/FbuttonHover", "Fimp/Backgrounds/FbuttonPress");
+ if( __buttStyle != null ) return __buttStyle;
+ __buttStyle = GenerateButtonStyle( "Fimp/Backgrounds/Fbutton", "Fimp/Backgrounds/FbuttonHover", "Fimp/Backgrounds/FbuttonPress");
return __buttStyle;
}
}
private static GUIStyle __buttStyle = null;
- public static GUIStyle ButtonStyleR { get { if (__buttStyler != null) return __buttStyler; __buttStyler = new GUIStyle(ButtonStyle); __buttStyler.richText = true; return __buttStyler; } }
+ public static GUIStyle ButtonStyleR { get { if( __buttStyler != null ) return __buttStyler; __buttStyler = new GUIStyle( ButtonStyle ); __buttStyler.richText = true; return __buttStyler; } }
private static GUIStyle __buttStyler = null;
/// Text Styles ----------------------------------------------------
@@ -357,16 +320,16 @@ namespace FIMSpace.FEditor
public static Texture2D Tex_Prepare { get { if (__texPrep != null) return __texPrep; __texPrep = Resources.Load("Fimp/Small Icons/FPrepare"); return __texPrep; } }
private static Texture2D __texPrep = null;
- public static Texture2D Tex_Anchor { get { if (__texAnchor != null) return __texAnchor; __texAnchor = Resources.Load("Fimp/Small Icons/Anchor"); return __texAnchor; } }
+ public static Texture2D Tex_Anchor { get { if( __texAnchor != null ) return __texAnchor; __texAnchor = Resources.Load( "Fimp/Small Icons/Anchor" ); return __texAnchor; } }
private static Texture2D __texAnchor = null;
- public static Texture2D Tex_FAnimator { get { if (__texFAnimator != null) return __texFAnimator; __texFAnimator = Resources.Load("Fimp/Small Icons/Fanimator"); return __texFAnimator; } }
+ public static Texture2D Tex_FAnimator { get { if( __texFAnimator != null ) return __texFAnimator; __texFAnimator = Resources.Load( "Fimp/Small Icons/Fanimator" ); return __texFAnimator; } }
private static Texture2D __texFAnimator = null;
- public static Texture2D Tex_FCorrect { get { if (__texFCorrect != null) return __texFCorrect; __texFCorrect = Resources.Load("Fimp/Small Icons/FCorrect"); return __texFCorrect; } }
+ public static Texture2D Tex_FCorrect { get { if( __texFCorrect != null ) return __texFCorrect; __texFCorrect = Resources.Load( "Fimp/Small Icons/FCorrect" ); return __texFCorrect; } }
private static Texture2D __texFCorrect = null;
- public static Texture2D Tex_Symmetry { get { if (__texSymm != null) return __texSymm; __texSymm = Resources.Load("Fimp/Small Icons/Symmetry"); return __texSymm; } }
+ public static Texture2D Tex_Symmetry { get { if( __texSymm != null ) return __texSymm; __texSymm = Resources.Load( "Fimp/Small Icons/Symmetry" ); return __texSymm; } }
private static Texture2D __texSymm = null;
diff --git a/Assets/Obi.meta b/Assets/Obi.meta
new file mode 100644
index 000000000..a1435212a
--- /dev/null
+++ b/Assets/Obi.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 36112b76e54ae47b48e48d646aee4ed0
+folderAsset: yes
+timeCreated: 1435850625
+licenseType: Store
+DefaultImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/CHANGELOG_rope.txt b/Assets/Obi/CHANGELOG_rope.txt
new file mode 100644
index 000000000..97384c8fa
--- /dev/null
+++ b/Assets/Obi/CHANGELOG_rope.txt
@@ -0,0 +1,552 @@
+# Change Log
+All notable changes to “Obi - Advanced ropes for Unity” will be documented in this file.
+
+## [7.1]
+
+### Added
+- ObiBone now exposes one particle group per bone in the hierarchy, allowing to easily use attachments.
+- New ObiBoneOverride component that allows to override curve-driven properties for a specific sub-hierarchy.
+- Solvers can now optionally enforce boundary limits, so that particles can't go outside those limits. This is often more convenient than manually placing invisible colliders for the same purpose.
+- Dynamic ObiParticleAttachments now have a "projection" boolean, when enabled it forces the rendered position/orientation of the attached particles to match that of the attachment location, even if the constraint doesn't fully converge. This is useful to avoid visual gaps under extreme conditions.
+- Actors now have a "mass scale" parameter, that multiplies the mass of all particles in the blueprinyt at the time of loading it into the solver. This is handy to create actors of different masses without the need to create a new blueprint.
+- ObiForceZones now have a "color" parameter, that can be used to change the color of particles entering the zone.
+
+### Changed
+- Improved performance for large amounts of static colliders: they're not processed at all during ObiSolver.Update().
+
+### Fixed
+- Null reference exception when using a ObiRopeExtrudedRenderer that doesn't reference a section asset.
+
+## [7.0.5]
+
+### Added
+- New pinhole constraint type and ObiPinhole component, that allows to constrain ropes to a point in space while allowing it to slide trough it. Supports two-way rigidbody coupling and can be motor driven.
+
+### Fixed
+- Erratic bend/twist constraint behavior when darboux vector is close to identity.
+- Crash when attempting to bake ObiRopeExtrudedRenderer paired with an ObiPathSmoother that uses a non-zero decimation factor.
+- IndexOutOfRangeError when having ropes using multiple different section assets and disabling all rope instances using one of them.
+- InvalidOperationException in Burst backend when having simulateWhenInvisible = false and solver not seen by any camera.
+
+## [7.0.4]
+
+### Fixed
+- Bug that caused inactive particles to still be rendered by ObiInstancedParticleRenderer.
+- Bug that preventing pin constraints' break threshold from working when using the Compute backend.
+
+## [7.0.3]
+
+### Added
+- Object layer support for all renderers.
+- New "Synchronous Fixed" solver synchronization mode, similar to Obi 6, offers tighter integration with rigidbody physics.
+- New "Tangled Ropes" sample scene.
+
+## [7.0.2]
+
+### Fixed
+- Solvers not placed at the scene origin would result in actors having incorrect motion blur in HDRP.
+- Fixed issue when disabling all solvers and colliders simultaneously: ipon re-enabling them, the colliders would be ignored.
+- Issue withe ElectricalSparks sample scene, ObiRopePrefabPlugger sample component may sometimes thorw an exception dependin on Unity's OnEnable call order.
+- Rope would sometimes disappear when using aerodynamic constraints with zero wind in Burst, due to a math.project returning NaN. Replaced with math.projectsafe.
+
+## [7.0.1]
+
+### Added
+- BakeMesh functionality to ObiRopeChainRenderer, you can now export baked chain meshes.
+- Render layer mask support to all rope renderers and particle renderers.
+
+### Fixed
+- Sceneview mouse lookaround in flytrough mode (right click + drag) didn't work in the path editor in Windows.
+- Having a ObiParticleRenderer with no material applied resulted in a exception in builds due GetInstanceID() returning 0 in editor but raising a nullref exception in the build.
+
+## [7.0]
+
+### Added
+- Compute shader based GPU solver backend.
+- More efficient solver update cycle, that also removes the need to have ObiUpdater components.
+- Aerodynamic constraint support for ObiRope, ObiRod and ObiBone.
+
+### Changed
+- Rendering system is now fully multithreaded, integrated with the solver backend.
+
+### Removed
+- Native library based 'Oni' solver backend.
+- ObiUpdater and all derived classes have been removed.
+
+## [6.5.1]
+
+### Added
+- Support for holes in terrain colliders.
+
+## [6.5]
+
+### Added
+- Improved constraint coloring, which results in much faster blueprint generation.
+
+### Fixed
+- Memory leak when using collision constraints in the Burst backend.
+- Performance drop when using collision constraints in Burst >1.7
+- Incorrect lighting on particles in the blueprint editor, when opening the editor without having previously opened any scene.
+
+## [6.4]
+
+### Added
+- Support for configurable enter play mode (domain and scene reload disabling).
+- Support for in-editor hot reloading.
+- Numerical fields to edit control point position and tangents added to the path editor.
+
+### Changed
+- Better path editor integration using Unity's editor custom tool API.
+- GrapplingHook sample scene now features a hook rope that extends over time, instead of extending instantly.
+- Reduced memory allocation in ObiPathSmoother Decimate() method.
+- Introduced a job handle pool to avoid runtime allocation of handles by both Burst and Oni backends.
+- Constraint padding array in Burst solver has been turned into a member variable instead of allocating anew it every frame.
+- Collision and friction batches are pooled instead of allocated every frame.
+
+### Fixed
+- InvalidOperationException when performing certain spatial queries with jobs debugger enabled in the Burst backend.
+- ObiBone collision category was internally resetting to zero upon pressing play.
+- Particle render mode in blueprint editor wasn't updated every frame under specific circumstances.
+
+## [6.3]
+
+### Added
+- New ObiBone actor, creates a particle-based representation of a bone hierarchy and simulates it using rod constraints.
+- Built-in support for applying solver gravity in world-space.
+
+### Fixed
+- Bug in attachments: prefab modifications were not being applied to the component.
+- Slight reduction in solver memory allocation.
+- Object disposed exception when using contact callbacks with a non-visible solver.
+
+## [6.2]
+
+#IMPORTANT: If updating from an older version, you’ll need to readjust collision filtering in your scenes.
+Phase-based collision filtering has been replaced by mask/categroy based system.
+
+### Added
+- New spatial query API, that allows to perform efficient distance, overlap and raycast queries.
+
+### Changed
+- Collision phase filtering has been replaced by a category/mask system. If you upgrade existing projects to Obi 6.2, you will have to set up categories and masks appropiately.
+
+
+## [6.1]
+
+### Added
+- RopeCutting sample scene, where screen-space line dragged by the user is used to cut multiple 3D ropes.
+- Snake sample scene, where a snake-like character implemented using a rope can be controlled by the user.
+
+### Changed
+- Decreased minimum error in distance fields to 1e-07
+
+### Fixed
+- Bug in Oni backend: collision stickiness resulted in rapid particle separation from the collision surface.
+- Bug that caused NaN velocity assignments to rigidbodies after removing all actors from a solver.
+
+## [6.0.1]
+
+### Fixed
+- Bug in Burst backend, resulting in InvalidOperationException when enabling Burst safety checks.
+- Bug in ObiSolver that caused particleToActor array entries to be null.
+
+## [6.0]
+
+### Added
+- Optional simplex-based surface collion pipeline for more accurate collision detection/response.
+- Predictive variable-step constraint solving that makes syncing Unity's physics no longer necessary when using substeps.
+- Amount of CCD is now adjustable per-solver.
+- Collision margin is now adjustable per-solver.
+- Bend and bend/twist constraints now support plasticity.
+- One-sided collision detection between particles. Particles with one-sided collision detection will always project penetrating particles to the side defined by their associated normal.
+
+### Fixed
+- Bug in dynamic particle attachments that would case colliders parented under a solver to lose their attachments upon enabling/reenabling a solver.
+
+### Changed
+- Contacts "particle" and "other" have been renamed to "bodyA" and "bodyB". bodyB might be a simplex or collider index, depending on the contact type.To access
+particle indices from simplex indices, use the solver.simplices array.
+
+## [5.6.2]
+
+### Fixed
+- Missed collisions using certain meshes for MeshColliders, due to a bug in bounding interval hierarchy generation.
+- Corrected orientation error in the first particle of rods, when there's multiple rods in a solver.
+- Corrected rendering error in rods, when there's multiple rods in a solver.
+
+## [5.6.1]
+
+### Fixed
+- Bug in Burst backend: solver bounding box size was typically underestimated.
+- Bug in Burst backend: when using volume constraints: "InvalidOperationException: The NativeContainer ApplyVolumeConstraintsBatchJob.particleIndices has not been assigned or constructed"
+- Bug in Burst backend: not releasing native arrays when empty solvers -with zero actors in them- are present in the scene.
+- Bug in Oni backend: volume constraints not working properly when multiple actors are present in the solver.
+- Fixed crash when using ObiLateUpdater or ObiLateFixedUpdater with the Burst backend.
+- Reduced GC allocation in dynamic particle attachments.
+- Fixed bug in Skin constraints, that caused them to fail restricting particle movement in certain circumstances.
+
+### Changed
+- Updated Oni iOS library to XCode 12.1. Make sure to use XCode 12.1 or up to build for iOS when using the Oni backend.
+- ObiKinematicVelocities component has been removed. Its functionality is now built into the engine, and automatically used for kinematic rigidbodies.
+
+### Added
+- Sample ObiContactDispatcher component, that will call custom enter/stay/exit contact events.
+- Support for multiple solvers in sample script in ObiContactGrabber.
+- Added util LookAroundCamera component.
+
+## [5.6]
+
+### Added
+- Faster SDF generation.
+- New sample scene.
+
+### Fixed
+- Bug that causes out of bounds access when dinamically adding/removing colliders at runtime.
+- Bug that prevented stitch constraints from working first time they were enabled.
+- Offset in particle selection brush on high density screens.
+
+### Changed
+- Constraint batches of multiple actors are now merged together. This greatly reduces the amount of dispatched jobs and improves performance on both backends.
+- Colliders no longer have a "use distance fields" boolean value, they will always use the SDF as long as they have one.
+
+## [5.5]
+
+### Added
+- Backend system: abstracts the underlying particle-based physics engine used. To the native, built-in engine (Oni), we have added a Burst-based implementation that
+will run on all platforms supported by Burst.
+
+### Changed
+- Improved path smoother, line and extruded renderer performance.
+
+## [5.4]
+
+### Fixed
+- Bug that caused a crash when using Obi in conjunction with Mirror networking system (NetworkIdentity component).
+- Bug that could cause a crash when disabling an actor under a disabled solver.
+- Bug that prevented self-collisions to work correctly between particles created at runtime by a ObiRopeCursor.
+
+### Changed
+- Recompiled iOS libraries using XCode 11.3.1, to circumvent bitcode compatibility issues now that XCode 11.4 and up have a bug that cause linking against Obi to fail.
+
+
+## [5.3]
+
+### Added
+- Added adaptive rendering decimation to ObiPathSmoother, controllable using a curvature threshold.
+- Greatly increased numerical precision for rigidbody interaction when solvers are far away from the origin.
+- 2D colliders now span infinitely in the Z axis.
+
+### Fixed
+- Issue in the ObiStitcher editor that picked up incorrect particles when adding stitches.
+- Issue that caused a 1-frame delay for collider geometry parented inside a solver.
+- Issue in ObiParticleDragger that caused incorrect behavior with multiple solvers.
+- Bug in particle advection, that assumed diffuse particle positions to be expreseed in world space. Now advection works correctly
+for solvers not positioned at 0,0,0.
+
+## [5.2]
+
+### Added
+- Rope tear callback (cloth.OnRopeTorn)
+- Function to reset particle positions orientations and and velocities in an actor (actor.ResetParticles())
+- Added support for ObiRopeLineRenderer in SRPs.
+
+### Fixed
+- Issue with inertia rotations, that caused wrong inertia tensors for complex compound colliders.
+- Issue in particle attachments, that forced to call Bind() manually after changing their target or particle group at runtime.
+
+
+## [5.1]
+
+### Added
+-Smooth initial overlap resolution by using clamped depenetration velocity.
+-Actors now automatically create a solver root when editing them in prefab mode.
+-Brought back rope mesh baking.
+
+### Fixed
+- Bug that caused solvers with no actors in their hierarchy to freeze Unity when updated by a fixed updater.
+- Bug that prevented multiple colliders in the same object to be notified of transform changes.
+
+### Fixed
+-Fixed bug that caused null ref when attempting to edit a rope with no blueprint.
+
+## [5.0]
+
+#IMPORTANT: You’ll need to re-create all your 4.x ObiRope components. Data serialization and workflows are significantly different from previous versions.
+
+### Changed
+- Introduced blueprints: particle/constraint object representations are now stored in assets called "blueprints" (as opposed to being stored in the actor itself, as in previous versions). This improves
+memory consumption, editor performance, completely separates data from the runtime components that operate on it, and enables easier and faster workflow.
+- Non-linear, non-destructive rope editing with instant feedback.
+- Simplified underlying engine, constraints are grouped in batches using graph coloring for optimal parallelism.
+- Unified handles and pin constraints as "attachments".
+- Pin and distance constraints now correctly report forces in Newtons.
+- Unitless "Stiffness" parameters have been replaced by "Compliance" parameters in most constraint types, expressed in Newtons/meter.
+
+### Added
+- Support for multiple cursors in a single rope.
+
+### Removed
+- World space/local space simulation. Simulation is now always performed in solver space.
+- Solvers no longer have a maxParticles attribute. They dynamically change their capacity at runtime.
+
+### Fixed
+- Crash in certain iOS devices using the A12 cpu.
+
+## [4.2]
+
+### Added
+- Remade all sample scenes to work in Unity 2019.1 and above.
+
+
+## [4.1]
+
+#IMPORTANT: You’ll need to re-create all your 3.x ObiRope components, as internal data layout of previous versions as well as serialized GameObject data from previous versions is not compatible with 4.x.
+
+### Added
+- Now you can bake the rope mesh anytime, saving it as a new mesh asset in your project. Useful for set dressing and generating static geometry. Only works for ObiRopeExtrudedMeshRederer and ObiRopeMeshRenderer.
+- More accurate collision/contact model, using staggered projections.
+- Approximate shock propagation for particle contacts. This makes particle stacking easier and stabler. A new parameter has been added to the solver that controls the amount of shock propagation.
+- Split material friction into static and dynamic friction.
+- Added rolling contacts w/ rolling friction. These are slightly more expensive than regular contacts. Can be controlled on a per-collision material basis.
+- Added ObiInstancedParticleRenderer, allows to draw particles as instances of an arbitrary mesh (requires GPU instancing).
+- Particle-particle collision callbacks (solver.OnParticleCollision)
+
+### Fixed
+- Bug that caused mesh colliders with negative thickness to crash.
+
+### Changed
+- More reliable, higher precision algorithm for distance field generation. Specially noticeable in sharp corners/crevices.
+
+## [4.0.2]
+
+#IMPORTANT: You’ll need to re-create all your 3.x ObiRope components, as internal data layout of previous versions as well as serialized GameObject data from previous versions is not compatible with 4.x.
+
+### Changed
+- Switched the Windows compiler to Clang/LLVM, resulting in a huge performance improvement.
+
+### Fixed
+- Null ref exception when copying a ObiCloth component.
+- Issue with pin constraints overshooting when solver set to world space mode.
+- Issue that prevented pin constraints being torn.
+
+## [4.0]
+
+#IMPORTANT: You’ll need to re-create all your ObiRope components, as internal data layout of previous versions as well as serialized GameObject data from previous versions is not compatible with 4.x.
+
+### Added
+- New ObiRod actor: advanced rope that models torsion, as well as anisotropic bending and shearing.
+- Added 3 new constraint types: Shear/Stretch, Bend/Twist and Chain.
+- Achieved zero garbage generation trough the use of new Unity API for camera frustum planes.
+
+### Changed
+- All particle buffers (positions, velocities, etc). are now shared between C++/C# using pointers to aligned memory. This completely eliminates the need for copying data back and forth, simplifies the API
+ and improves performance. The entire Oni.Get/SetParticle* family of methods has disappeared, now you can work with the particle buffers directly.
+- Rope rendering modes have been replaced by ObiRopeRenderer components.
+
+### Fixed
+- Null ref exception when initializing a disabled actor.
+- Bug that caused XPBD to be time step dependent.
+
+## [3.5]
+
+### Added
+- Support for 32 and 64 bit Linux architectures.
+- Two-way rigidbody interaction for local-space solvers.
+- Added world inertia scale.
+- ObiCollider now takes a reference to a Collider, enabling the use of multiple colliders in the same GameObject.
+
+### Changed
+- Separated world velocity scale into linear and angular components.
+- World velocity scale is no longer specified per-actor, but per-solver.
+- Better ObiProfiler: it now shows a per-thread pyramid diagram of internal jobs, with more human-readable names.
+
+### Removed
+- Solvers no longer have a Collision Layers property. All solvers share the same colliders. Note that you can still use phases to ignore collisions with certain colliders.
+- Local space solvers no longer need their own copy of each ObiCollider in the scene, they can all share the same colliders. This results in much higher performance for multiple local-space solvers.
+
+### Fixed
+- Added (float3x3) typecast to particle shaders, to be GLES friendly.
+
+## [3.4.1]
+
+### Added
+- "Thickness from particles" now works in Custom Mesh render mode.
+- Custom Mesh mode now has a "volume scaling" parameter that squashes and stretches the mesh together with the rope.
+
+## [3.4]
+
+### Added
+- Perspective-correct particle rendering.
+- ObiParticleRenderer now supports custom shaders for rendering.
+
+### Fixed
+- Bug that required to disable and re-enable ObiParticleRenderer when moving the actor to a new solver.
+- Bug that caused twitching when performing more than 1 physics step per frame when using handles.
+
+## [3.3.1]
+
+### Fixed
+- Removed unused variable warnings introduced in 3.3
+- Fixed null ref exception when creating a new distance field asset.
+- Fixed crash when using multiple solvers in different update modes.
+- Fixed some sample scenes lacking collision due to missing distance field.
+
+## [3.3]
+
+### Added
+- Support for 2D rigidbody coupling has been brought back.
+- Added substepping to the core solver. This allows to update each solver at a different effective frequency, and decouple the Obi
+ physics loop from Unity’s.
+- New implementation of fine-grained parallel tasks in core solver, that boosts performance up to x1.5.
+- Support for a new type of rope rendering, that can deform any mesh to follow the rope curve.
+- Support for a new collision primitive: distance fields.
+- Support for per-particle coloring of rope.
+- ObiCollider automatically creates ObiRigidbody component if needed when reparenting it.
+- Helper script (ObiKinematicVelocities) that calculates angular and linear velocities for kinematic rigidbodies that are transformed around. Useful for continuous collision detection and friction effects against objects that are being moved around using their transform instead of forces.
+
+### Changed
+- Near-zero garbage generation for OnCollision and ObFluidUpdated solver events.
+- Near-zero garbage generation for rope rendering.
+- Constraints.GetBatches() now returns an IEnumerable. This means it cannot be accesed by index. There’s a helper method GetFirstBatch() that returns
+the correctly typed first batch, or null if there’s none.
+
+### Fixed
+- Null reference exception in pin constraints when visualization is enabled.
+- Bug that caused asleep particles to miss collisions upon reactivation.
+- Bug that caused copying a rope to “steal“ the mesh from the original one.
+
+## [3.2]
+### Added
+- Support for CapsuleCollider2D.
+
+### Changed
+- Rope is still rendered (though not simulated) when the ObiRope component is disabled.
+- Colliders/rigidbodies are no longer copied over to the C++ library each frame. Instead, only colliders that have their transform or any collision-related property altered are copied to the solver. This greatly improves performance when many colliders are present, and greatly reduces memory allocation and GC activity.
+- AllocateParticles() and FreeParticles() have been merged with AddActor() and RemoveActor() respectively. A new per-particle array “particleToActor” makes it faster and easier to know which actor a particle belongs to.
+
+### Removed
+- ObiCollisionGroup has disappeared. It is no longer necessary to manually add colliders to a group, instead each ObiSolver automatically picks up all ObiColliders in a given layer.
+- MeshColliders are now always treated as two-sided thin concave meshes. Solid and one-sided modes have disappeared.
+
+### Fixed
+- Android issue that prevented some devices from finding the Oni library.
+- Removed redundant menu items.
+
+## [3.1.1]
+### Added
+- New “Line” rendering mode for ropes. This will render the rope as a camera-oriented quad strip, similar to what Unity’s LineRenderer does. This is useful for lightweight rendering and 2D games.
+- Particle renderer is now much faster and also allocates less memory.
+- New “hierarchical” method to generate tether constraints: this method generates more constraints than the traditional “anchor to fixed” approach, but works in the general case even if there are no fixed particles.
+
+### Changed
+- Installation is no longer required. Obi now works right out of the box, so the installation window has been removed, and the “Editor default resources” and “Gizmos” folders removed.
+
+## [3.1]
+### Added
+- You can now choose where should the solver be updated: FixedUpdate, AfterFixedUpdate, or LateUpdate.
+- Rope rendering now supports variable thickness, based on particle radii. Enabled by default, disable “thickness from particles” to get uniform thickness regardless of particle radii variations.
+- Edit-time preview of “smoothness” rope parameter.
+- Utility method to calculate actual rope length.
+- Support for triggers. A trigger collider will generate contact constraints, but won´t enforce them.
+- Contact structs returned by the OnCollision event now include the contact tangent and bitangent vectors.
+- Added per-particle layer properties, for finer collision control.
+
+### Changed
+- Faster and more accurate rigidbody impulse application, which results in better collision resolution.
+- Greatly improved pin constraint stability for large mass ratios.
+- ObiColliderGroup’s Colliders and Colliders2D properties are now plain arrays: “colliders” and “colliders2D”.
+- Memory allocation for rope mesh generation has been reduced by 90%.
+- ObiParticleRenderer memory allocation has been greatly reduced, and its performance improved.
+- Pin constraints are now always drawn in particle edit mode, not only when the particles are selected.
+
+### Fixed
+- Got rid of warnings related to obsolete platform enums in sample scripts.
+- Potential bug in GCHandle deallocation affecting upcoming Unity versions (thanks to the guys at Unity for pointing me at this)
+- Tearable pin constraints now work correctly.
+
+## [3.0.1]
+### Added
+- Support for iOS simulator.
+- Faster collision contact generation.
+
+### Fixed
+- Crash in Crane scene due to a bug in pin constraints.
+
+## [3.0]
+
+#IMPORTANT: You’ll need to re-generate all your ropes as internal data layout of previous versions is not compatible with this update.
+### Added
+- Welcome window with automatic installer.
+- Upgraded constraint projection to XPBD (extended position-based dynamics). This decouples stiffness and damping from the amount of iterations, resulting in more realistic simulation.
+- Solver constraint enforcement order can now be changed. This allows to change the relative importance of constraints.
+- The solver now uses a task-based threading system which allows to exploit parallelism between multiple solvers.
+- Custom multithreading profiler, that allows to fine-tune performance.
+- Optional local-space simulation, for better numerical accuracy in large-scale worlds and greater control.
+- ObiStitcher component allows to stitch together separate ropes.
+- Added pencil paint mode to particle editor.
+- Automatic self-collisions disabling for particles that intersect in rest pose. This allows to set larger particle radii
+ to ensure better self-collisions, without worrying about constraint fighting.
+- Breakable pin constraints.
+- Ropes are now tearable, and custom prefabs can be instantiated at both sides of the tear.
+- Rope length can be changed at runtime, using the ObiRopeCursor component.
+- Procedural curve geometry smoothing.
+
+### Changed
+- Actor particle limit is no longer 16384 but 65536, matching Unity’s own vertex limit.
+- Particle editor paint brush falloff has ben changed from linear to gaussian.
+- Distance constraints’ compression stiffness has been replaced by a slack percentage.
+- Performance improvement in mesh colliders and edge colliders.
+
+### Fixed
+- Bug in collision detection against terrains.
+- Crash in 32-bit windows systems due to memory misalignment.
+- Bug that caused slow convergence and excessive jittering for particle-particle sequential contact resolution.
+- Bug in hierarchical grid update that caused a crash in some cases when a hash key collision happened.
+- Bug in continuous collision detection that caused particles to be pushed to the other side of very thin objects.
+- Bug in ray/bounding box intersection test caused by non-IEEE754 compliant SSE division by zero.
+- Bug that caused ObiParticleRenderer to ignore camera culling mask, and render in all cameras.
+- Bug that caused a crash under certain conditions in 32 bit systems.
+- Bug that caused particle property value field to reset to the value of the last particle when painting.
+- Fixed collision stabilization bug that caused particles to sink slightly when over a dynamic rigidbody.
+
+## [1.2]
+
+### Added
+- Android support.
+- Upgraded constraint projection to XPBD (extended position-based dynamics). This decouples stiffness and damping from the amount of iterations.
+- Solver constraint enforcement order can now be changed. This allows to change the relative importance of constraints.
+- Welcome window with automatic installer.
+- Resolution-preserving method to change rope length dynamically.
+- Added pencil paint mode to particle editor.
+- Optional local-space simulation, for better numerical accuracy in large-scale worlds and greater control.
+- Custom multithreading profiler, that allows to fine-tune performance.
+- Better particle visualization in editor.
+- Breakable pin constraints.
+
+### Changed
+- Actor particle limit is no longer 16384 but 65536, matching Unity’s own vertex limit.
+- Particle editor paint brush falloff has ben changed from linear to gaussian.
+- Distance constraints’ compression stiffness has been replaced by a slack percentage.
+
+### Fixed
+- Bug that caused an index out of bounds exception when initializing rope with zero resolution.
+- Bug that caused an error message regarding MeshFilter destruction when entering play mode with a rope selected in the hierarchy.
+- Bug that prevented the particle editor window from appearing on retina displays.
+- 1-frame delay between particle and rigid body physics, which affected pin and collision constraints.
+
+## [1.1]
+
+### Added
+- MeshColliders are now fully supported.
+- Support for 2D physics, Box2D, Circle2D and Edge2D colliders.
+- Chain rendering.
+- Sleep threshold that keeps particles fixed in place when their kinetic energy is low.
+- Chain constraints, that allow for 100% inextensible ropes.
+- Rope thickness, twist, cap sections and section shape can now be changed without the need to re-initialize the rope.
+- Required constraint components are automatically removed from the object when removing the rope component in editor.
+
+### Fixed
+- Issue with box colliders, that caused incorrect contact generation in corners when using contactOffset.
+
+## [1.0.0] - 2015-07-16
+- Initial release.
diff --git a/Assets/Obi/CHANGELOG_rope.txt.meta b/Assets/Obi/CHANGELOG_rope.txt.meta
new file mode 100644
index 000000000..7cc321af1
--- /dev/null
+++ b/Assets/Obi/CHANGELOG_rope.txt.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 8d9d04260bc994f1b9d444b675212dc6
+labels:
+- ObiRope
+TextScriptImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor.meta b/Assets/Obi/Editor.meta
new file mode 100644
index 000000000..ec618e6c7
--- /dev/null
+++ b/Assets/Obi/Editor.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: d6a0c47fa0afb4e1fb441061faa32d50
+folderAsset: yes
+timeCreated: 1435569421
+licenseType: Store
+DefaultImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common.meta b/Assets/Obi/Editor/Common.meta
new file mode 100644
index 000000000..5684f1cf4
--- /dev/null
+++ b/Assets/Obi/Editor/Common.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 3d5722720e25b4db69e767c6920cf081
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints.meta b/Assets/Obi/Editor/Common/Blueprints.meta
new file mode 100644
index 000000000..5576b9554
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 1af54f7feeec0410cada2fc051752b61
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints/BlueprintEditorTools.meta b/Assets/Obi/Editor/Common/Blueprints/BlueprintEditorTools.meta
new file mode 100644
index 000000000..6737bc72c
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/BlueprintEditorTools.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: aa63386a67f904b399175c9931270250
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints/BlueprintEditorTools/ObiBlueprintEditorTool.cs b/Assets/Obi/Editor/Common/Blueprints/BlueprintEditorTools/ObiBlueprintEditorTool.cs
new file mode 100644
index 000000000..54dcca92d
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/BlueprintEditorTools/ObiBlueprintEditorTool.cs
@@ -0,0 +1,40 @@
+using UnityEngine;
+using UnityEditor;
+
+namespace Obi
+{
+ public abstract class ObiBlueprintEditorTool
+ {
+ protected ObiActorBlueprintEditor editor;
+ protected string m_Name;
+ protected Texture m_Icon;
+
+ public string name
+ {
+ get { return m_Name; }
+ }
+
+ public Texture icon
+ {
+ get
+ {
+ return m_Icon;
+ }
+ }
+
+ public ObiBlueprintEditorTool(ObiActorBlueprintEditor editor)
+ {
+ this.editor = editor;
+ }
+
+ public virtual void OnEnable(){}
+ public virtual void OnDisable(){}
+ public virtual void OnDestroy(){}
+ public virtual string GetHelpString() { return string.Empty; }
+
+ public abstract void OnInspectorGUI();
+ public virtual void OnSceneGUI(SceneView sceneView){}
+
+ public virtual bool Editable(int index) { return editor.visible[index]; }
+ }
+}
\ No newline at end of file
diff --git a/Assets/Obi/Editor/Common/Blueprints/BlueprintEditorTools/ObiBlueprintEditorTool.cs.meta b/Assets/Obi/Editor/Common/Blueprints/BlueprintEditorTools/ObiBlueprintEditorTool.cs.meta
new file mode 100644
index 000000000..95c9d3dd5
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/BlueprintEditorTools/ObiBlueprintEditorTool.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: ca0c1c4cbbd024d49b15bf3439506500
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints/BlueprintEditorTools/ObiPaintBrushEditorTool.cs b/Assets/Obi/Editor/Common/Blueprints/BlueprintEditorTools/ObiPaintBrushEditorTool.cs
new file mode 100644
index 000000000..c2c9e1233
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/BlueprintEditorTools/ObiPaintBrushEditorTool.cs
@@ -0,0 +1,130 @@
+using UnityEngine;
+using UnityEditor;
+
+namespace Obi
+{
+ public class ObiPaintBrushEditorTool : ObiBlueprintEditorTool
+ {
+ public ObiRaycastBrush paintBrush;
+ public bool selectionMask = false;
+ public int sourcePropertyIndex = 0; /**("BrushIcon");
+ m_Name = "Property painting";
+
+ paintBrush = new ObiRaycastBrush(editor.sourceMesh,
+ () =>
+ {
+ // As RecordObject diffs with the end of the current frame,
+ // and this is a multi-frame operation, we need to use RegisterCompleteObjectUndo instead.
+ Undo.RegisterCompleteObjectUndo(editor.blueprint, "Paint particles");
+ },
+ () =>
+ {
+ editor.Refresh();
+ },
+ () =>
+ {
+ EditorUtility.SetDirty(editor.blueprint);
+ });
+
+ }
+
+ public override string GetHelpString()
+ {
+ return "Paint particle properties directly on the mesh. Most brushes have an alternate mode, accesed by holding 'shift' while painting.";
+ }
+
+ public override void OnInspectorGUI()
+ {
+ EditorGUILayout.BeginVertical(EditorStyles.inspectorDefaultMargins);
+ EditorGUILayout.Space();
+
+ // toolbar with available brush modes for the current property:
+ editor.currentProperty.BrushModes(paintBrush);
+
+ EditorGUILayout.Space();
+
+ EditorGUI.BeginChangeCheck();
+ editor.currentPropertyIndex = editor.PropertySelector(editor.currentPropertyIndex);
+ if (EditorGUI.EndChangeCheck())
+ {
+ editor.Refresh();
+ editor.currentProperty.OnSelect(paintBrush);
+ }
+
+ if (paintBrush.brushMode is ObiFloatCopyBrushMode)
+ {
+ EditorGUI.BeginChangeCheck();
+ sourcePropertyIndex = editor.PropertySelector(sourcePropertyIndex, "Copy from");
+ var sourceProperty = editor.GetProperty(sourcePropertyIndex) as ObiBlueprintFloatProperty;
+ if (EditorGUI.EndChangeCheck())
+ {
+ (paintBrush.brushMode as ObiFloatCopyBrushMode).source = sourceProperty;
+ }
+ if (sourceProperty == null)
+ EditorGUILayout.HelpBox("You can't copy value from this property.", MessageType.Error);
+ }
+
+ if (paintBrush.brushMode.needsInputValue)
+ editor.currentProperty.PropertyField();
+
+ paintBrush.radius = EditorGUILayout.Slider("Brush size", paintBrush.radius, 0.0001f, 0.5f);
+ paintBrush.innerRadius = EditorGUILayout.Slider("Brush inner size", paintBrush.innerRadius, 0, 1);
+ paintBrush.opacity = EditorGUILayout.Slider("Brush opacity", paintBrush.opacity, 0, 1);
+ paintBrush.mirror.axis = (ObiBrushMirrorSettings.MirrorAxis)EditorGUILayout.EnumPopup("Brush mirror axis", paintBrush.mirror.axis);
+ paintBrush.mirror.space = (ObiBrushMirrorSettings.MirrorSpace)EditorGUILayout.EnumPopup("Brush mirror space", paintBrush.mirror.space);
+
+ EditorGUI.BeginChangeCheck();
+ meshBasedEditor.particleCulling = (ObiMeshBasedActorBlueprintEditor.ParticleCulling)EditorGUILayout.EnumPopup("Culling", meshBasedEditor.particleCulling);
+ if (ObiActorBlueprintEditor.selectedCount == 0)
+ {
+ EditorGUILayout.HelpBox("Select at least one particle to use selection mask.", MessageType.Info);
+ selectionMask = false;
+ GUI.enabled = false;
+ }
+ selectionMask = EditorGUILayout.Toggle("Selection mask", selectionMask);
+ if (EditorGUI.EndChangeCheck())
+ SceneView.RepaintAll();
+ GUI.enabled = true;
+
+ EditorGUILayout.EndVertical();
+
+ EditorGUILayout.Space();
+ GUILayout.Box(GUIContent.none, ObiEditorUtils.GetSeparatorLineStyle());
+
+ EditorGUILayout.BeginVertical(EditorStyles.inspectorDefaultMargins);
+
+ editor.RenderModeSelector();
+ editor.currentProperty.VisualizationOptions();
+
+ EditorGUILayout.EndVertical();
+ }
+
+ public override bool Editable(int index)
+ {
+ return editor.visible[index] && (!selectionMask || ObiActorBlueprintEditor.selectionStatus[index]);
+ }
+
+ public override void OnSceneGUI(SceneView view)
+ {
+ if (Camera.current != null)
+ {
+ var blueprint = meshBasedEditor.blueprint as ObiMeshBasedActorBlueprint;
+ paintBrush.raycastTransform = blueprint != null ? Matrix4x4.TRS(Vector3.zero, blueprint.rotation, blueprint.scale) : Matrix4x4.identity;
+
+ paintBrush.raycastTarget = meshBasedEditor.sourceMesh;
+ paintBrush.DoBrush(editor.blueprint.positions);
+ }
+ }
+
+ }
+}
diff --git a/Assets/Obi/Editor/Common/Blueprints/BlueprintEditorTools/ObiPaintBrushEditorTool.cs.meta b/Assets/Obi/Editor/Common/Blueprints/BlueprintEditorTools/ObiPaintBrushEditorTool.cs.meta
new file mode 100644
index 000000000..b0abbdf5a
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/BlueprintEditorTools/ObiPaintBrushEditorTool.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 332bb5fc94a774291b4c4ebe50f61205
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints/BlueprintEditorTools/ObiParticleSelectionEditorTool.cs b/Assets/Obi/Editor/Common/Blueprints/BlueprintEditorTools/ObiParticleSelectionEditorTool.cs
new file mode 100644
index 000000000..6a21eb662
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/BlueprintEditorTools/ObiParticleSelectionEditorTool.cs
@@ -0,0 +1,336 @@
+using UnityEngine;
+using UnityEditor;
+using UnityEditorInternal;
+
+namespace Obi
+{
+ public class ObiParticleSelectionEditorTool : ObiBlueprintEditorTool
+ {
+ ObiScreenSpaceBrush selectionBrush;
+ ObiSelectBrushMode selectMode;
+ ObiTethersTool tethersTool;
+
+ protected ReorderableList particleGroupList;
+ protected bool mixedPropertyValue = false;
+ protected float minSelectionValue;
+ protected float maxSelectionValue;
+
+ public ObiParticleSelectionEditorTool(ObiActorBlueprintEditor editor) : base(editor)
+ {
+ m_Icon = Resources.Load("SelectIcon");
+ m_Name = "Particle selection";
+
+ selectionBrush = new ObiScreenSpaceBrush(null, UpdateSelection, null);
+ selectMode = new ObiSelectBrushMode(new ObiBlueprintSelected(editor));
+
+ selectionBrush.brushMode = selectMode;
+ tethersTool = new ObiTethersTool();
+
+ InitializeGroupsList();
+ }
+
+
+ public override string GetHelpString()
+ {
+ if (ObiActorBlueprintEditor.selectedCount > 0)
+ return "" + ObiActorBlueprintEditor.selectedCount + " selected particles.";
+ else
+ return "No particles selected. Click and drag over particles to select them.";
+ }
+
+ private void InitializeGroupsList()
+ {
+ particleGroupList = new ReorderableList(editor.serializedObject,
+ editor.serializedObject.FindProperty("groups"),
+ false, true, true, true);
+
+ particleGroupList.drawHeaderCallback = (Rect rect) =>
+ {
+ EditorGUI.LabelField(rect, "Groups");
+ };
+
+ particleGroupList.drawElementCallback = (Rect rect, int index, bool isActive, bool isFocused) =>
+ {
+ var element = particleGroupList.serializedProperty.GetArrayElementAtIndex(index);
+ rect.y += 4;
+
+ SerializedObject obj = new SerializedObject(element.objectReferenceValue);
+ ObiParticleGroup group = obj.targetObject as ObiParticleGroup;
+
+ EditorGUI.PropertyField(new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight),
+ obj.FindProperty("m_Name"), new GUIContent("Name"));
+ rect.y += EditorGUIUtility.singleLineHeight + 2;
+
+ if (GUI.Button(new Rect(rect.x, rect.y, rect.width * 0.5f, EditorGUIUtility.singleLineHeight), "Select", EditorStyles.miniButtonLeft))
+ {
+ if ((Event.current.modifiers & EventModifiers.Shift) == 0)
+ {
+ for (int p = 0; p < ObiActorBlueprintEditor.selectionStatus.Length; p++)
+ ObiActorBlueprintEditor.selectionStatus[p] = false;
+ }
+
+ foreach (int p in group.particleIndices)
+ ObiActorBlueprintEditor.selectionStatus[p] = true;
+
+ UpdateSelection();
+ }
+
+ if (GUI.Button(new Rect(rect.x + rect.width * 0.5f, rect.y, rect.width * 0.5f, EditorGUIUtility.singleLineHeight), "Set", EditorStyles.miniButtonRight))
+ {
+ group.particleIndices.Clear();
+ for (int p = 0; p < ObiActorBlueprintEditor.selectionStatus.Length; p++)
+ {
+ if (ObiActorBlueprintEditor.selectionStatus[p])
+ group.particleIndices.Add(p);
+ }
+ }
+
+ obj.ApplyModifiedProperties();
+ };
+
+ particleGroupList.elementHeight = (EditorGUIUtility.singleLineHeight + 2) * 2 + 8;
+
+ particleGroupList.onAddCallback = (ReorderableList list) =>
+ {
+
+ var group = editor.blueprint.AppendNewParticleGroup("new group");
+
+ for (int i = 0; i < ObiActorBlueprintEditor.selectionStatus.Length; i++)
+ {
+ if (ObiActorBlueprintEditor.selectionStatus[i])
+ group.particleIndices.Add(i);
+ }
+
+ AssetDatabase.SaveAssets();
+ };
+
+ particleGroupList.onRemoveCallback = (ReorderableList list) =>
+ {
+ editor.blueprint.RemoveParticleGroupAt(list.index);
+ };
+ }
+
+ private void SelectionTools()
+ {
+ EditorGUILayout.BeginHorizontal();
+ GUILayout.FlexibleSpace();
+ if (GUILayout.Button(new GUIContent(Resources.Load("InvertButton"), "Invert selection"), GUILayout.MaxHeight(24), GUILayout.MaxWidth(48)))
+ {
+ for (int i = 0; i < ObiActorBlueprintEditor.selectionStatus.Length; i++)
+ {
+ if (editor.blueprint.IsParticleActive(i))
+ ObiActorBlueprintEditor.selectionStatus[i] = !ObiActorBlueprintEditor.selectionStatus[i];
+ }
+ UpdateSelection();
+ }
+
+ GUI.enabled = ObiActorBlueprintEditor.selectedCount > 0;
+ if (GUILayout.Button(new GUIContent(Resources.Load("ClearButton"), "Clear selection"), GUILayout.MaxHeight(24), GUILayout.MaxWidth(48)))
+ {
+ for (int i = 0; i < ObiActorBlueprintEditor.selectionStatus.Length; i++)
+ ObiActorBlueprintEditor.selectionStatus[i] = false;
+ UpdateSelection();
+ }
+
+ if (GUILayout.Button(new GUIContent(Resources.Load("OptimizeButton"), "Optimize selected"), GUILayout.MaxHeight(24), GUILayout.MaxWidth(48)))
+ {
+ Undo.RecordObject(editor.blueprint, "Optimize particles away");
+ editor.blueprint.RemoveSelectedParticles(ref ObiActorBlueprintEditor.selectionStatus);
+ editor.Refresh();
+ }
+
+ if (GUILayout.Button(new GUIContent(Resources.Load("RemoveButton"), "Remove selected"), GUILayout.MaxHeight(24), GUILayout.MaxWidth(48)))
+ {
+ Undo.RecordObject(editor.blueprint, "Remove particles");
+ editor.blueprint.RemoveSelectedParticles(ref ObiActorBlueprintEditor.selectionStatus, false);
+ editor.Refresh();
+ }
+ GUI.enabled = true;
+
+ if (GUILayout.Button(new GUIContent(Resources.Load("RestoreButton"), "Restore removed particles"), GUILayout.MaxHeight(24), GUILayout.MaxWidth(48)))
+ {
+ Undo.RecordObject(editor.blueprint, "Restore removed particles");
+ editor.blueprint.RestoreRemovedParticles();
+ editor.Refresh();
+ }
+
+ GUILayout.FlexibleSpace();
+ EditorGUILayout.EndHorizontal();
+
+ EditorGUILayout.Space();
+ EditorGUILayout.LabelField("Property-based selection", EditorStyles.boldLabel);
+ var property = editor.currentProperty as ObiBlueprintFloatProperty;
+ if (property != null)
+ {
+ if (!Mathf.Approximately(property.minVisualizationValue,property.maxVisualizationValue))
+ {
+ EditorGUILayout.HelpBox("Drag the slider to select based on " + property.name + ". You can choose a different property in the \"Property\" dropdown below.", MessageType.None);
+ minSelectionValue = Mathf.Max(minSelectionValue, property.minVisualizationValue);
+ maxSelectionValue = Mathf.Min(maxSelectionValue, property.maxVisualizationValue);
+ maxSelectionValue = Mathf.Max(maxSelectionValue, minSelectionValue);
+
+ EditorGUI.BeginChangeCheck();
+ EditorGUILayout.MinMaxSlider("Select by " + property.name, ref minSelectionValue, ref maxSelectionValue, property.minVisualizationValue, property.maxVisualizationValue);
+ minSelectionValue = EditorGUILayout.FloatField("Minimum " + property.name, minSelectionValue);
+ maxSelectionValue = EditorGUILayout.FloatField("Maximum " + property.name, maxSelectionValue);
+ if (EditorGUI.EndChangeCheck())
+ {
+ for (int i = 0; i < ObiActorBlueprintEditor.selectionStatus.Length; i++)
+ {
+ if (editor.blueprint.IsParticleActive(i))
+ {
+ var value = property.Get(i);
+ ObiActorBlueprintEditor.selectionStatus[i] = value >= minSelectionValue && value <= maxSelectionValue;
+ }
+ }
+ UpdateSelection();
+ }
+ }
+ else
+ {
+ EditorGUILayout.HelpBox("All particles have the same " + property.name + " value.", MessageType.Info);
+ }
+ }
+ else
+ {
+ EditorGUILayout.HelpBox("Property-based selection only works with scalar properties.",MessageType.Info);
+ }
+ }
+
+ public override void OnInspectorGUI()
+ {
+ // Selection tools:
+ EditorGUILayout.BeginVertical(EditorStyles.inspectorDefaultMargins);
+ EditorGUILayout.Space();
+
+ selectionBrush.radius = EditorGUILayout.Slider("Brush size", selectionBrush.radius, 5, 200);
+
+ if (editor is ObiMeshBasedActorBlueprintEditor)
+ {
+ EditorGUI.BeginChangeCheck();
+ (editor as ObiMeshBasedActorBlueprintEditor).particleCulling = (ObiMeshBasedActorBlueprintEditor.ParticleCulling)EditorGUILayout.EnumPopup("Culling", (editor as ObiMeshBasedActorBlueprintEditor).particleCulling);
+ if (EditorGUI.EndChangeCheck())
+ SceneView.RepaintAll();
+ }
+
+
+ EditorGUILayout.Space();
+ SelectionTools();
+
+ EditorGUILayout.EndVertical();
+
+
+ // Properties:
+ EditorGUILayout.Space();
+ GUILayout.Box(GUIContent.none, ObiEditorUtils.GetSeparatorLineStyle());
+
+ EditorGUILayout.BeginVertical(EditorStyles.inspectorDefaultMargins);
+ EditorGUILayout.Space();
+ EditorGUILayout.LabelField("Properties", EditorStyles.boldLabel);
+ EditorGUILayout.HelpBox("Select a property to view and edit. Currently editing " + editor.currentProperty.name+".", MessageType.None);
+
+ EditorGUI.BeginChangeCheck();
+ editor.currentPropertyIndex = editor.PropertySelector(editor.currentPropertyIndex);
+ if (EditorGUI.EndChangeCheck())
+ {
+ editor.Refresh();
+ UpdateSelection();
+ }
+
+ // Property value:
+ EditorGUI.showMixedValue = mixedPropertyValue;
+ EditorGUI.BeginChangeCheck();
+ editor.currentProperty.PropertyField();
+ if (EditorGUI.EndChangeCheck())
+ {
+ Undo.RecordObject(editor.blueprint, "Set particle property");
+ for (int i = 0; i < ObiActorBlueprintEditor.selectionStatus.Length; i++)
+ {
+ if (!ObiActorBlueprintEditor.selectionStatus[i]) continue;
+ editor.currentProperty.SetDefaultToIndex(i);
+ }
+ editor.Refresh();
+ }
+
+ EditorGUI.showMixedValue = false;
+
+ EditorGUILayout.EndVertical();
+
+
+ // Particle groups:
+ EditorGUILayout.Space();
+ GUILayout.Box(GUIContent.none, ObiEditorUtils.GetSeparatorLineStyle());
+
+ EditorGUILayout.BeginVertical(EditorStyles.inspectorDefaultMargins);
+
+ EditorGUILayout.Space();
+ EditorGUILayout.LabelField("Particle groups", EditorStyles.boldLabel);
+ particleGroupList.DoLayoutList();
+
+ EditorGUILayout.EndVertical();
+
+
+
+ if (editor.blueprint.usesTethers)
+ {
+ EditorGUILayout.Space();
+ GUILayout.Box(GUIContent.none, ObiEditorUtils.GetSeparatorLineStyle());
+ EditorGUILayout.BeginVertical(EditorStyles.inspectorDefaultMargins);
+ EditorGUILayout.Space();
+ tethersTool.DoTethers(editor);
+ EditorGUILayout.EndVertical();
+ }
+
+ EditorGUILayout.Space();
+ GUILayout.Box(GUIContent.none, ObiEditorUtils.GetSeparatorLineStyle());
+
+ EditorGUILayout.BeginVertical(EditorStyles.inspectorDefaultMargins);
+
+ editor.RenderModeSelector();
+ ObiActorBlueprintEditor.dotRadiusScale = EditorGUILayout.Slider(new GUIContent("Particle dot size"), ObiActorBlueprintEditor.dotRadiusScale, 0, 5);
+ editor.currentProperty.VisualizationOptions();
+
+ EditorGUILayout.EndVertical();
+ }
+
+ public override void OnSceneGUI(SceneView sceneView)
+ {
+ if (Camera.current != null)
+ selectionBrush.DoBrush(editor.blueprint.positions);
+ }
+
+ protected void UpdateSelection()
+ {
+ ObiActorBlueprintEditor.selectedCount = 0;
+ mixedPropertyValue = false;
+
+ // Find out how many selected particles we have, and whether they all have the same value for the current property:
+ for (int i = 0; i < ObiActorBlueprintEditor.selectionStatus.Length; i++)
+ {
+ if (editor.blueprint.IsParticleActive(i) && ObiActorBlueprintEditor.selectionStatus[i])
+ {
+ ObiActorBlueprintEditor.selectedCount++;
+
+ if (ObiActorBlueprintEditor.activeParticle >= 0)
+ {
+ if (!editor.currentProperty.Equals(ObiActorBlueprintEditor.activeParticle, i))
+ mixedPropertyValue = true;
+ }
+ else
+ ObiActorBlueprintEditor.activeParticle = i;
+ }
+ else if (ObiActorBlueprintEditor.activeParticle == i)
+ ObiActorBlueprintEditor.activeParticle = -1;
+ }
+
+ // Set initial property value:
+ if (!mixedPropertyValue && ObiActorBlueprintEditor.activeParticle >= 0)
+ editor.currentProperty.GetDefaultFromIndex(ObiActorBlueprintEditor.activeParticle);
+
+ editor.Repaint();
+ SceneView.RepaintAll();
+
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/Assets/Obi/Editor/Common/Blueprints/BlueprintEditorTools/ObiParticleSelectionEditorTool.cs.meta b/Assets/Obi/Editor/Common/Blueprints/BlueprintEditorTools/ObiParticleSelectionEditorTool.cs.meta
new file mode 100644
index 000000000..774ebafc2
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/BlueprintEditorTools/ObiParticleSelectionEditorTool.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: b3940c62f9ffe4808afc4d2d70ae5e28
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints/BlueprintEditorTools/ObiPropertyTextureEditorTool.cs b/Assets/Obi/Editor/Common/Blueprints/BlueprintEditorTools/ObiPropertyTextureEditorTool.cs
new file mode 100644
index 000000000..8ceee4b05
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/BlueprintEditorTools/ObiPropertyTextureEditorTool.cs
@@ -0,0 +1,166 @@
+using UnityEngine;
+using UnityEditor;
+using UnityEditorInternal;
+using System.Collections;
+using System;
+
+namespace Obi
+{
+ public class ObiPropertyTextureEditorTool : ObiBlueprintEditorTool
+ {
+ public enum TextureChannel
+ {
+ Red = 0,
+ Green = 1,
+ Blue = 2,
+ Alpha = 3,
+ }
+
+ protected bool selectionMask = false;
+ protected bool import = true;
+ protected bool export = true;
+
+ protected float minPropertyValue = 0;
+ protected float maxPropertyValue = 10;
+
+ protected int exportWidth = 512;
+ protected int exportHeight = 512;
+ protected int padding = 64;
+
+ protected Texture2D propertyTexture;
+ protected TextureChannel textureChannel;
+
+ protected ObiBlueprintFloatProperty floatProperty;
+ protected ObiBlueprintColorProperty colorProperty;
+ protected Action textureReadCallback;
+
+ public ObiMeshBasedActorBlueprintEditor meshBasedEditor
+ {
+ get { return editor as ObiMeshBasedActorBlueprintEditor; }
+ }
+
+ public ObiPropertyTextureEditorTool(ObiMeshBasedActorBlueprintEditor editor) : base(editor)
+ {
+ m_Icon = Resources.Load("TextureIcon");
+ m_Name = "Texture import/export";
+ }
+
+ public override string GetHelpString()
+ {
+ return "Import/export particle properties to textures. Assumes that your mesh has non-overlapping UVs.";
+ }
+
+ private void FloatFromTexture(int i, Color color)
+ {
+ if (!selectionMask || ObiActorBlueprintEditor.selectionStatus[i])
+ {
+ float value = minPropertyValue + color[(int)textureChannel] * (maxPropertyValue - minPropertyValue);
+ floatProperty.Set(i, value);
+ }
+ }
+
+ private void ColorFromTexture(int i, Color color)
+ {
+ if (!selectionMask || ObiActorBlueprintEditor.selectionStatus[i])
+ colorProperty.Set(i, color);
+ }
+
+ public override void OnInspectorGUI()
+ {
+ EditorGUILayout.BeginVertical(EditorStyles.inspectorDefaultMargins);
+ EditorGUILayout.Space();
+
+ EditorGUI.BeginChangeCheck();
+ editor.currentPropertyIndex = editor.PropertySelector(editor.currentPropertyIndex);
+ if (EditorGUI.EndChangeCheck())
+ editor.Refresh();
+
+ EditorGUILayout.EndVertical();
+
+ EditorGUILayout.Space();
+ GUILayout.Box(GUIContent.none, ObiEditorUtils.GetSeparatorLineStyle());
+
+ EditorGUILayout.BeginVertical(EditorStyles.inspectorDefaultMargins);
+ import = EditorGUILayout.BeginFoldoutHeaderGroup(import, "Import texture");
+
+ if (import)
+ {
+ propertyTexture = (Texture2D)EditorGUILayout.ObjectField("Source", propertyTexture, typeof(Texture2D), false);
+
+ floatProperty = editor.currentProperty as ObiBlueprintFloatProperty;
+ colorProperty = editor.currentProperty as ObiBlueprintColorProperty;
+
+ if (floatProperty != null)
+ {
+ textureReadCallback = FloatFromTexture;
+ textureChannel = (TextureChannel)EditorGUILayout.EnumPopup("Source channel", textureChannel);
+ minPropertyValue = EditorGUILayout.FloatField("Min value", minPropertyValue);
+ maxPropertyValue = EditorGUILayout.FloatField("Max value", maxPropertyValue);
+ }
+ else if (colorProperty != null)
+ {
+ textureReadCallback = ColorFromTexture;
+ }
+
+ if (GUILayout.Button("Import"))
+ {
+ Undo.RecordObject(editor.blueprint, "Import particle property");
+ if (!meshBasedEditor.ReadParticlePropertyFromTexture(propertyTexture, textureReadCallback))
+ {
+ EditorUtility.DisplayDialog("Invalid texture", "The texture is either null or not readable.", "Ok");
+ }
+
+ // force automatic range calculation for floating point properties.
+ if (floatProperty != null)
+ floatProperty.autoRange = true;
+ editor.Refresh();
+ }
+ }
+ EditorGUILayout.EndFoldoutHeaderGroup();
+ EditorGUILayout.EndVertical();
+
+ EditorGUILayout.Space();
+ GUILayout.Box(GUIContent.none, ObiEditorUtils.GetSeparatorLineStyle());
+
+ EditorGUILayout.BeginVertical(EditorStyles.inspectorDefaultMargins);
+ export = EditorGUILayout.BeginFoldoutHeaderGroup(export, "Export texture");
+
+ if (export)
+ {
+ exportWidth = EditorGUILayout.IntField("Texture width", exportWidth);
+ exportHeight = EditorGUILayout.IntField("Texture height", exportHeight);
+ padding = EditorGUILayout.IntField("Padding", padding);
+ if (GUILayout.Button("Export"))
+ {
+ var path = EditorUtility.SaveFilePanel("Save texture as PNG",
+ "",
+ "property.png",
+ "png");
+ if (path.Length > 0)
+ {
+ // force automatic range calculation for floating point properties.
+ if (floatProperty != null)
+ floatProperty.autoRange = true;
+ editor.Refresh();
+
+ if (!meshBasedEditor.WriteParticlePropertyToTexture(path, exportWidth, exportHeight, padding))
+ {
+ EditorUtility.DisplayDialog("Invalid path", "Could not write a texture to that location.", "Ok");
+ }
+ }
+ }
+ }
+
+ EditorGUILayout.EndFoldoutHeaderGroup();
+ EditorGUILayout.EndVertical();
+
+ EditorGUILayout.Space();
+ GUILayout.Box(GUIContent.none, ObiEditorUtils.GetSeparatorLineStyle());
+
+ EditorGUILayout.BeginVertical(EditorStyles.inspectorDefaultMargins);
+ editor.RenderModeSelector();
+ EditorGUILayout.EndVertical();
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/Assets/Obi/Editor/Common/Blueprints/BlueprintEditorTools/ObiPropertyTextureEditorTool.cs.meta b/Assets/Obi/Editor/Common/Blueprints/BlueprintEditorTools/ObiPropertyTextureEditorTool.cs.meta
new file mode 100644
index 000000000..0655a7673
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/BlueprintEditorTools/ObiPropertyTextureEditorTool.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 7727285b07aa44d6e8f65a8bc1f5d972
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints/BlueprintEditorTools/ObiTethersTool.cs b/Assets/Obi/Editor/Common/Blueprints/BlueprintEditorTools/ObiTethersTool.cs
new file mode 100644
index 000000000..a1e4d29fe
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/BlueprintEditorTools/ObiTethersTool.cs
@@ -0,0 +1,86 @@
+using UnityEngine;
+using UnityEditor;
+using System;
+
+
+namespace Obi
+{
+ public class ObiTethersTool
+ {
+ protected Rect tetherDropdownRect;
+ protected bool[] tetheredGroups = new bool[0];
+
+ // the GenericMenu.MenuFunction2 event handler for when a menu item is selected
+ void OnTetherGroupSelected(object index)
+ {
+ int i = (int)index;
+ tetheredGroups[i] = !tetheredGroups[i];
+ }
+
+ public void DoTethers(ObiActorBlueprintEditor editor)
+ {
+ EditorGUILayout.LabelField("Tethers", EditorStyles.boldLabel);
+
+ var tethers = editor.blueprint.GetConstraintsByType(Oni.ConstraintType.Tether);
+ int tetherCount = 0;
+ if (tethers != null)
+ tetherCount = tethers.GetConstraintCount();
+
+ if (tetherCount > 0)
+ EditorGUILayout.LabelField("" + tetherCount + " tether constraints.", EditorStyles.helpBox);
+ else
+ EditorGUILayout.LabelField("No tether constraints. Select at least one particle group in the dropdown, then click 'Generate Tethers'.", EditorStyles.helpBox);
+
+ Array.Resize(ref tetheredGroups, editor.blueprint.groups.Count);
+
+ // display the GenericMenu when pressing a button
+ if (GUILayout.Button("Tethered groups", EditorStyles.popup))
+ {
+ // create the menu and add items to it
+ GenericMenu menu = new GenericMenu();
+
+ // forward slashes nest menu items under submenus
+ for (int i = 0; i < editor.blueprint.groups.Count; ++i)
+ {
+ menu.AddItem(new GUIContent(editor.blueprint.groups[i].name), tetheredGroups[i], OnTetherGroupSelected, i);
+ }
+
+ // display the menu
+ menu.DropDown(tetherDropdownRect);
+ }
+
+ if (Event.current.type == EventType.Repaint)
+ tetherDropdownRect = GUILayoutUtility.GetLastRect();
+
+
+ EditorGUILayout.BeginHorizontal();
+ if (GUILayout.Button("Generate tethers",GUILayout.MinHeight(32)))
+ {
+ // Select all particles in the tethered groups:
+ for (int i = 0; i < ObiActorBlueprintEditor.selectionStatus.Length; ++i)
+ {
+ ObiActorBlueprintEditor.selectionStatus[i] = false;
+ for (int j = 0; j < tetheredGroups.Length; ++j)
+ {
+ if (tetheredGroups[j] && editor.blueprint.groups[j].ContainsParticle(i))
+ {
+ ObiActorBlueprintEditor.selectionStatus[i] = true;
+ break;
+ }
+ }
+ }
+
+ editor.blueprint.GenerateTethers(ObiActorBlueprintEditor.selectionStatus);
+ editor.Refresh();
+ }
+
+ if (GUILayout.Button("Clear tethers",GUILayout.MinHeight(32)))
+ {
+ editor.blueprint.ClearTethers();
+ editor.Refresh();
+ }
+ EditorGUILayout.EndHorizontal();
+
+ }
+ }
+}
diff --git a/Assets/Obi/Editor/Common/Blueprints/BlueprintEditorTools/ObiTethersTool.cs.meta b/Assets/Obi/Editor/Common/Blueprints/BlueprintEditorTools/ObiTethersTool.cs.meta
new file mode 100644
index 000000000..fd2ba16fb
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/BlueprintEditorTools/ObiTethersTool.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 6aefc9e7e74be461e93ee58f15c5a1dd
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints/Brushes.meta b/Assets/Obi/Editor/Common/Blueprints/Brushes.meta
new file mode 100644
index 000000000..23624c350
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Brushes.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 625a6e0c1ba72483190830373b7b45fe
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes.meta b/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes.meta
new file mode 100644
index 000000000..9bdbd1de6
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 4fc4d44dc6d334c2985875fc6f7b8cb1
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/IObiBrushMode.cs b/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/IObiBrushMode.cs
new file mode 100644
index 000000000..4257fe690
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/IObiBrushMode.cs
@@ -0,0 +1,9 @@
+namespace Obi
+{
+ public interface IObiBrushMode
+ {
+ string name{get;}
+ bool needsInputValue{ get; }
+ void ApplyStamps(ObiBrushBase brush, bool modified);
+ }
+}
diff --git a/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/IObiBrushMode.cs.meta b/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/IObiBrushMode.cs.meta
new file mode 100644
index 000000000..ab2580d12
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/IObiBrushMode.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 4c46364da0f1641c7ab84e12348a6a4b
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiColorPaintBrushMode.cs b/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiColorPaintBrushMode.cs
new file mode 100644
index 000000000..e094e7c17
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiColorPaintBrushMode.cs
@@ -0,0 +1,38 @@
+using UnityEngine;
+
+namespace Obi
+{
+ public class ObiColorPaintBrushMode : IObiBrushMode
+ {
+ ObiBlueprintColorProperty property;
+
+ public ObiColorPaintBrushMode(ObiBlueprintColorProperty property)
+ {
+ this.property = property;
+ }
+
+ public string name
+ {
+ get { return "Paint"; }
+ }
+
+ public bool needsInputValue
+ {
+ get { return true; }
+ }
+
+ public void ApplyStamps(ObiBrushBase brush, bool modified)
+ {
+ for (int i = 0; i < brush.weights.Length; ++i)
+ {
+ if (!property.Masked(i) && brush.weights[i] > 0)
+ {
+ Color currentValue = property.Get(i);
+ Color delta = brush.weights[i] * brush.opacity * brush.speed * (property.GetDefault() - currentValue);
+
+ property.Set(i, currentValue + delta * (modified ? -1 : 1));
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiColorPaintBrushMode.cs.meta b/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiColorPaintBrushMode.cs.meta
new file mode 100644
index 000000000..d9fe60146
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiColorPaintBrushMode.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 1fd033c8f79b1494d8b8de5c8311f8c1
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiColorSmoothBrushMode.cs b/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiColorSmoothBrushMode.cs
new file mode 100644
index 000000000..a5fd9c632
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiColorSmoothBrushMode.cs
@@ -0,0 +1,53 @@
+using UnityEngine;
+
+namespace Obi
+{
+ public class ObiColorSmoothBrushMode : IObiBrushMode
+ {
+ ObiBlueprintColorProperty property;
+
+ public ObiColorSmoothBrushMode(ObiBlueprintColorProperty property)
+ {
+ this.property = property;
+ }
+
+ public string name
+ {
+ get { return "Smooth"; }
+ }
+
+ public bool needsInputValue
+ {
+ get { return false; }
+ }
+
+ public void ApplyStamps(ObiBrushBase brush, bool modified)
+ {
+ Color averageValue = Color.black;
+ float totalWeight = 0;
+
+ for (int i = 0; i < brush.weights.Length; ++i)
+ {
+ if (!property.Masked(i) && brush.weights[i] > 0)
+ {
+ averageValue += property.Get(i) * brush.weights[i];
+ totalWeight += brush.weights[i];
+ }
+
+ }
+ averageValue /= totalWeight;
+
+ for (int i = 0; i < brush.weights.Length; ++i)
+ {
+ if (!property.Masked(i) && brush.weights[i] > 0)
+ {
+ Color currentValue = property.Get(i);
+ Color delta = brush.opacity * brush.speed * (Color.Lerp(currentValue, averageValue, brush.weights[i]) - currentValue);
+
+ property.Set(i, currentValue + delta * (modified ? -1 : 1));
+ }
+ }
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiColorSmoothBrushMode.cs.meta b/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiColorSmoothBrushMode.cs.meta
new file mode 100644
index 000000000..8a0a75a71
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiColorSmoothBrushMode.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: a69a8a1614478445cbb770a5e123ab18
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiFloatAddBrushMode.cs b/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiFloatAddBrushMode.cs
new file mode 100644
index 000000000..8c2a5aa81
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiFloatAddBrushMode.cs
@@ -0,0 +1,36 @@
+namespace Obi
+{
+ public class ObiFloatAddBrushMode : IObiBrushMode
+ {
+ ObiBlueprintFloatProperty property;
+
+ public ObiFloatAddBrushMode(ObiBlueprintFloatProperty property)
+ {
+ this.property = property;
+ }
+
+ public string name
+ {
+ get { return "Add"; }
+ }
+
+ public bool needsInputValue
+ {
+ get { return true; }
+ }
+
+ public void ApplyStamps(ObiBrushBase brush, bool modified)
+ {
+ for (int i = 0; i < brush.weights.Length; ++i)
+ {
+ if (!property.Masked(i) && brush.weights[i] > 0)
+ {
+ float currentValue = property.Get(i);
+ float delta = brush.weights[i] * brush.opacity * brush.speed * property.GetDefault();
+
+ property.Set(i, currentValue + delta * (modified ? -1 : 1));
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiFloatAddBrushMode.cs.meta b/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiFloatAddBrushMode.cs.meta
new file mode 100644
index 000000000..66272b907
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiFloatAddBrushMode.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 8b39e10cedc94461083b3b19c3ddb343
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiFloatCopyBrushMode.cs b/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiFloatCopyBrushMode.cs
new file mode 100644
index 000000000..ae0b60fee
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiFloatCopyBrushMode.cs
@@ -0,0 +1,42 @@
+namespace Obi
+{
+ public class ObiFloatCopyBrushMode : IObiBrushMode
+ {
+ ObiBlueprintFloatProperty property;
+ public ObiBlueprintFloatProperty source;
+
+ public ObiFloatCopyBrushMode(ObiBlueprintFloatProperty property, ObiBlueprintFloatProperty source)
+ {
+ this.property = property;
+ this.source = source;
+ }
+
+ public string name
+ {
+ get { return "Copy"; }
+ }
+
+ public bool needsInputValue
+ {
+ get { return false; }
+ }
+
+ public void ApplyStamps(ObiBrushBase brush, bool modified)
+ {
+ if (property != null && source != null)
+ {
+ for (int i = 0; i < brush.weights.Length; ++i)
+ {
+ if (!property.Masked(i) && brush.weights[i] > 0)
+ {
+ float currentValue = property.Get(i);
+ float sourceValue = source.Get(i);
+ float delta = brush.weights[i] * brush.opacity * brush.speed * (sourceValue - currentValue);
+
+ property.Set(i, currentValue + delta * (modified ? -1 : 1));
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiFloatCopyBrushMode.cs.meta b/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiFloatCopyBrushMode.cs.meta
new file mode 100644
index 000000000..a51236b78
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiFloatCopyBrushMode.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 95bb470841f42415ab256cd64adb9242
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiFloatPaintBrushMode.cs b/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiFloatPaintBrushMode.cs
new file mode 100644
index 000000000..369a0d1e2
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiFloatPaintBrushMode.cs
@@ -0,0 +1,37 @@
+
+namespace Obi
+{
+ public class ObiFloatPaintBrushMode : IObiBrushMode
+ {
+ ObiBlueprintFloatProperty property;
+
+ public ObiFloatPaintBrushMode(ObiBlueprintFloatProperty property)
+ {
+ this.property = property;
+ }
+
+ public string name
+ {
+ get { return "Paint"; }
+ }
+
+ public bool needsInputValue
+ {
+ get { return true; }
+ }
+
+ public void ApplyStamps(ObiBrushBase brush, bool modified)
+ {
+ for (int i = 0; i < brush.weights.Length; ++i)
+ {
+ if (!property.Masked(i) && brush.weights[i] > 0)
+ {
+ float currentValue = property.Get(i);
+ float delta = brush.weights[i] * brush.opacity * brush.speed * (property.GetDefault() - currentValue);
+
+ property.Set(i, currentValue + delta * (modified ? -1 : 1));
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiFloatPaintBrushMode.cs.meta b/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiFloatPaintBrushMode.cs.meta
new file mode 100644
index 000000000..94c33004a
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiFloatPaintBrushMode.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: eb3d176006d404a508bef284d2701ab0
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiFloatSmoothBrushMode.cs b/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiFloatSmoothBrushMode.cs
new file mode 100644
index 000000000..35cfcdbc5
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiFloatSmoothBrushMode.cs
@@ -0,0 +1,55 @@
+using UnityEngine;
+
+namespace Obi
+{
+ public class ObiFloatSmoothBrushMode : IObiBrushMode
+ {
+ ObiBlueprintFloatProperty property;
+
+ public ObiFloatSmoothBrushMode(ObiBlueprintFloatProperty property)
+ {
+ this.property = property;
+ }
+
+ public string name
+ {
+ get { return "Smooth"; }
+ }
+
+ public bool needsInputValue
+ {
+ get { return false; }
+ }
+
+ public void ApplyStamps(ObiBrushBase brush, bool modified)
+ {
+ var floatProperty = (ObiBlueprintFloatProperty)property;
+
+ float averageValue = 0;
+ float totalWeight = 0;
+
+ for (int i = 0; i < brush.weights.Length; ++i)
+ {
+ if (!property.Masked(i) && brush.weights[i] > 0)
+ {
+ averageValue += floatProperty.Get(i) * brush.weights[i];
+ totalWeight += brush.weights[i];
+ }
+
+ }
+ averageValue /= totalWeight;
+
+ for (int i = 0; i < brush.weights.Length; ++i)
+ {
+ if (!property.Masked(i) && brush.weights[i] > 0)
+ {
+ float currentValue = floatProperty.Get(i);
+ float delta = brush.opacity * brush.speed * (Mathf.Lerp(currentValue,averageValue,brush.weights[i]) - currentValue);
+
+ floatProperty.Set(i, currentValue + delta * (modified ? -1 : 1));
+ }
+ }
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiFloatSmoothBrushMode.cs.meta b/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiFloatSmoothBrushMode.cs.meta
new file mode 100644
index 000000000..d3a486a2e
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiFloatSmoothBrushMode.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 63dad56a994af4db7bb3449382022c54
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiIntPaintBrushMode.cs b/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiIntPaintBrushMode.cs
new file mode 100644
index 000000000..426e4c680
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiIntPaintBrushMode.cs
@@ -0,0 +1,33 @@
+namespace Obi
+{
+ public class ObiIntPaintBrushMode : IObiBrushMode
+ {
+ ObiBlueprintIntProperty property;
+
+ public ObiIntPaintBrushMode(ObiBlueprintIntProperty property)
+ {
+ this.property = property;
+ }
+
+ public string name
+ {
+ get { return "Paint"; }
+ }
+
+ public bool needsInputValue
+ {
+ get { return true; }
+ }
+
+ public void ApplyStamps(ObiBrushBase brush, bool modified)
+ {
+ for (int i = 0; i < brush.weights.Length; ++i)
+ {
+ if (!property.Masked(i) && brush.weights[i] > (1 - brush.opacity))
+ {
+ property.Set(i, property.GetDefault());
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiIntPaintBrushMode.cs.meta b/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiIntPaintBrushMode.cs.meta
new file mode 100644
index 000000000..0bef4606e
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiIntPaintBrushMode.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: d8882849c81104cef80b3dfdab2021c9
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiMasterSlavePaintBrushMode.cs b/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiMasterSlavePaintBrushMode.cs
new file mode 100644
index 000000000..2691275af
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiMasterSlavePaintBrushMode.cs
@@ -0,0 +1,39 @@
+namespace Obi
+{
+ public class ObiMasterSlavePaintBrushMode : IObiBrushMode
+ {
+ ObiBlueprintIntProperty property;
+
+ public ObiMasterSlavePaintBrushMode(ObiBlueprintIntProperty property)
+ {
+ this.property = property;
+ }
+
+ public string name
+ {
+ get { return "Master/Slave paint"; }
+ }
+
+ public bool needsInputValue
+ {
+ get { return true; }
+ }
+
+ public void ApplyStamps(ObiBrushBase brush, bool modified)
+ {
+ for (int i = 0; i < brush.weights.Length; ++i)
+ {
+ if (!property.Masked(i) && brush.weights[i] > (1 - brush.opacity))
+ {
+ int currentValue = property.Get(i);
+
+ if (modified)
+ currentValue &= ~(int)(1 << property.GetDefault());
+ else currentValue |= (int)(1 << property.GetDefault());
+
+ property.Set(i, currentValue);
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiMasterSlavePaintBrushMode.cs.meta b/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiMasterSlavePaintBrushMode.cs.meta
new file mode 100644
index 000000000..83254b41c
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiMasterSlavePaintBrushMode.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 62f8e9adfc17440359a9b51005cd0948
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiSelectBrushMode.cs b/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiSelectBrushMode.cs
new file mode 100644
index 000000000..66d732c00
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiSelectBrushMode.cs
@@ -0,0 +1,33 @@
+namespace Obi
+{
+ public class ObiSelectBrushMode : IObiBrushMode
+ {
+ ObiBlueprintSelected property;
+ string customName;
+
+ public ObiSelectBrushMode(ObiBlueprintSelected property, string customName = "Select")
+ {
+ this.property = property;
+ this.customName = customName;
+ }
+
+ public string name
+ {
+ get { return customName; }
+ }
+
+ public bool needsInputValue
+ {
+ get { return true; }
+ }
+
+ public void ApplyStamps(ObiBrushBase brush, bool modified)
+ {
+ for (int i = 0; i < brush.weights.Length; ++i)
+ {
+ if (brush.weights[i] > 0 && !property.Masked(i))
+ property.Set(i,!modified);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiSelectBrushMode.cs.meta b/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiSelectBrushMode.cs.meta
new file mode 100644
index 000000000..ed3edeabf
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Brushes/BrushModes/ObiSelectBrushMode.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 9cea7ef42253f4d2b9b5a222521cdee8
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints/Brushes/ObiBrushBase.cs b/Assets/Obi/Editor/Common/Blueprints/Brushes/ObiBrushBase.cs
new file mode 100644
index 000000000..37951d48c
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Brushes/ObiBrushBase.cs
@@ -0,0 +1,161 @@
+using UnityEngine;
+using UnityEditor;
+using System;
+
+namespace Obi
+{
+
+ public abstract class ObiBrushBase
+ {
+ static int particleBrushHash = "ObiBrushHash".GetHashCode();
+
+ public IObiBrushMode brushMode;
+ public float radius = 1;
+ public float innerRadius = 0.5f;
+ public float opacity = 1;
+ public float[] weights = new float[0];
+ public bool drag = true;
+ public float speed = 0.1f;
+
+ protected int controlID;
+ protected Action onStrokeStart;
+ protected Action onStrokeUpdate;
+ protected Action onStrokeEnd;
+
+ public float SqrRadius
+ {
+ get{ return radius * radius; }
+ }
+
+ public ObiBrushBase(Action onStrokeStart, Action onStrokeUpdate, Action onStrokeEnd)
+ {
+ this.onStrokeStart = onStrokeStart;
+ this.onStrokeUpdate = onStrokeUpdate;
+ this.onStrokeEnd = onStrokeEnd;
+ }
+
+ protected virtual float WeightFromDistance(float distance)
+ {
+ // anything outside the brush should have zero weight:
+ if (distance > radius)
+ return 0;
+
+ float t = Mathf.InverseLerp(innerRadius * radius, radius, distance);
+ return Mathf.SmoothStep(1, 0, t);
+ }
+
+ protected abstract void GenerateWeights(Vector3[] positions);
+
+ protected virtual void OnMouseDown(Vector3[] positions)
+ {
+ if (Event.current.button != 0 || (Event.current.modifiers & ~EventModifiers.Shift) != EventModifiers.None)
+ return;
+
+ GUIUtility.hotControl = controlID;
+
+ GenerateWeights(positions);
+
+ if (onStrokeStart != null)
+ onStrokeStart();
+
+ if (brushMode != null)
+ brushMode.ApplyStamps(this, (Event.current.modifiers & EventModifiers.Shift) != 0);
+
+ if (onStrokeUpdate != null)
+ onStrokeUpdate();
+
+ Event.current.Use();
+ }
+
+ protected virtual void OnMouseMove(Vector3[] positions)
+ {
+
+ }
+
+ protected virtual void OnMouseDrag(Vector3[] positions)
+ {
+
+ if (GUIUtility.hotControl == controlID && drag)
+ {
+
+ GenerateWeights(positions);
+
+ if (brushMode != null)
+ brushMode.ApplyStamps(this, (Event.current.modifiers & EventModifiers.Shift) != 0);
+
+ if (onStrokeUpdate != null)
+ onStrokeUpdate();
+
+ Event.current.Use();
+
+ }
+ }
+
+ protected virtual void OnMouseUp(Vector3[] positions)
+ {
+ if (GUIUtility.hotControl == controlID)
+ {
+
+ GUIUtility.hotControl = 0;
+ Event.current.Use();
+
+ if (onStrokeEnd != null)
+ onStrokeEnd();
+ }
+ }
+
+ protected virtual void OnRepaint()
+ {
+ }
+
+ public void DoBrush(Vector3[] positions)
+ {
+
+ Matrix4x4 cachedMatrix = Handles.matrix;
+
+ controlID = GUIUtility.GetControlID(particleBrushHash, FocusType.Passive);
+ Array.Resize(ref weights, positions.Length);
+
+ switch (Event.current.GetTypeForControl(controlID))
+ {
+
+ case EventType.MouseDown:
+
+ OnMouseDown(positions);
+
+ break;
+
+ case EventType.MouseMove:
+
+ OnMouseMove(positions);
+
+ SceneView.RepaintAll();
+ break;
+
+ case EventType.MouseDrag:
+
+ OnMouseDrag(positions);
+
+ break;
+
+ case EventType.MouseUp:
+
+ OnMouseUp(positions);
+
+ break;
+
+ case EventType.Repaint:
+
+ Handles.matrix = Matrix4x4.identity;
+
+ OnRepaint();
+
+ Handles.matrix = cachedMatrix;
+
+ break;
+
+ }
+ }
+ }
+}
+
diff --git a/Assets/Obi/Editor/Common/Blueprints/Brushes/ObiBrushBase.cs.meta b/Assets/Obi/Editor/Common/Blueprints/Brushes/ObiBrushBase.cs.meta
new file mode 100644
index 000000000..692767df9
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Brushes/ObiBrushBase.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 094253962d646436792561e708e62376
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints/Brushes/ObiBrushMirrorSettings.cs b/Assets/Obi/Editor/Common/Blueprints/Brushes/ObiBrushMirrorSettings.cs
new file mode 100644
index 000000000..c4bd65c1d
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Brushes/ObiBrushMirrorSettings.cs
@@ -0,0 +1,51 @@
+using System;
+using UnityEngine;
+
+[Serializable]
+public struct ObiBrushMirrorSettings
+{
+ [Flags]
+ public enum MirrorAxis
+ {
+ None = 0x0,
+ X = 0x1,
+ Y = 0x2,
+ Z = 0x4
+ }
+
+ public enum MirrorSpace
+ {
+ World = 0,
+ Camera = 1
+ }
+
+ public MirrorAxis axis;
+ public MirrorSpace space;
+
+ public Vector3 ToAxis()
+ {
+ uint m = (uint)axis;
+
+ bool xMirror = (m & (uint)MirrorAxis.X) > 0;
+ bool yMirror = (m & (uint)MirrorAxis.Y) > 0;
+ bool zMirror = (m & (uint)MirrorAxis.Z) > 0;
+
+ if (axis < 0 || ((int)axis > (int)MirrorAxis.X + (int)MirrorAxis.Y + (int)MirrorAxis.Z))
+ {
+ return Vector3.one;
+ }
+
+ Vector3 reflection = Vector3.one;
+
+ if (xMirror)
+ reflection.x = -1f;
+
+ if (yMirror)
+ reflection.y = -1f;
+
+ if (zMirror)
+ reflection.z = -1f;
+
+ return reflection;
+ }
+}
diff --git a/Assets/Obi/Editor/Common/Blueprints/Brushes/ObiBrushMirrorSettings.cs.meta b/Assets/Obi/Editor/Common/Blueprints/Brushes/ObiBrushMirrorSettings.cs.meta
new file mode 100644
index 000000000..d33b4379e
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Brushes/ObiBrushMirrorSettings.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: d10a9257ac23248418439eb80e02a611
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints/Brushes/ObiRaycastBrush.cs b/Assets/Obi/Editor/Common/Blueprints/Brushes/ObiRaycastBrush.cs
new file mode 100644
index 000000000..0578e888f
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Brushes/ObiRaycastBrush.cs
@@ -0,0 +1,125 @@
+using UnityEngine;
+using UnityEditor;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace Obi
+{
+
+ public class ObiRaycastBrush : ObiBrushBase
+ {
+ public Matrix4x4 raycastTransform = Matrix4x4.identity;
+ public Mesh raycastTarget = null;
+ public bool drawVolume = false;
+ private List rays = new List();
+ private List hits = new List();
+
+ public ObiBrushMirrorSettings mirror;
+
+ public ObiRaycastBrush(Mesh raycastTarget, Action onStrokeStart, Action onStrokeUpdate, Action onStrokeEnd) : base(onStrokeStart, onStrokeUpdate, onStrokeEnd)
+ {
+ radius = 0.1f;
+ this.raycastTarget = raycastTarget;
+ rays = new List();
+ }
+
+ protected override void GenerateWeights(Vector3[] positions)
+ {
+ if (raycastTarget != null)
+ {
+ rays.Clear();
+ hits.Clear();
+
+ for (int i = 0; i < positions.Length; i++)
+ weights[i] = 0;
+
+ var vertices = raycastTarget.vertices;
+ var triangles = raycastTarget.triangles;
+
+ Ray mouseRay = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);
+ rays.Add(mouseRay);
+
+ ObiBrushMirrorSettings currentAxis = mirror;
+
+ if (mirror.axis != ObiBrushMirrorSettings.MirrorAxis.None)
+ {
+ for (int i = 0; i < 3; i++)
+ {
+ currentAxis.axis = (ObiBrushMirrorSettings.MirrorAxis)(1u << i);
+ if (((uint)mirror.axis & (1u << i)) < 1)
+ continue;
+
+ Vector3 mirrorVector = currentAxis.ToAxis();
+
+ if (currentAxis.space == ObiBrushMirrorSettings.MirrorSpace.World)
+ {
+ Vector3 center = raycastTarget.bounds.center;
+ rays.Add(new Ray(Vector3.Scale(mouseRay.origin - center, mirrorVector) + center,
+ Vector3.Scale(mouseRay.direction, mirrorVector)));
+ }
+ else
+ {
+ Transform t = SceneView.lastActiveSceneView.camera.transform;
+ Vector3 o = t.InverseTransformPoint(mouseRay.origin);
+ Vector3 d = t.InverseTransformDirection(mouseRay.direction);
+ rays.Add(new Ray(t.TransformPoint(Vector3.Scale(o, mirrorVector)),
+ t.TransformDirection(Vector3.Scale(d, mirrorVector))));
+ }
+ }
+ }
+
+ foreach (var ray in rays)
+ {
+ if (ObiMeshUtils.WorldRaycast(ray, raycastTransform, vertices, triangles, out ObiRaycastHit hit))
+ {
+ hit.position = raycastTransform.MultiplyPoint3x4(hit.position);
+ hit.normal = raycastTransform.MultiplyVector(hit.normal);
+ hits.Add(hit);
+
+ for (int i = 0; i < positions.Length; i++)
+ {
+ // get distance from hit position to particle position:
+ float weight = WeightFromDistance(Vector3.Distance(hit.position, positions[i]));
+ weights[i] = Mathf.Max(weights[i], weight);
+ }
+ }
+ }
+ }
+ }
+
+ protected override void OnMouseMove(Vector3[] positions)
+ {
+ base.OnMouseMove(positions);
+ GenerateWeights(positions);
+ }
+
+ protected override void OnRepaint()
+ {
+ base.OnRepaint();
+
+ if (raycastTarget != null)
+ {
+ Color brushColor = ObiEditorSettings.GetOrCreateSettings().brushColor;
+
+ foreach (var hit in hits)
+ {
+ if (hit != null && hit.triangle >= 0)
+ {
+ Handles.color = brushColor;
+ Handles.DrawLine(hit.position, hit.position + hit.normal.normalized * radius);
+ Handles.DrawWireDisc(hit.position, hit.normal, radius);
+ Handles.DrawWireDisc(hit.position, hit.normal, innerRadius * radius);
+
+ if (drawVolume)
+ {
+ Handles.color = new Color(brushColor.r, brushColor.g, brushColor.b, 0.2f);
+ Handles.SphereHandleCap(0, hit.position, Quaternion.identity, radius * 2, EventType.Repaint);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
diff --git a/Assets/Obi/Editor/Common/Blueprints/Brushes/ObiRaycastBrush.cs.meta b/Assets/Obi/Editor/Common/Blueprints/Brushes/ObiRaycastBrush.cs.meta
new file mode 100644
index 000000000..d3e4fb086
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Brushes/ObiRaycastBrush.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: d925323750dca4dcaa5cca91b18521b5
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints/Brushes/ObiScreenSpaceBrush.cs b/Assets/Obi/Editor/Common/Blueprints/Brushes/ObiScreenSpaceBrush.cs
new file mode 100644
index 000000000..341b491bb
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Brushes/ObiScreenSpaceBrush.cs
@@ -0,0 +1,61 @@
+using UnityEngine;
+using UnityEditor;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace Obi
+{
+
+ public class ObiScreenSpaceBrush : ObiBrushBase
+ {
+ public ObiScreenSpaceBrush(Action onStrokeStart, Action onStrokeUpdate, Action onStrokeEnd) : base(onStrokeStart, onStrokeUpdate, onStrokeEnd)
+ {
+ radius = 32;
+ }
+
+ protected override float WeightFromDistance(float distance)
+ {
+ // anything outside the brush should have zero weight:
+ if (distance * EditorGUIUtility.pixelsPerPoint > radius)
+ return 0;
+ return 1;
+ }
+
+ protected override void GenerateWeights(Vector3[] positions)
+ {
+ for (int i = 0; i < positions.Length; i++)
+ {
+ // get particle position in gui space:
+ Vector2 pos = HandleUtility.WorldToGUIPoint(positions[i]);
+
+ // get distance from mouse position to particle position:
+ weights[i] = WeightFromDistance(Vector3.Distance(Event.current.mousePosition, pos));
+ }
+ }
+
+ protected override void OnRepaint()
+ {
+ base.OnRepaint();
+
+ Camera cam = Camera.current;
+ float depth = (cam.nearClipPlane + cam.farClipPlane) * 0.5f;
+
+ float ppp = EditorGUIUtility.pixelsPerPoint;
+ Vector2 mousePos = new Vector2(Event.current.mousePosition.x * ppp,
+ cam.pixelHeight - Event.current.mousePosition.y * ppp);
+
+ Handles.color = ObiEditorSettings.GetOrCreateSettings().brushColor;
+ Vector3 point = new Vector3(mousePos.x, mousePos.y, depth);
+ Vector3 wsPoint = cam.ScreenToWorldPoint(point);
+
+ var p1 = cam.ScreenToWorldPoint(new Vector3(1, 0, depth));
+ var p2 = cam.ScreenToWorldPoint(new Vector3(0, 0, depth));
+ float units = Vector3.Distance(p1, p2);
+
+ Handles.DrawWireDisc(wsPoint, cam.transform.forward, radius * units);
+ }
+
+ }
+}
+
diff --git a/Assets/Obi/Editor/Common/Blueprints/Brushes/ObiScreenSpaceBrush.cs.meta b/Assets/Obi/Editor/Common/Blueprints/Brushes/ObiScreenSpaceBrush.cs.meta
new file mode 100644
index 000000000..71c3ff401
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Brushes/ObiScreenSpaceBrush.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 38fc5288fb3c94ebeb7eaa88a3bc5119
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints/ObiActorBlueprintEditor.cs b/Assets/Obi/Editor/Common/Blueprints/ObiActorBlueprintEditor.cs
new file mode 100644
index 000000000..0e819c697
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/ObiActorBlueprintEditor.cs
@@ -0,0 +1,477 @@
+using UnityEngine;
+using UnityEngine.Rendering;
+using UnityEditor;
+using UnityEngine.SceneManagement;
+using UnityEditor.SceneManagement;
+using System.Collections;
+using System.Collections.Generic;
+using System;
+using System.Linq;
+
+namespace Obi
+{
+
+ [CustomEditor(typeof(ObiActorBlueprint), true)]
+ public class ObiActorBlueprintEditor : Editor, IObiSelectableParticleProvider
+ {
+ public List tools = new List();
+ public int currentToolIndex = 0;
+
+ public List properties = new List();
+ public int currentPropertyIndex = 0;
+
+ public List renderModes = new List();
+ public int renderModeFlags = 0;
+ BooleanPreference showRenderModes;
+
+ public bool autoGenerate = false;
+ public bool editMode = false;
+ public bool isEditing = false;
+ protected UnityEngine.Object oldSelection;
+
+ //Additional status info for all particles:
+ public static float dotRadiusScale = 1;
+ public static int selectedCount = 0;
+ public static int activeParticle = -1;
+ public static bool[] selectionStatus = new bool[0];
+
+ public bool[] visible = new bool[0];
+ public Color[] tint = new Color[0];
+ protected float[] sqrDistanceToCamera = new float[0];
+ public int[] sortedIndices = new int[0];
+
+ public ObiActorBlueprint blueprint
+ {
+ get { return target as ObiActorBlueprint; }
+ }
+
+ public ObiBlueprintPropertyBase currentProperty
+ {
+ get { return GetProperty(currentPropertyIndex); }
+ }
+
+ public ObiBlueprintEditorTool currentTool
+ {
+ get { return GetTool(currentToolIndex); }
+ }
+
+ public override bool UseDefaultMargins()
+ {
+ return false;
+ }
+
+ public ObiBlueprintPropertyBase GetProperty(int index)
+ {
+ return (properties.Count > index && index >= 0) ? properties[index] : null;
+ }
+
+ public ObiBlueprintEditorTool GetTool(int index)
+ {
+ return (tools.Count > index && index >= 0) ? tools[index] : null;
+ }
+
+#if (UNITY_2019_1_OR_NEWER)
+ System.Action renderCallback;
+#endif
+
+ public virtual void OnEnable()
+ {
+ properties.Clear();
+ renderModes.Clear();
+ tools.Clear();
+
+ properties.Add(new ObiBlueprintMass(this));
+ properties.Add(new ObiBlueprintRadius(this));
+ properties.Add(new ObiBlueprintFilterCategory(this));
+ properties.Add(new ObiBlueprintFilterMask(this));
+
+ renderModes.Add(new ObiBlueprintRenderModeParticles(this));
+ showRenderModes = new BooleanPreference($"{target.GetType()}.showRenderModes", false);
+
+#if (UNITY_2019_1_OR_NEWER)
+ renderCallback = new System.Action((cntxt, cam) => { DrawWithCamera(cam); });
+ RenderPipelineManager.beginCameraRendering += renderCallback;
+#endif
+ Camera.onPreCull += DrawWithCamera;
+ SceneView.duringSceneGui += OnSceneGUI;
+
+ EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
+ }
+
+ public virtual void OnDisable()
+ {
+ ExitBlueprintEditMode();
+
+#if (UNITY_2019_1_OR_NEWER)
+ RenderPipelineManager.beginCameraRendering -= renderCallback;
+#endif
+ Camera.onPreCull -= DrawWithCamera;
+ SceneView.duringSceneGui -= OnSceneGUI;
+ EditorApplication.playModeStateChanged -= OnPlayModeStateChanged;
+
+ foreach (var tool in tools)
+ {
+ tool.OnDisable();
+ tool.OnDestroy();
+ }
+
+ foreach (var renderMode in renderModes)
+ {
+ renderMode.OnDestroy();
+ }
+ }
+
+ void OnPlayModeStateChanged(PlayModeStateChange playmodeState)
+ {
+ if (playmodeState == PlayModeStateChange.ExitingEditMode)
+ {
+ if (StageUtility.GetCurrentStage() is ObiActorBlueprintEditorStage)
+ StageUtility.GoToMainStage();
+ }
+ }
+
+ protected bool Generate()
+ {
+ if (!blueprint.edited)
+ {
+ EditorUtility.SetDirty(target);
+ CoroutineJob job = new CoroutineJob();
+ IEnumerator routine = job.Start(blueprint.Generate());
+ EditorCoroutine.ShowCoroutineProgressBar("Generating blueprint...", routine);
+ Refresh();
+ EditorGUIUtility.ExitGUI();
+ }
+ else
+ {
+ if (EditorUtility.DisplayDialog("Blueprint generation", "This blueprint contains manually edited data. If you regenerate the blueprint, these changes will be lost. Are you sure you want to proceed?", "Ok", "Cancel"))
+ {
+ EditorUtility.SetDirty(target);
+ CoroutineJob job = new CoroutineJob();
+ IEnumerator routine = job.Start(blueprint.Generate());
+ EditorCoroutine.ShowCoroutineProgressBar("Generating blueprint...", routine);
+ Refresh();
+ EditorGUIUtility.ExitGUI();
+ }
+ else return false;
+ }
+ return true;
+ }
+
+ protected virtual bool ValidateBlueprint() { return true; }
+
+ private void DrawGenerationControls()
+ {
+ GUILayout.BeginHorizontal();
+
+ float originalLabelWidth = EditorGUIUtility.labelWidth;
+ EditorGUIUtility.labelWidth = 72;
+ autoGenerate = EditorGUILayout.ToggleLeft("Auto Generate", autoGenerate, GUILayout.ExpandWidth(false));
+ EditorGUIUtility.labelWidth = originalLabelWidth;
+
+ GUI.enabled = !autoGenerate;
+ if (GUILayout.Button("Generate", GUI.skin.FindStyle("LargeButton"), GUILayout.Height(32)))
+ Generate();
+
+ GUILayout.EndHorizontal();
+ }
+
+ public override void OnInspectorGUI()
+ {
+ serializedObject.UpdateIfRequiredOrScript();
+
+ EditorGUILayout.BeginVertical(EditorStyles.inspectorDefaultMargins);
+
+ EditorGUI.BeginChangeCheck();
+ DrawBlueprintProperties();
+ bool blueprintPropertiesChanged = EditorGUI.EndChangeCheck();
+ bool blueprintValid = ValidateBlueprint();
+
+ GUILayout.Space(10);
+
+ GUI.enabled = blueprintValid;
+ DrawGenerationControls();
+
+ GUI.enabled = (blueprint != null && !blueprint.empty && !Application.isPlaying);
+ EditorGUI.BeginChangeCheck();
+ editMode = GUILayout.Toggle(editMode, editMode ? "Done" : "Edit", "Button");
+ if (EditorGUI.EndChangeCheck())
+ {
+ if (editMode)
+ EditorApplication.delayCall += EnterBlueprintEditMode;
+ else
+ EditorApplication.delayCall += ExitBlueprintEditMode;
+ }
+ EditorGUILayout.EndVertical();
+ GUI.enabled = true;
+
+ if (isEditing)
+ DrawTools();
+
+ if (GUI.changed)
+ {
+ serializedObject.ApplyModifiedPropertiesWithoutUndo();
+
+ if (autoGenerate && blueprintValid && blueprintPropertiesChanged)
+ blueprint.GenerateImmediate();
+
+ // There might be blueprint editing operations that have no undo entry, so do this to
+ // ensure changes are serialized to disk by Unity.
+ EditorUtility.SetDirty(target);
+ }
+
+ }
+
+ protected virtual void DrawBlueprintProperties()
+ {
+ Editor.DrawPropertiesExcluding(serializedObject, "m_Script");
+ }
+
+ private void DrawWithCamera(Camera camera)
+ {
+ if (editMode)
+ {
+ for (int i = 0; i < renderModes.Count; ++i)
+ {
+ if ((1 << i & renderModeFlags) != 0)
+ renderModes[i].DrawWithCamera(camera);
+ }
+ }
+ }
+
+ void EnterBlueprintEditMode()
+ {
+ if (!isEditing)
+ {
+ ActiveEditorTracker.sharedTracker.isLocked = true;
+
+ string assetPath = AssetDatabase.GetAssetPath(blueprint);
+ ObiActorBlueprintEditorStage stage = ObiActorBlueprintEditorStage.CreateStage(assetPath, this);
+ StageUtility.GoToStage(stage, true);
+
+ isEditing = true;
+ }
+ }
+
+ void ExitBlueprintEditMode()
+ {
+ if (isEditing)
+ {
+ isEditing = false;
+ AssetDatabase.SaveAssets();
+ StageUtility.GoToMainStage();
+ }
+ }
+
+ public void CleanupEditor()
+ {
+ ActiveEditorTracker.sharedTracker.isLocked = false;
+ ObiParticleEditorDrawing.DestroyParticlesMesh();
+ }
+
+ public virtual void OnSceneGUI(SceneView sceneView)
+ {
+
+ if (!isEditing || sceneView.camera == null)
+ return;
+
+ ResizeParticleArrays();
+
+ Event e = Event.current;
+
+ if (e.type == EventType.Repaint)
+ {
+
+ // Update camera facing status and world space positions array:
+ UpdateParticleVisibility(sceneView.camera);
+
+ // Generate sorted indices for back-to-front rendering:
+ for (int i = 0; i < sortedIndices.Length; i++)
+ sortedIndices[i] = i;
+ Array.Sort(sortedIndices, (a, b) => sqrDistanceToCamera[b].CompareTo(sqrDistanceToCamera[a]));
+
+ // render modes OnSceneRepaint:
+ for (int i = 0; i < renderModes.Count; ++i)
+ {
+ if ((1 << i & renderModeFlags) != 0)
+ renderModes[i].OnSceneRepaint(sceneView);
+ }
+
+ // property OnSceneRepaint:
+ currentProperty.OnSceneRepaint();
+
+ // update particle color based on visiblity, etc.
+ UpdateTintColor();
+
+ // Draw particle handles:
+ ObiParticleEditorDrawing.DrawParticles(sceneView.camera, blueprint, visible, tint, sortedIndices, dotRadiusScale);
+
+ }
+
+ if (currentTool != null)
+ currentTool.OnSceneGUI(sceneView);
+
+ }
+
+ protected virtual void UpdateTintColor()
+ {
+ Color regularColor = ObiEditorSettings.GetOrCreateSettings().particleColor;
+ Color selectedColor = ObiEditorSettings.GetOrCreateSettings().selectedParticleColor;
+ Color activeColor = ObiEditorSettings.GetOrCreateSettings().activeParticleColor;
+
+ for (int i = 0; i < blueprint.positions.Length; i++)
+ {
+ // get particle color:
+ if (activeParticle == i)
+ tint[i] = activeColor;
+ else
+ tint[i] = selectionStatus[i] ? selectedColor : regularColor;
+
+ tint[i].a = visible[i] ? 1 : 0.15f;
+ }
+ }
+
+ protected void ResizeParticleArrays()
+ {
+ if (blueprint.positions != null)
+ {
+ activeParticle = Mathf.Min(activeParticle, blueprint.positions.Length - 1);
+ Array.Resize(ref selectionStatus, blueprint.positions.Length);
+ Array.Resize(ref visible, blueprint.positions.Length);
+ Array.Resize(ref tint, blueprint.positions.Length);
+ Array.Resize(ref sqrDistanceToCamera, blueprint.positions.Length);
+ Array.Resize(ref sortedIndices, blueprint.positions.Length);
+ }
+
+ }
+
+ public int PropertySelector(int propertyIndex, string label = "Property")
+ {
+ // get all particle properties:
+ string[] propertyNames = new string[properties.Count];
+ for (int i = 0; i < properties.Count; ++i)
+ propertyNames[i] = properties[i].name;
+
+ // Draw a selection dropdown:
+ return EditorGUILayout.Popup(label, propertyIndex, propertyNames);
+ }
+
+ public virtual void RenderModeSelector()
+ {
+ showRenderModes.value = EditorGUILayout.BeginFoldoutHeaderGroup(showRenderModes, "Render modes");
+ if (showRenderModes)
+ {
+ EditorGUI.BeginChangeCheck();
+ for (int i = 0; i < renderModes.Count; ++i)
+ {
+ int value = 1 << i;
+
+ if (EditorGUILayout.Toggle(renderModes[i].name, (value & renderModeFlags) != 0))
+ renderModeFlags |= value;
+ else
+ renderModeFlags &= ~value;
+ }
+ if (EditorGUI.EndChangeCheck())
+ Refresh();
+ }
+ EditorGUILayout.EndFoldoutHeaderGroup();
+ }
+
+ public void Refresh()
+ {
+ // currentProperty might be null after reloading editor during
+ // asset saving.
+ currentProperty?.RecalculateMinMax();
+
+ // refresh render modes:
+ for (int i = 0; i < renderModes.Count; ++i)
+ {
+ if ((1 << i & renderModeFlags) != 0)
+ renderModes[i].Refresh();
+ }
+
+ SceneView.RepaintAll();
+ }
+
+ public virtual void UpdateParticleVisibility(Camera cam)
+ {
+
+ for (int i = 0; i < blueprint.positions.Length; i++)
+ {
+ if (blueprint.IsParticleActive(i))
+ {
+ visible[i] = true;
+
+ if (Camera.current != null)
+ {
+ Vector3 camToParticle = cam.transform.position - blueprint.positions[i];
+ sqrDistanceToCamera[i] = camToParticle.sqrMagnitude;
+ }
+ }
+ }
+
+ if ((renderModeFlags & 1) != 0)
+ Refresh();
+ }
+
+ protected void DrawTools()
+ {
+
+ GUIContent[] contents = new GUIContent[tools.Count];
+
+ for (int i = 0; i < tools.Count; ++i)
+ contents[i] = new GUIContent(tools[i].icon, tools[i].name);
+
+ EditorGUILayout.Space();
+ GUILayout.Box(GUIContent.none, ObiEditorUtils.GetSeparatorLineStyle());
+ EditorGUILayout.Space();
+
+ EditorGUILayout.BeginVertical(EditorStyles.inspectorDefaultMargins);
+ EditorGUI.BeginChangeCheck();
+ int newSelectedTool = ObiEditorUtils.DoToolBar(currentToolIndex, contents);
+ EditorGUILayout.EndVertical();
+
+ if (EditorGUI.EndChangeCheck())
+ {
+ if (currentTool != null)
+ currentTool.OnDisable();
+
+ currentToolIndex = newSelectedTool;
+
+ if (currentTool != null)
+ currentTool.OnEnable();
+
+ SceneView.RepaintAll();
+ }
+
+ if (currentTool != null)
+ {
+ EditorGUILayout.BeginVertical(EditorStyles.inspectorDefaultMargins);
+ EditorGUILayout.LabelField(currentTool.name, EditorStyles.boldLabel);
+
+ string help = currentTool.GetHelpString();
+ if (!help.Equals(string.Empty))
+ EditorGUILayout.LabelField(help, EditorStyles.helpBox);
+ EditorGUILayout.EndVertical();
+
+ currentTool.OnInspectorGUI();
+ }
+
+ }
+
+ public void SetSelected(int particleIndex, bool selected)
+ {
+ selectionStatus[particleIndex] = selected;
+ }
+
+ public bool IsSelected(int particleIndex)
+ {
+ return selectionStatus[particleIndex];
+ }
+
+ public bool Editable(int particleIndex)
+ {
+ return currentTool.Editable(particleIndex) && blueprint.IsParticleActive(particleIndex);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/Assets/Obi/Editor/Common/Blueprints/ObiActorBlueprintEditor.cs.meta b/Assets/Obi/Editor/Common/Blueprints/ObiActorBlueprintEditor.cs.meta
new file mode 100644
index 000000000..c1fbbadee
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/ObiActorBlueprintEditor.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 2e39e6eea226f4ecbbe091613ff79f85
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints/ObiActorBlueprintEditorStage.cs b/Assets/Obi/Editor/Common/Blueprints/ObiActorBlueprintEditorStage.cs
new file mode 100644
index 000000000..561ee8976
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/ObiActorBlueprintEditorStage.cs
@@ -0,0 +1,72 @@
+using System;
+using System.IO;
+using UnityEditor;
+using UnityEditor.SceneManagement;
+using UnityEngine;
+
+namespace Obi
+{
+ [Serializable]
+ class ObiActorBlueprintEditorStage : PreviewSceneStage
+ {
+ ObiActorBlueprintEditor m_BlueprintEditor;
+
+ string m_AssetPath;
+ public override string assetPath { get { return m_AssetPath; } }
+
+ internal static ObiActorBlueprintEditorStage CreateStage(string assetPath, ObiActorBlueprintEditor avatarEditor)
+ {
+ ObiActorBlueprintEditorStage stage = CreateInstance();
+ stage.Init(assetPath, avatarEditor);
+ return stage;
+ }
+
+ private void Init(string modelAssetPath, ObiActorBlueprintEditor avatarEditor)
+ {
+ m_AssetPath = modelAssetPath;
+ m_BlueprintEditor = avatarEditor;
+ }
+
+ protected override bool OnOpenStage()
+ {
+ base.OnOpenStage();
+
+ if (!File.Exists(assetPath))
+ {
+ Debug.LogError("ActivateStage called on BlueprintStage with an invalid path: Blueprint file not found " + assetPath);
+ return false;
+ }
+
+ return true;
+ }
+
+ protected override void OnCloseStage()
+ {
+ m_BlueprintEditor.CleanupEditor();
+
+ base.OnCloseStage();
+ }
+
+ protected override void OnFirstTimeOpenStageInSceneView(SceneView sceneView)
+ {
+ // Frame in scene view
+ sceneView.Frame(m_BlueprintEditor.blueprint.bounds);
+
+ // Setup Scene view state
+ sceneView.sceneViewState.showFlares = false;
+ sceneView.sceneViewState.alwaysRefresh = false;
+ sceneView.sceneViewState.showFog = false;
+ sceneView.sceneViewState.showSkybox = false;
+ sceneView.sceneViewState.showImageEffects = false;
+ sceneView.sceneViewState.showParticleSystems = false;
+ sceneView.sceneLighting = true;
+ }
+
+ protected override GUIContent CreateHeaderContent()
+ {
+ return new GUIContent(
+ "Blueprint Editor",
+ Resources.Load("Icons/ObiActorBlueprint Icon"));
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/Obi/Editor/Common/Blueprints/ObiActorBlueprintEditorStage.cs.meta b/Assets/Obi/Editor/Common/Blueprints/ObiActorBlueprintEditorStage.cs.meta
new file mode 100644
index 000000000..91b16abee
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/ObiActorBlueprintEditorStage.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 4c8d9d8042d49436c89c515b001088ac
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints/ObiMeshBasedActorBlueprintEditor.cs b/Assets/Obi/Editor/Common/Blueprints/ObiMeshBasedActorBlueprintEditor.cs
new file mode 100644
index 000000000..98630677a
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/ObiMeshBasedActorBlueprintEditor.cs
@@ -0,0 +1,275 @@
+using UnityEngine;
+using UnityEditor;
+using System;
+using System.IO;
+
+namespace Obi
+{
+ [CustomEditor(typeof(ObiMeshBasedActorBlueprint), true)]
+ public abstract class ObiMeshBasedActorBlueprintEditor : ObiActorBlueprintEditor
+ {
+
+ [Flags]
+ public enum ParticleCulling
+ {
+ Off = 0,
+ Back = 1 << 0,
+ Front = 1 << 1
+ }
+
+ protected Mesh visualizationMesh;
+ protected Mesh visualizationWireMesh;
+ public ParticleCulling particleCulling = ParticleCulling.Back;
+
+ protected Material gradientMaterial;
+ protected Material textureExportMaterial;
+ protected Material paddingMaterial;
+
+ public override void OnEnable()
+ {
+ base.OnEnable();
+ gradientMaterial = Resources.Load("PropertyGradientMaterial");
+ textureExportMaterial = Resources.Load("UVSpaceColorMaterial");
+ paddingMaterial = Resources.Load("PaddingMaterial");
+ }
+
+ public abstract Mesh sourceMesh
+ {
+ get;
+ }
+
+ protected void NonReadableMeshWarning(Mesh mesh)
+ {
+ EditorGUILayout.BeginVertical(EditorStyles.helpBox);
+ Texture2D icon = EditorGUIUtility.Load("icons/console.erroricon.png") as Texture2D;
+ EditorGUILayout.LabelField(new GUIContent("The input mesh is not readable. Read/Write must be enabled in the mesh import settings.", icon), EditorStyles.wordWrappedMiniLabel);
+
+ EditorGUILayout.BeginHorizontal();
+ GUILayout.FlexibleSpace();
+ if (GUILayout.Button("Fix now", GUILayout.MaxWidth(100), GUILayout.MinHeight(32)))
+ {
+ string assetPath = AssetDatabase.GetAssetPath(mesh);
+ ModelImporter modelImporter = AssetImporter.GetAtPath(assetPath) as ModelImporter;
+ if (modelImporter != null)
+ {
+ modelImporter.isReadable = true;
+ }
+ modelImporter.SaveAndReimport();
+ }
+ EditorGUILayout.EndHorizontal();
+ EditorGUILayout.EndVertical();
+ }
+
+ protected override bool ValidateBlueprint()
+ {
+ if (sourceMesh != null)
+ {
+ if (!sourceMesh.isReadable)
+ {
+ NonReadableMeshWarning(sourceMesh);
+ return false;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ public abstract int VertexToParticle(int vertexIndex);
+
+ public override void UpdateParticleVisibility(Camera cam)
+ {
+ if (cam != null)
+ {
+ for (int i = 0; i < blueprint.positions.Length; i++)
+ {
+ if (blueprint.IsParticleActive(i))
+ {
+ Vector3 camToParticle = cam.transform.position - blueprint.positions[i];
+ sqrDistanceToCamera[i] = camToParticle.sqrMagnitude;
+
+ Vector3 normal;
+
+ switch (particleCulling)
+ {
+ case ParticleCulling.Off:
+ visible[i] = true;
+ break;
+ case ParticleCulling.Back:
+ normal = blueprint.restOrientations[i] * Vector3.forward;
+ visible[i] = Vector3.Dot(normal, camToParticle) > 0;
+ break;
+ case ParticleCulling.Front:
+ normal = blueprint.restOrientations[i] * Vector3.forward;
+ visible[i] = Vector3.Dot(normal, camToParticle) <= 0;
+ break;
+ }
+ }
+ }
+
+ if ((renderModeFlags & 1) != 0)
+ Refresh();
+ }
+ }
+
+ public void DrawGradientMesh(float[] vertexWeights = null, float[] wireframeWeights = null)
+ {
+ // Due to this Unity bug: https://issuetracker.unity3d.com/issues/drawmeshnow-is-not-drawing-mesh-immediately-dx12
+ // we need to create two meshes insteaf of one :(
+ if (sourceMesh == null)
+ return;
+
+ visualizationMesh = GameObject.Instantiate(sourceMesh);
+ visualizationWireMesh = GameObject.Instantiate(sourceMesh);
+
+ if (gradientMaterial.SetPass(0))
+ {
+ var matrix = Matrix4x4.TRS(Vector3.zero, (blueprint as ObiMeshBasedActorBlueprint).rotation, (blueprint as ObiMeshBasedActorBlueprint).scale);
+
+ Color[] colors = new Color[visualizationMesh.vertexCount];
+ for (int i = 0; i < colors.Length; i++)
+ {
+ int particle = VertexToParticle(i);
+ if (particle >= 0 && particle < blueprint.particleCount)
+ {
+ float weight = 1;
+ if (vertexWeights != null)
+ weight = vertexWeights[particle];
+
+ colors[i] = weight * currentProperty.ToColor(particle);
+ }
+ else
+ colors[i] = Color.gray;
+ }
+
+ visualizationMesh.colors = colors;
+ Graphics.DrawMeshNow(visualizationMesh, matrix);
+
+ Color wireColor = ObiEditorSettings.GetOrCreateSettings().brushWireframeColor;
+
+ if (gradientMaterial.SetPass(1))
+ {
+ for (int i = 0; i < colors.Length; i++)
+ {
+ int particle = VertexToParticle(i);
+ if (particle >= 0 && particle < blueprint.particleCount)
+ {
+ if (wireframeWeights != null)
+ colors[i] = wireColor * wireframeWeights[particle];
+ else
+ colors[i] = wireColor;
+ }
+ else
+ colors[i] = Color.gray;
+ }
+
+ visualizationWireMesh.colors = colors;
+ GL.wireframe = true;
+ Graphics.DrawMeshNow(visualizationWireMesh, matrix);
+ GL.wireframe = false;
+ }
+
+ }
+
+ GameObject.DestroyImmediate(visualizationMesh);
+ GameObject.DestroyImmediate(visualizationWireMesh);
+ }
+
+
+ /**
+ * Reads particle data from a 2D texture. Can be used to adjust per particle mass, skin radius, etc. using
+ * a texture instead of painting it in the editor.
+ *
+ * Will call onReadProperty once for each particle, passing the particle index and the bilinearly interpolated
+ * color of the texture at its coordinate.
+ *
+ * Be aware that, if a particle corresponds to more than
+ * one physical vertex and has multiple uv coordinates,
+ * onReadProperty will be called multiple times for that particle.
+ */
+ public bool ReadParticlePropertyFromTexture(Texture2D source, Action onReadProperty)
+ {
+
+ if (source == null || onReadProperty == null)
+ return false;
+
+ Vector2[] uvs = sourceMesh.uv;
+
+ // Iterate over all vertices in the mesh reading back colors from the texture:
+ for (int i = 0; i < sourceMesh.vertexCount; ++i)
+ {
+ try
+ {
+ onReadProperty(VertexToParticle(i), source.GetPixelBilinear(uvs[i].x, uvs[i].y));
+ }
+ catch (UnityException e)
+ {
+ Debug.LogException(e);
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public bool WriteParticlePropertyToTexture(string path, int width, int height, int padding)
+ {
+
+ if (path == null || textureExportMaterial == null || !textureExportMaterial.SetPass(0))
+ return false;
+
+ if (visualizationMesh == null)
+ {
+ visualizationMesh = GameObject.Instantiate(sourceMesh);
+ }
+
+ RenderTexture tempRT = RenderTexture.GetTemporary(width, height, 0);
+ RenderTexture paddingRT = RenderTexture.GetTemporary(width, height, 0);
+
+ RenderTexture old = RenderTexture.active;
+ RenderTexture.active = tempRT;
+
+ GL.PushMatrix();
+
+ var proj = Matrix4x4.Ortho(0, 1, 0, 1, -1, 1);
if (Camera.current != null) proj = proj * Camera.current.worldToCameraMatrix.inverse;
GL.LoadProjectionMatrix(proj);
+
+ Color[] colors = new Color[sourceMesh.vertexCount];
+ for (int i = 0; i < colors.Length; i++)
+ colors[i] = currentProperty.ToColor(VertexToParticle(i));
+
+ visualizationMesh.colors = colors;
+ Graphics.DrawMeshNow(visualizationMesh, Matrix4x4.identity);
+
+ GL.PopMatrix();
+
+ // Perform padding/edge dilation
+ paddingMaterial.SetFloat("_Padding", padding);
+ Graphics.Blit(tempRT, paddingRT, paddingMaterial);
+
+ // Read result into our Texture2D.
+ RenderTexture.active = paddingRT;
+ Texture2D texture = new Texture2D(width, height, TextureFormat.RGBA32, false);
+ texture.ReadPixels(new Rect(0, 0, width, height), 0, 0);
+
+ RenderTexture.active = old;
+ RenderTexture.ReleaseTemporary(paddingRT);
+ RenderTexture.ReleaseTemporary(tempRT);
+
+ byte[] png = texture.EncodeToPNG();
+ GameObject.DestroyImmediate(texture);
+
+ try
+ {
+ File.WriteAllBytes(path, png);
+ }
+ catch (Exception e)
+ {
+ Debug.LogException(e);
+ return false;
+ }
+
+ AssetDatabase.Refresh();
+
+ return true;
+ }
+ }
+}
diff --git a/Assets/Obi/Editor/Common/Blueprints/ObiMeshBasedActorBlueprintEditor.cs.meta b/Assets/Obi/Editor/Common/Blueprints/ObiMeshBasedActorBlueprintEditor.cs.meta
new file mode 100644
index 000000000..497250ff1
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/ObiMeshBasedActorBlueprintEditor.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: c81a94632ae434014aedb4cc241e73e2
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints/ObiMeshUtils.cs b/Assets/Obi/Editor/Common/Blueprints/ObiMeshUtils.cs
new file mode 100644
index 000000000..02ae7b5d5
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/ObiMeshUtils.cs
@@ -0,0 +1,93 @@
+using UnityEngine;
+using System.Collections;
+
+namespace Obi
+{
+ public static class ObiMeshUtils
+ {
+ // Temporary vector3 values
+ static Vector3 tv1, tv2, tv3, tv4;
+
+ public static bool RayIntersectsTriangle(Vector3 origin,
+ Vector3 dir,
+ Vector3 vert0,
+ Vector3 vert1,
+ Vector3 vert2,
+ ref float distance,
+ ref Vector3 normal)
+ {
+ float det;
+
+ ObiVectorMath.Subtract(vert0, vert1, ref tv1);
+ ObiVectorMath.Subtract(vert0, vert2, ref tv2);
+
+ ObiVectorMath.Cross(dir, tv2, ref tv4);
+ det = Vector3.Dot(tv1, tv4);
+
+ if (det < Mathf.Epsilon)
+ return false;
+
+ ObiVectorMath.Subtract(vert0, origin, ref tv3);
+
+ float u = Vector3.Dot(tv3, tv4);
+
+ if (u < 0f || u > det)
+ return false;
+
+ ObiVectorMath.Cross(tv3, tv1, ref tv4);
+
+ float v = Vector3.Dot(dir, tv4);
+
+ if (v < 0f || u + v > det)
+ return false;
+
+ distance = Vector3.Dot(tv2, tv4) * (1f / det);
+ ObiVectorMath.Cross(tv1, tv2, ref normal);
+
+ return true;
+ }
+
/**
* Find the nearest triangle intersected by InWorldRay on this mesh. InWorldRay is in world space.
* @hit contains information about the hit point. @distance limits how far from @InWorldRay.origin the hit
* point may be. @cullingMode determines what face orientations are tested (Culling.Front only tests front
* faces, Culling.Back only tests back faces, and Culling.FrontBack tests both).
* Ray origin and position values are in local space.
*/
public static bool WorldRaycast(Ray InWorldRay, Matrix4x4 transform, Vector3[] vertices, int[] triangles, out ObiRaycastHit hit, float distance = Mathf.Infinity)
{
+ Ray ray = InWorldRay;
+ if (transform != null)
+ {
+ Matrix4x4 inv = transform.inverse;
+ ray.origin = inv.MultiplyPoint3x4(ray.origin);
+ ray.direction = inv.MultiplyVector(ray.direction);
+ }
return MeshRaycast(ray, vertices, triangles, out hit, distance);
}
/**
* Cast a ray (in model space) against a mesh.
*/
public static bool MeshRaycast(Ray InRay, Vector3[] vertices, int[] triangles, out ObiRaycastHit hit, float distance = Mathf.Infinity)
{
+ Vector3 hitNormal = Vector3.zero; // vars used in loop
+ Vector3 vert0, vert1, vert2;
+ Vector3 origin = InRay.origin, direction = InRay.direction;
+
+ hit = new ObiRaycastHit(Mathf.Infinity,
+ Vector3.zero,
+ Vector3.zero,
+ -1);
+ /**
+ * Iterate faces, testing for nearest hit to ray origin.
+ */
+ for (int CurTri = 0; CurTri < triangles.Length; CurTri += 3)
+ {
+ if (CurTri + 2 >= triangles.Length) continue;
+ if (triangles[CurTri + 2] >= vertices.Length) continue;
+
+ vert0 = vertices[triangles[CurTri + 0]];
+ vert1 = vertices[triangles[CurTri + 1]];
+ vert2 = vertices[triangles[CurTri + 2]];
+
+ // Second pass, test intersection with triangle
+ if (RayIntersectsTriangle(origin, direction, vert0, vert1, vert2, ref distance, ref hitNormal))
+ {
+ if (distance < hit.distance)
+ {
+ hit.distance = distance;
+ hit.triangle = CurTri / 3;
+ hit.position = InRay.GetPoint(hit.distance);
+ hit.normal = hitNormal;
+ }
+ }
+ }
+
+ return hit.triangle > -1;
}
+ }
+
+}
\ No newline at end of file
diff --git a/Assets/Obi/Editor/Common/Blueprints/ObiMeshUtils.cs.meta b/Assets/Obi/Editor/Common/Blueprints/ObiMeshUtils.cs.meta
new file mode 100644
index 000000000..90c00ab9b
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/ObiMeshUtils.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 4d2a4dd4e807c4053b4e4af4d43db45e
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints/ObiParticleEditorDrawing.cs b/Assets/Obi/Editor/Common/Blueprints/ObiParticleEditorDrawing.cs
new file mode 100644
index 000000000..b3af4d4a8
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/ObiParticleEditorDrawing.cs
@@ -0,0 +1,127 @@
+using UnityEngine;
+using UnityEditor;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace Obi
+{
+ public class ObiParticleEditorDrawing : MonoBehaviour
+ {
+ public static Mesh particlesMesh;
+ public static Material particleMaterial;
+
+ private static void CreateParticlesMesh()
+ {
+ if (particlesMesh == null)
+ {
+ particlesMesh = new Mesh();
+ particlesMesh.hideFlags = HideFlags.HideAndDontSave;
+ }
+ }
+
+ private static void CreateParticleMaterials()
+ {
+ if (!particleMaterial)
+ {
+ particleMaterial = Resources.Load("EditorParticle");
+ }
+ }
+
+ public static void DestroyParticlesMesh()
+ {
+ GameObject.DestroyImmediate(particlesMesh);
+ }
+
+ public static void DrawParticles(Camera cam, ObiActorBlueprint blueprint, bool[] visible, Color[] baseColor, int[] sortedIndices, float radiusScale = 1)
+ {
+ CreateParticlesMesh();
+ CreateParticleMaterials();
+
+ if (!particleMaterial.SetPass(0))
+ return;
+
+ //because each vertex needs to be drawn as a quad.
+ int particlesPerDrawcall = Constants.maxVertsPerMesh / 4;
+ int drawcallCount = blueprint.particleCount / particlesPerDrawcall + 1;
+ particlesPerDrawcall = Mathf.Min(particlesPerDrawcall, blueprint.particleCount);
+
+ List vertices = new List(blueprint.activeParticleCount* 4);
+ List normals = new List(blueprint.activeParticleCount * 4);
+ List uvs = new List(blueprint.activeParticleCount * 4);
+ List colors = new List(blueprint.activeParticleCount * 4);
+ List triangles = new List(blueprint.activeParticleCount * 6);
+
+ Vector3 particleOffset0 = new Vector3(1, 1, 0);
+ Vector3 particleOffset1 = new Vector3(-1, 1, 0);
+ Vector3 particleOffset2 = new Vector3(-1, -1, 0);
+ Vector3 particleOffset3 = new Vector3(1, -1, 0);
+
+ Vector4 radius = new Vector4(1, 0, 0, 0.005f * radiusScale);
+
+ for (int i = 0; i < drawcallCount; ++i)
+ {
+ //Draw all cloth vertices:
+ particlesMesh.Clear();
+ vertices.Clear();
+ uvs.Clear();
+ normals.Clear();
+ colors.Clear();
+ triangles.Clear();
+
+ int index = 0;
+
+ // Run over all particles (not only active ones), since they're reordered based on distance to camera.
+ // Then test if the sorted index is active or not, and skip inactive ones.
+ int limit = Mathf.Min((i + 1) * particlesPerDrawcall, blueprint.particleCount);
+
+ for (int j = i * particlesPerDrawcall; j < limit; ++j)
+ {
+ int sortedIndex = sortedIndices[j];
+
+ // skip inactive ones:
+ if (!blueprint.IsParticleActive(sortedIndex))
+ continue;
+
+ normals.Add(particleOffset0);
+ normals.Add(particleOffset1);
+ normals.Add(particleOffset2);
+ normals.Add(particleOffset3);
+
+ uvs.Add(radius);
+ uvs.Add(radius);
+ uvs.Add(radius);
+ uvs.Add(radius);
+
+ vertices.Add(blueprint.positions[sortedIndex]);
+ vertices.Add(blueprint.positions[sortedIndex]);
+ vertices.Add(blueprint.positions[sortedIndex]);
+ vertices.Add(blueprint.positions[sortedIndex]);
+
+ colors.Add(baseColor[sortedIndex]);
+ colors.Add(baseColor[sortedIndex]);
+ colors.Add(baseColor[sortedIndex]);
+ colors.Add(baseColor[sortedIndex]);
+
+ triangles.Add(index + 2);
+ triangles.Add(index + 1);
+ triangles.Add(index);
+ triangles.Add(index + 3);
+ triangles.Add(index + 2);
+ triangles.Add(index);
+
+ index += 4;
+ }
+
+ particlesMesh.SetVertices(vertices);
+ particlesMesh.SetNormals(normals);
+ particlesMesh.SetColors(colors);
+ particlesMesh.SetUVs(0, uvs);
+ particlesMesh.SetTriangles(triangles,0, true);
+
+ Graphics.DrawMeshNow(particlesMesh, Matrix4x4.identity);
+ }
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/Assets/Obi/Editor/Common/Blueprints/ObiParticleEditorDrawing.cs.meta b/Assets/Obi/Editor/Common/Blueprints/ObiParticleEditorDrawing.cs.meta
new file mode 100644
index 000000000..561f8c744
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/ObiParticleEditorDrawing.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 982f73e0e40c749f09db403624bbd8e1
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints/Properties.meta b/Assets/Obi/Editor/Common/Blueprints/Properties.meta
new file mode 100644
index 000000000..1efd01e8b
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Properties.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: dfda10b0e82f747998295540d5750108
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints/Properties/BaseTypes.meta b/Assets/Obi/Editor/Common/Blueprints/Properties/BaseTypes.meta
new file mode 100644
index 000000000..1de2e12b8
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Properties/BaseTypes.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 7b9ba4ddc644a4bfa8ab44a5826b8007
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints/Properties/BaseTypes/ObiBlueprintBoolProperty.cs b/Assets/Obi/Editor/Common/Blueprints/Properties/BaseTypes/ObiBlueprintBoolProperty.cs
new file mode 100644
index 000000000..d3b35a8d7
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Properties/BaseTypes/ObiBlueprintBoolProperty.cs
@@ -0,0 +1,24 @@
+using UnityEngine;
+using UnityEditor;
+using System.Collections;
+
+namespace Obi
+{
+ public abstract class ObiBlueprintBoolProperty : ObiBlueprintProperty
+ {
+ public override bool Equals(int firstIndex, int secondIndex)
+ {
+ return Get(firstIndex) == Get(secondIndex);
+ }
+
+ public override void PropertyField()
+ {
+ value = EditorGUILayout.Toggle(name, value);
+ }
+
+ public override Color ToColor(int index)
+ {
+ return value ? Color.white : Color.gray;
+ }
+ }
+}
diff --git a/Assets/Obi/Editor/Common/Blueprints/Properties/BaseTypes/ObiBlueprintBoolProperty.cs.meta b/Assets/Obi/Editor/Common/Blueprints/Properties/BaseTypes/ObiBlueprintBoolProperty.cs.meta
new file mode 100644
index 000000000..719c085a0
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Properties/BaseTypes/ObiBlueprintBoolProperty.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 19cb8e21747094d6dae8dff155654066
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints/Properties/BaseTypes/ObiBlueprintColorProperty.cs b/Assets/Obi/Editor/Common/Blueprints/Properties/BaseTypes/ObiBlueprintColorProperty.cs
new file mode 100644
index 000000000..a62d0c3b2
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Properties/BaseTypes/ObiBlueprintColorProperty.cs
@@ -0,0 +1,31 @@
+using UnityEngine;
+using UnityEditor;
+using System.Collections;
+
+namespace Obi
+{
+ public abstract class ObiBlueprintColorProperty : ObiBlueprintProperty
+ {
+ public ObiActorBlueprintEditor editor;
+
+ public ObiBlueprintColorProperty(ObiActorBlueprintEditor editor)
+ {
+ this.editor = editor;
+ }
+
+ public override bool Equals(int firstIndex, int secondIndex)
+ {
+ return Get(firstIndex) == Get(secondIndex);
+ }
+
+ public override void PropertyField()
+ {
+ value = EditorGUILayout.ColorField(name, value);
+ }
+
+ public override Color ToColor(int index)
+ {
+ return editor.blueprint.colors[index];
+ }
+ }
+}
diff --git a/Assets/Obi/Editor/Common/Blueprints/Properties/BaseTypes/ObiBlueprintColorProperty.cs.meta b/Assets/Obi/Editor/Common/Blueprints/Properties/BaseTypes/ObiBlueprintColorProperty.cs.meta
new file mode 100644
index 000000000..226bed79e
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Properties/BaseTypes/ObiBlueprintColorProperty.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 64ab0b4fad7614808acc3cdb75215c50
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints/Properties/BaseTypes/ObiBlueprintFloatProperty.cs b/Assets/Obi/Editor/Common/Blueprints/Properties/BaseTypes/ObiBlueprintFloatProperty.cs
new file mode 100644
index 000000000..8b5217444
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Properties/BaseTypes/ObiBlueprintFloatProperty.cs
@@ -0,0 +1,94 @@
+using UnityEngine;
+using UnityEditor;
+
+namespace Obi
+{
+ public abstract class ObiBlueprintFloatProperty : ObiBlueprintProperty
+ {
+ public float minVisualizationValue = 0;
+ public float maxVisualizationValue = 10;
+ protected float minUserVisualizationValue = 0;
+ protected float maxUserVisualizationValue = 10;
+
+ protected float? minValue = null;
+ protected float? maxValue = null;
+
+ public bool autoRange = true;
+ public ObiActorBlueprintEditor editor;
+
+ public ObiBlueprintFloatProperty(ObiActorBlueprintEditor editor, float? minValue = null, float? maxValue = null)
+ {
+ this.editor = editor;
+ this.minValue = minValue;
+ this.maxValue = maxValue;
+ }
+
+ public override bool Equals(int firstIndex, int secondIndex)
+ {
+ float v1 = Get(firstIndex);
+ float v2 = Get(secondIndex);
+ if (v1 == v2) return true;
+ return Mathf.Approximately(v1,v2);
+ }
+
+ public override void PropertyField()
+ {
+ EditorGUI.BeginChangeCheck();
+ value = EditorGUILayout.FloatField(name, value);
+ if (EditorGUI.EndChangeCheck())
+ {
+ if (minValue.HasValue)
+ value = Mathf.Max(minValue.Value, value);
+ if (maxValue.HasValue)
+ value = Mathf.Min(maxValue.Value, value);
+ }
+ }
+
+ public override void RecalculateMinMax()
+ {
+ if (editor != null && autoRange)
+ {
+ maxVisualizationValue = float.MinValue;
+ minVisualizationValue = float.MaxValue;
+
+ for (int i = 0; i < editor.blueprint.activeParticleCount; i++)
+ {
+ float v = Get(i);
+ maxVisualizationValue = Mathf.Max(maxVisualizationValue, v);
+ minVisualizationValue = Mathf.Min(minVisualizationValue, v);
+ }
+ }
+ else
+ {
+ maxVisualizationValue = maxUserVisualizationValue;
+ minVisualizationValue = minUserVisualizationValue;
+ }
+ }
+
+ public override void VisualizationOptions()
+ {
+ EditorGUI.BeginChangeCheck();
+ autoRange = EditorGUILayout.Toggle("Automatic property range", autoRange);
+ GUI.enabled = !autoRange;
+ EditorGUI.indentLevel++;
+ minUserVisualizationValue = EditorGUILayout.FloatField("Min", minUserVisualizationValue);
+ maxUserVisualizationValue = EditorGUILayout.FloatField("Max", maxUserVisualizationValue);
+ EditorGUI.indentLevel--;
+ GUI.enabled = true;
+
+ if (EditorGUI.EndChangeCheck())
+ {
+ RecalculateMinMax();
+ editor.Refresh();
+ }
+ }
+
+ public override Color ToColor(int index)
+ {
+ Gradient gradient = ObiEditorSettings.GetOrCreateSettings().propertyGradient;
+ if (!Mathf.Approximately(minVisualizationValue, maxVisualizationValue))
+ return gradient.Evaluate(Mathf.InverseLerp(minVisualizationValue, maxVisualizationValue, Get(index)));
+ else return gradient.Evaluate(0);
+ }
+ }
+}
diff --git a/Assets/Obi/Editor/Common/Blueprints/Properties/BaseTypes/ObiBlueprintFloatProperty.cs.meta b/Assets/Obi/Editor/Common/Blueprints/Properties/BaseTypes/ObiBlueprintFloatProperty.cs.meta
new file mode 100644
index 000000000..a8a2539df
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Properties/BaseTypes/ObiBlueprintFloatProperty.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: be67f2576200242f080bbcc074dc598a
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints/Properties/BaseTypes/ObiBlueprintIntProperty.cs b/Assets/Obi/Editor/Common/Blueprints/Properties/BaseTypes/ObiBlueprintIntProperty.cs
new file mode 100644
index 000000000..4cbc05b86
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Properties/BaseTypes/ObiBlueprintIntProperty.cs
@@ -0,0 +1,41 @@
+using UnityEngine;
+using UnityEditor;
+
+namespace Obi
+{
+ public abstract class ObiBlueprintIntProperty : ObiBlueprintProperty
+ {
+ protected int? minValue = null;
+ protected int? maxValue = null;
+
+ public ObiBlueprintIntProperty(int? minValue = null, int? maxValue = null)
+ {
+ this.minValue = minValue;
+ this.maxValue = maxValue;
+ }
+
+ public override bool Equals(int firstIndex, int secondIndex)
+ {
+ return Get(firstIndex) == Get(secondIndex);
+ }
+
+ public override void PropertyField()
+ {
+ EditorGUI.BeginChangeCheck();
+ value = EditorGUILayout.IntField(name, value);
+ if (EditorGUI.EndChangeCheck())
+ {
+ if (minValue.HasValue)
+ value = Mathf.Max(minValue.Value, value);
+ if (maxValue.HasValue)
+ value = Mathf.Min(maxValue.Value, value);
+ }
+ }
+
+ public override Color ToColor(int index)
+ {
+ int colorIndex = Get(index) % ObiUtils.colorAlphabet.Length;
+ return ObiUtils.colorAlphabet[colorIndex];
+ }
+ }
+}
diff --git a/Assets/Obi/Editor/Common/Blueprints/Properties/BaseTypes/ObiBlueprintIntProperty.cs.meta b/Assets/Obi/Editor/Common/Blueprints/Properties/BaseTypes/ObiBlueprintIntProperty.cs.meta
new file mode 100644
index 000000000..069bfc02e
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Properties/BaseTypes/ObiBlueprintIntProperty.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: d8661f9e9cfd044c7bb759145c2a8d73
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints/Properties/BaseTypes/ObiBlueprintMaskProperty.cs b/Assets/Obi/Editor/Common/Blueprints/Properties/BaseTypes/ObiBlueprintMaskProperty.cs
new file mode 100644
index 000000000..e4b0713e0
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Properties/BaseTypes/ObiBlueprintMaskProperty.cs
@@ -0,0 +1,28 @@
+using UnityEngine;
+using UnityEditor;
+
+namespace Obi
+{
+ public abstract class ObiBlueprintMaskProperty : ObiBlueprintIntProperty
+ {
+ public ObiBlueprintMaskProperty() : base(null,null)
+ {
+ }
+
+ public override void PropertyField()
+ {
+ value = EditorGUILayout.MaskField(name, value, ObiUtils.categoryNames);
+ }
+
+ private int MathMod(int a, int b)
+ {
+ return (Mathf.Abs(a * b) + a) % b;
+ }
+
+ public override Color ToColor(int index)
+ {
+ int colorIndex = MathMod(Get(index),ObiUtils.colorAlphabet.Length);
+ return ObiUtils.colorAlphabet[colorIndex];
+ }
+ }
+}
diff --git a/Assets/Obi/Editor/Common/Blueprints/Properties/BaseTypes/ObiBlueprintMaskProperty.cs.meta b/Assets/Obi/Editor/Common/Blueprints/Properties/BaseTypes/ObiBlueprintMaskProperty.cs.meta
new file mode 100644
index 000000000..60f3c1783
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Properties/BaseTypes/ObiBlueprintMaskProperty.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 165ad17d69adf415ea7609a9373de001
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints/Properties/BaseTypes/ObiBlueprintProperty.cs b/Assets/Obi/Editor/Common/Blueprints/Properties/BaseTypes/ObiBlueprintProperty.cs
new file mode 100644
index 000000000..fb7681244
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Properties/BaseTypes/ObiBlueprintProperty.cs
@@ -0,0 +1,79 @@
+using UnityEngine;
+using UnityEditor;
+using System.Collections.Generic;
+
+namespace Obi
+{
+ public abstract class ObiBlueprintPropertyBase
+ {
+ protected List brushModes = new List();
+ private int selectedBrushMode;
+
+ public abstract string name
+ {
+ get;
+ }
+
+ public abstract void PropertyField();
+ public virtual void VisualizationOptions(){}
+ public virtual void OnSceneRepaint(){}
+
+ public abstract bool Equals(int firstIndex, int secondIndex);
+
+ public abstract void GetDefaultFromIndex(int index);
+ public abstract void SetDefaultToIndex(int index);
+ public virtual bool Masked(int index)
+ {
+ return false;
+ }
+
+ public virtual void RecalculateMinMax() { }
+ public virtual Color ToColor(int index) { return Color.white; }
+
+ protected void Initialize(ObiBrushBase paintBrush)
+ {
+ // Initialize the brush if there's no brush mode set:
+ if (paintBrush.brushMode == null && brushModes.Count > 0)
+ {
+ selectedBrushMode = 0;
+ paintBrush.brushMode = brushModes[selectedBrushMode];
+ }
+ }
+
+ public void OnSelect(ObiBrushBase paintBrush)
+ {
+ // Upon selecting the property, change to the last selected brush mode:
+ if (brushModes.Count > selectedBrushMode)
+ paintBrush.brushMode = brushModes[selectedBrushMode];
+
+ }
+
+ public void BrushModes(ObiBrushBase paintBrush)
+ {
+ Initialize(paintBrush);
+
+ GUIContent[] contents = new GUIContent[brushModes.Count];
+ for (int i = 0; i < brushModes.Count; ++i)
+ contents[i] = new GUIContent(brushModes[i].name);
+
+ EditorGUI.BeginChangeCheck();
+ selectedBrushMode = ObiEditorUtils.DoToolBar(selectedBrushMode, contents);
+ if (EditorGUI.EndChangeCheck())
+ {
+ paintBrush.brushMode = brushModes[selectedBrushMode];
+ }
+ }
+ }
+
+ public abstract class ObiBlueprintProperty : ObiBlueprintPropertyBase
+ {
+ protected T value;
+
+ public T GetDefault() { return value; }
+ public override void GetDefaultFromIndex(int index) { value = Get(index); }
+ public override void SetDefaultToIndex(int index) { Set(index, value); }
+
+ public abstract T Get(int index);
+ public abstract void Set(int index, T value);
+ }
+}
diff --git a/Assets/Obi/Editor/Common/Blueprints/Properties/BaseTypes/ObiBlueprintProperty.cs.meta b/Assets/Obi/Editor/Common/Blueprints/Properties/BaseTypes/ObiBlueprintProperty.cs.meta
new file mode 100644
index 000000000..ba7b85be8
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Properties/BaseTypes/ObiBlueprintProperty.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 60a83ba184caf4a1aba4da6754776a1d
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints/Properties/IObiPropertyEditableProvider.cs b/Assets/Obi/Editor/Common/Blueprints/Properties/IObiPropertyEditableProvider.cs
new file mode 100644
index 000000000..f5345891b
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Properties/IObiPropertyEditableProvider.cs
@@ -0,0 +1,13 @@
+using UnityEngine;
+using System.Collections;
+
+namespace Obi
+{
+ public interface IObiSelectableParticleProvider
+ {
+ void SetSelected(int particleIndex, bool selected);
+ bool IsSelected(int particleIndex);
+ bool Editable(int particleIndex);
+ }
+
+}
\ No newline at end of file
diff --git a/Assets/Obi/Editor/Common/Blueprints/Properties/IObiPropertyEditableProvider.cs.meta b/Assets/Obi/Editor/Common/Blueprints/Properties/IObiPropertyEditableProvider.cs.meta
new file mode 100644
index 000000000..3bf0408fa
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Properties/IObiPropertyEditableProvider.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 0c3a2643915854763af75d63fa1ec0c9
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints/Properties/ObiBlueprintColor.cs b/Assets/Obi/Editor/Common/Blueprints/Properties/ObiBlueprintColor.cs
new file mode 100644
index 000000000..83d73b9fd
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Properties/ObiBlueprintColor.cs
@@ -0,0 +1,33 @@
+using UnityEngine;
+
+namespace Obi
+{
+ public class ObiBlueprintColor : ObiBlueprintColorProperty
+ {
+ public ObiBlueprintColor(ObiActorBlueprintEditor editor) : base(editor)
+ {
+ brushModes.Add(new ObiColorPaintBrushMode(this));
+ brushModes.Add(new ObiColorSmoothBrushMode(this));
+ }
+
+ public override string name
+ {
+ get { return "Color"; }
+ }
+
+ public override Color Get(int index)
+ {
+ return editor.blueprint.colors[index];
+ }
+ public override void Set(int index, Color value)
+ {
+ editor.blueprint.colors[index] = value;
+ editor.blueprint.edited = true;
+ }
+ public override bool Masked(int index)
+ {
+ return !editor.Editable(index);
+ }
+
+ }
+}
diff --git a/Assets/Obi/Editor/Common/Blueprints/Properties/ObiBlueprintColor.cs.meta b/Assets/Obi/Editor/Common/Blueprints/Properties/ObiBlueprintColor.cs.meta
new file mode 100644
index 000000000..a371aacab
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Properties/ObiBlueprintColor.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 810c95482e60a44209c5ece07e287153
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints/Properties/ObiBlueprintFilterCategory.cs b/Assets/Obi/Editor/Common/Blueprints/Properties/ObiBlueprintFilterCategory.cs
new file mode 100644
index 000000000..acd53eef4
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Properties/ObiBlueprintFilterCategory.cs
@@ -0,0 +1,32 @@
+namespace Obi
+{
+ public class ObiBlueprintFilterCategory : ObiBlueprintIntProperty
+ {
+ public ObiActorBlueprintEditor editor;
+
+ public ObiBlueprintFilterCategory(ObiActorBlueprintEditor editor) : base(ObiUtils.MinCategory, ObiUtils.MaxCategory)
+ {
+ this.editor = editor;
+ brushModes.Add(new ObiIntPaintBrushMode(this));
+ }
+
+ public override string name
+ {
+ get { return "Category"; }
+ }
+
+ public override int Get(int index)
+ {
+ return ObiUtils.GetCategoryFromFilter(editor.blueprint.filters[index]);
+ }
+ public override void Set(int index, int value)
+ {
+ editor.blueprint.filters[index] = ObiUtils.MakeFilter(ObiUtils.GetMaskFromFilter(editor.blueprint.filters[index]), value);
+ editor.blueprint.edited = true;
+ }
+ public override bool Masked(int index)
+ {
+ return !editor.Editable(index);
+ }
+ }
+}
diff --git a/Assets/Obi/Editor/Common/Blueprints/Properties/ObiBlueprintFilterCategory.cs.meta b/Assets/Obi/Editor/Common/Blueprints/Properties/ObiBlueprintFilterCategory.cs.meta
new file mode 100644
index 000000000..503074933
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Properties/ObiBlueprintFilterCategory.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 08502999496e54f49bb9dee0e0855794
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints/Properties/ObiBlueprintFilterMask.cs b/Assets/Obi/Editor/Common/Blueprints/Properties/ObiBlueprintFilterMask.cs
new file mode 100644
index 000000000..6c2d57b57
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Properties/ObiBlueprintFilterMask.cs
@@ -0,0 +1,32 @@
+namespace Obi
+{
+ public class ObiBlueprintFilterMask : ObiBlueprintMaskProperty
+ {
+ public ObiActorBlueprintEditor editor;
+
+ public ObiBlueprintFilterMask(ObiActorBlueprintEditor editor)
+ {
+ this.editor = editor;
+ brushModes.Add(new ObiIntPaintBrushMode(this));
+ }
+
+ public override string name
+ {
+ get { return "Collides with"; }
+ }
+
+ public override int Get(int index)
+ {
+ return ObiUtils.GetMaskFromFilter(editor.blueprint.filters[index]);
+ }
+ public override void Set(int index, int value)
+ {
+ editor.blueprint.filters[index] = ObiUtils.MakeFilter(value,ObiUtils.GetCategoryFromFilter(editor.blueprint.filters[index]));
+ editor.blueprint.edited = true;
+ }
+ public override bool Masked(int index)
+ {
+ return !editor.Editable(index);
+ }
+ }
+}
diff --git a/Assets/Obi/Editor/Common/Blueprints/Properties/ObiBlueprintFilterMask.cs.meta b/Assets/Obi/Editor/Common/Blueprints/Properties/ObiBlueprintFilterMask.cs.meta
new file mode 100644
index 000000000..2bdf6b4af
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Properties/ObiBlueprintFilterMask.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: ead8a00c964834718a2411be5d7361f3
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints/Properties/ObiBlueprintMass.cs b/Assets/Obi/Editor/Common/Blueprints/Properties/ObiBlueprintMass.cs
new file mode 100644
index 000000000..32b0e3dd6
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Properties/ObiBlueprintMass.cs
@@ -0,0 +1,33 @@
+namespace Obi
+{
+ public class ObiBlueprintMass : ObiBlueprintFloatProperty
+ {
+
+ public ObiBlueprintMass(ObiActorBlueprintEditor editor) : base(editor,0)
+ {
+ brushModes.Add(new ObiFloatPaintBrushMode(this));
+ brushModes.Add(new ObiFloatAddBrushMode(this));
+ brushModes.Add(new ObiFloatCopyBrushMode(this, this));
+ brushModes.Add(new ObiFloatSmoothBrushMode(this));
+ }
+
+ public override string name
+ {
+ get { return "Mass"; }
+ }
+
+ public override float Get(int index)
+ {
+ return ObiUtils.InvMassToMass(editor.blueprint.invMasses[index]);
+ }
+ public override void Set(int index, float value)
+ {
+ editor.blueprint.invMasses[index] = ObiUtils.MassToInvMass(value);
+ editor.blueprint.edited = true;
+ }
+ public override bool Masked(int index)
+ {
+ return !editor.Editable(index);
+ }
+ }
+}
diff --git a/Assets/Obi/Editor/Common/Blueprints/Properties/ObiBlueprintMass.cs.meta b/Assets/Obi/Editor/Common/Blueprints/Properties/ObiBlueprintMass.cs.meta
new file mode 100644
index 000000000..7dcb1686f
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Properties/ObiBlueprintMass.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: bd39fbd4c226542e58dc8ecceb5f8f14
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints/Properties/ObiBlueprintRadius.cs b/Assets/Obi/Editor/Common/Blueprints/Properties/ObiBlueprintRadius.cs
new file mode 100644
index 000000000..21f8d384e
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Properties/ObiBlueprintRadius.cs
@@ -0,0 +1,37 @@
+using UnityEngine;
+
+namespace Obi
+{
+ public class ObiBlueprintRadius : ObiBlueprintFloatProperty
+ {
+
+ public ObiBlueprintRadius(ObiActorBlueprintEditor editor) : base(editor,0.0000001f)
+ {
+ brushModes.Add(new ObiFloatPaintBrushMode(this));
+ brushModes.Add(new ObiFloatAddBrushMode(this));
+ brushModes.Add(new ObiFloatCopyBrushMode(this, this));
+ brushModes.Add(new ObiFloatSmoothBrushMode(this));
+ }
+
+ public override string name
+ {
+ get { return "Radius"; }
+ }
+
+ public override float Get(int index)
+ {
+ return editor.blueprint.principalRadii[index][0];
+ }
+ public override void Set(int index, float value)
+ {
+ value = Mathf.Max(0.0000001f, value);
+ float ratio = value / Get(index);
+ editor.blueprint.principalRadii[index] = editor.blueprint.principalRadii[index] * ratio;
+ editor.blueprint.edited = true;
+ }
+ public override bool Masked(int index)
+ {
+ return !editor.Editable(index);
+ }
+ }
+}
diff --git a/Assets/Obi/Editor/Common/Blueprints/Properties/ObiBlueprintRadius.cs.meta b/Assets/Obi/Editor/Common/Blueprints/Properties/ObiBlueprintRadius.cs.meta
new file mode 100644
index 000000000..174009811
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Properties/ObiBlueprintRadius.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: b5c61b50f6f4a468aa246f01e5268831
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints/Properties/ObiBlueprintSelected.cs b/Assets/Obi/Editor/Common/Blueprints/Properties/ObiBlueprintSelected.cs
new file mode 100644
index 000000000..920a50202
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Properties/ObiBlueprintSelected.cs
@@ -0,0 +1,29 @@
+namespace Obi
+{
+ public class ObiBlueprintSelected : ObiBlueprintBoolProperty
+ {
+ public IObiSelectableParticleProvider provider;
+ public ObiBlueprintSelected(IObiSelectableParticleProvider provider)
+ {
+ this.provider = provider;
+ }
+
+ public override string name
+ {
+ get { return "Selected"; }
+ }
+
+ public override bool Get(int index)
+ {
+ return provider.IsSelected(index);
+ }
+ public override void Set(int index, bool value)
+ {
+ provider.SetSelected(index,value);
+ }
+ public override bool Masked(int index)
+ {
+ return !provider.Editable(index);
+ }
+ }
+}
diff --git a/Assets/Obi/Editor/Common/Blueprints/Properties/ObiBlueprintSelected.cs.meta b/Assets/Obi/Editor/Common/Blueprints/Properties/ObiBlueprintSelected.cs.meta
new file mode 100644
index 000000000..d46419e14
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/Properties/ObiBlueprintSelected.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 270971958421b4fec9e5a5ba95699518
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints/RenderModes.meta b/Assets/Obi/Editor/Common/Blueprints/RenderModes.meta
new file mode 100644
index 000000000..d44e8e2f7
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/RenderModes.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: be5de82c95ded480d881176f73fc19b7
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints/RenderModes/ObiBlueprintRenderMode.cs b/Assets/Obi/Editor/Common/Blueprints/RenderModes/ObiBlueprintRenderMode.cs
new file mode 100644
index 000000000..0b780b88f
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/RenderModes/ObiBlueprintRenderMode.cs
@@ -0,0 +1,25 @@
+using UnityEngine;
+using UnityEditor;
+using System.Collections;
+
+namespace Obi
+{
+ public abstract class ObiBlueprintRenderMode
+ {
+ protected ObiActorBlueprintEditor editor;
+ public abstract string name
+ {
+ get;
+ }
+ public ObiBlueprintRenderMode(ObiActorBlueprintEditor editor)
+ {
+ this.editor = editor;
+ }
+
+ public virtual void DrawWithCamera(Camera camera) {}
+ public virtual void OnSceneRepaint(SceneView sceneView) {}
+ public virtual void Refresh(){}
+
+ public virtual void OnDestroy() { }
+ }
+}
\ No newline at end of file
diff --git a/Assets/Obi/Editor/Common/Blueprints/RenderModes/ObiBlueprintRenderMode.cs.meta b/Assets/Obi/Editor/Common/Blueprints/RenderModes/ObiBlueprintRenderMode.cs.meta
new file mode 100644
index 000000000..585711f9b
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/RenderModes/ObiBlueprintRenderMode.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: d60f616a126974e6d8be81fbbe459bac
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints/RenderModes/ObiBlueprintRenderModeAerodynamicConstraints.cs b/Assets/Obi/Editor/Common/Blueprints/RenderModes/ObiBlueprintRenderModeAerodynamicConstraints.cs
new file mode 100644
index 000000000..eeb6854bf
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/RenderModes/ObiBlueprintRenderModeAerodynamicConstraints.cs
@@ -0,0 +1,63 @@
+using UnityEngine;
+using UnityEditor;
+using System.Collections.Generic;
+
+namespace Obi
+{
+ public class ObiBlueprintRenderModeAerodynamicConstraints : ObiBlueprintRenderMode
+ {
+ public override string name
+ {
+ get { return "Aerodynamic constraints"; }
+ }
+
+ public ObiMeshBasedActorBlueprintEditor meshBasedEditor
+ {
+ get { return editor as ObiMeshBasedActorBlueprintEditor; }
+ }
+
+ public ObiBlueprintRenderModeAerodynamicConstraints(ObiMeshBasedActorBlueprintEditor editor) : base(editor)
+ {
+ }
+
+ public override void OnSceneRepaint(SceneView sceneView)
+ {
+ var meshEditor = editor as ObiMeshBasedActorBlueprintEditor;
+ if (meshEditor != null)
+ {
+ // Get per-particle normals:
+ Vector3[] normals = meshEditor.sourceMesh.normals;
+ Vector3[] particleNormals = new Vector3[meshEditor.blueprint.particleCount];
+ for (int i = 0; i < normals.Length; ++i)
+ {
+ int welded = meshEditor.VertexToParticle(i);
+ particleNormals[welded] = normals[i];
+ }
+
+ using (new Handles.DrawingScope(Color.blue, Matrix4x4.identity))
+ {
+ var constraints = editor.blueprint.GetConstraintsByType(Oni.ConstraintType.Aerodynamics) as ObiConstraints;
+ if (constraints != null)
+ {
+ Vector3[] lines = new Vector3[constraints.GetActiveConstraintCount() * 2];
+ int lineIndex = 0;
+
+ foreach (var batch in constraints.batches)
+ {
+ for (int i = 0; i < batch.activeConstraintCount; ++i)
+ {
+ int particleIndex = batch.particleIndices[i];
+ Vector3 position = editor.blueprint.GetParticlePosition(particleIndex);
+ lines[lineIndex++] = position;
+ lines[lineIndex++] = position + particleNormals[particleIndex] * 0.025f;
+ }
+ }
+
+ Handles.DrawLines(lines);
+ }
+ }
+ }
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/Assets/Obi/Editor/Common/Blueprints/RenderModes/ObiBlueprintRenderModeAerodynamicConstraints.cs.meta b/Assets/Obi/Editor/Common/Blueprints/RenderModes/ObiBlueprintRenderModeAerodynamicConstraints.cs.meta
new file mode 100644
index 000000000..c6efaed72
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/RenderModes/ObiBlueprintRenderModeAerodynamicConstraints.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 18881e26e784d47aaa8aa27c93fe0b49
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints/RenderModes/ObiBlueprintRenderModeBendConstraints.cs b/Assets/Obi/Editor/Common/Blueprints/RenderModes/ObiBlueprintRenderModeBendConstraints.cs
new file mode 100644
index 000000000..a5f68cb9d
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/RenderModes/ObiBlueprintRenderModeBendConstraints.cs
@@ -0,0 +1,44 @@
+using UnityEngine;
+using UnityEditor;
+using System.Collections.Generic;
+
+namespace Obi
+{
+ public class ObiBlueprintRenderModeBendConstraints : ObiBlueprintRenderMode
+ {
+ public override string name
+ {
+ get { return "Bend constraints"; }
+ }
+
+ public ObiBlueprintRenderModeBendConstraints(ObiActorBlueprintEditor editor) : base(editor)
+ {
+ }
+
+ public override void OnSceneRepaint(SceneView sceneView)
+ {
+ using (new Handles.DrawingScope(Color.magenta, Matrix4x4.identity))
+ {
+ var constraints = editor.blueprint.GetConstraintsByType(Oni.ConstraintType.Bending) as ObiConstraints;
+ if (constraints != null)
+ {
+ Vector3[] lines = new Vector3[constraints.GetActiveConstraintCount() * 2];
+ int lineIndex = 0;
+
+ foreach (var batch in constraints.batches)
+ {
+ for (int i = 0; i < batch.activeConstraintCount; ++i)
+ {
+ lines[lineIndex++] = editor.blueprint.GetParticlePosition(batch.particleIndices[i * 3]);
+ lines[lineIndex++] = editor.blueprint.GetParticlePosition(batch.particleIndices[i * 3 + 1]);
+ }
+ }
+
+ Handles.DrawLines(lines);
+ }
+ }
+
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/Assets/Obi/Editor/Common/Blueprints/RenderModes/ObiBlueprintRenderModeBendConstraints.cs.meta b/Assets/Obi/Editor/Common/Blueprints/RenderModes/ObiBlueprintRenderModeBendConstraints.cs.meta
new file mode 100644
index 000000000..ec81849a4
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/RenderModes/ObiBlueprintRenderModeBendConstraints.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 15e21bc6bea1c4320948413c8d7334bd
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints/RenderModes/ObiBlueprintRenderModeDistanceConstraints.cs b/Assets/Obi/Editor/Common/Blueprints/RenderModes/ObiBlueprintRenderModeDistanceConstraints.cs
new file mode 100644
index 000000000..b4fb4f071
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/RenderModes/ObiBlueprintRenderModeDistanceConstraints.cs
@@ -0,0 +1,44 @@
+using UnityEngine;
+using UnityEditor;
+using System.Collections.Generic;
+
+namespace Obi
+{
+ public class ObiBlueprintRenderModeDistanceConstraints : ObiBlueprintRenderMode
+ {
+ public override string name
+ {
+ get { return "Distance constraints"; }
+ }
+
+ public ObiBlueprintRenderModeDistanceConstraints(ObiActorBlueprintEditor editor) : base(editor)
+ {
+ }
+
+ public override void OnSceneRepaint(SceneView sceneView)
+ {
+
+ using (new Handles.DrawingScope(Color.green, Matrix4x4.identity))
+ {
+ var constraints = editor.blueprint.GetConstraintsByType(Oni.ConstraintType.Distance) as ObiConstraints;
+ if (constraints != null)
+ {
+ Vector3[] lines = new Vector3[constraints.GetActiveConstraintCount() * 2];
+ int lineIndex = 0;
+
+ foreach (var batch in constraints.batches)
+ {
+ for (int i = 0; i < batch.activeConstraintCount; ++i)
+ {
+ lines[lineIndex++] = editor.blueprint.GetParticlePosition(batch.particleIndices[i * 2]);
+ lines[lineIndex++] = editor.blueprint.GetParticlePosition(batch.particleIndices[i * 2 + 1]);
+ }
+ }
+
+ Handles.DrawLines(lines);
+ }
+ }
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/Assets/Obi/Editor/Common/Blueprints/RenderModes/ObiBlueprintRenderModeDistanceConstraints.cs.meta b/Assets/Obi/Editor/Common/Blueprints/RenderModes/ObiBlueprintRenderModeDistanceConstraints.cs.meta
new file mode 100644
index 000000000..c6b32ad18
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/RenderModes/ObiBlueprintRenderModeDistanceConstraints.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: ac734c05a2b994f148fd43cd5829b1be
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints/RenderModes/ObiBlueprintRenderModeMesh.cs b/Assets/Obi/Editor/Common/Blueprints/RenderModes/ObiBlueprintRenderModeMesh.cs
new file mode 100644
index 000000000..2f3473b9d
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/RenderModes/ObiBlueprintRenderModeMesh.cs
@@ -0,0 +1,46 @@
+using UnityEditor;
+
+namespace Obi
+{
+ public class ObiBlueprintRenderModeMesh : ObiBlueprintRenderMode
+ {
+ public override string name
+ {
+ get { return "Mesh"; }
+ }
+
+ public ObiMeshBasedActorBlueprintEditor meshBasedEditor
+ {
+ get { return editor as ObiMeshBasedActorBlueprintEditor; }
+ }
+
+ public ObiBlueprintRenderModeMesh(ObiMeshBasedActorBlueprintEditor editor) : base(editor)
+ {
+ }
+
+ public override void OnSceneRepaint(SceneView sceneView)
+ {
+ if (meshBasedEditor.currentTool is ObiPaintBrushEditorTool)
+ {
+ ObiPaintBrushEditorTool paintTool = (ObiPaintBrushEditorTool)meshBasedEditor.currentTool;
+
+ float[] weights = new float[ObiActorBlueprintEditor.selectionStatus.Length];
+ for (int i = 0; i < weights.Length; i++)
+ {
+ if (paintTool.selectionMask && !ObiActorBlueprintEditor.selectionStatus[i])
+ weights[i] = 0;
+ else
+ weights[i] = 1;
+ }
+
+ float[] wireframeWeights = new float[paintTool.paintBrush.weights.Length];
+ for (int i = 0; i < wireframeWeights.Length; i++)
+ wireframeWeights[i] = paintTool.paintBrush.weights[i];
+
+ meshBasedEditor.DrawGradientMesh(weights, wireframeWeights);
+ }
+ else
+ meshBasedEditor.DrawGradientMesh();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/Obi/Editor/Common/Blueprints/RenderModes/ObiBlueprintRenderModeMesh.cs.meta b/Assets/Obi/Editor/Common/Blueprints/RenderModes/ObiBlueprintRenderModeMesh.cs.meta
new file mode 100644
index 000000000..19cb4d496
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/RenderModes/ObiBlueprintRenderModeMesh.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: dbcd302f71d6446cd976f736b365c7ba
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints/RenderModes/ObiBlueprintRenderModeParticles.cs b/Assets/Obi/Editor/Common/Blueprints/RenderModes/ObiBlueprintRenderModeParticles.cs
new file mode 100644
index 000000000..47135af02
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/RenderModes/ObiBlueprintRenderModeParticles.cs
@@ -0,0 +1,65 @@
+using UnityEngine;
+using System.Collections;
+
+namespace Obi
+{
+ public class ObiBlueprintRenderModeParticles : ObiBlueprintRenderMode
+ {
+ public override string name
+ {
+ get { return "Particles"; }
+ }
+
+ private Shader shader;
+ private Material material;
+ private ParticleImpostorRendering impostorDrawer;
+ private MaterialPropertyBlock mpb;
+
+ public ObiBlueprintRenderModeParticles(ObiActorBlueprintEditor editor) :base(editor)
+ {
+ impostorDrawer = new ParticleImpostorRendering();
+ impostorDrawer.UpdateMeshes(editor.blueprint);
+ mpb = new MaterialPropertyBlock();
+ }
+
+ void CreateMaterialIfNeeded()
+ {
+ if (shader == null)
+ {
+ shader = Shader.Find("Obi/EditorParticles");
+ if (shader != null)
+ {
+ if (!shader.isSupported)
+ Debug.LogWarning("Particle rendering shader not suported.");
+
+ if (material == null || material.shader != shader)
+ {
+ GameObject.DestroyImmediate(material);
+ material = new Material(shader);
+ material.hideFlags = HideFlags.HideAndDontSave;
+ }
+ }
+ }
+ }
+
+ public override void DrawWithCamera(Camera camera)
+ {
+ CreateMaterialIfNeeded();
+ mpb.SetFloat("_RadiusScale", 1);
+ mpb.SetColor("_ParticleColor", Color.white);
+ foreach (Mesh mesh in impostorDrawer.Meshes)
+ Graphics.DrawMesh(mesh, Matrix4x4.identity, material, 0, camera, 0, mpb);
+ }
+
+ public override void Refresh()
+ {
+ impostorDrawer.UpdateMeshes(editor.blueprint, editor.visible, editor.tint);
+ }
+
+ public override void OnDestroy()
+ {
+ GameObject.DestroyImmediate(material);
+ impostorDrawer.ClearMeshes();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/Obi/Editor/Common/Blueprints/RenderModes/ObiBlueprintRenderModeParticles.cs.meta b/Assets/Obi/Editor/Common/Blueprints/RenderModes/ObiBlueprintRenderModeParticles.cs.meta
new file mode 100644
index 000000000..7e91ad77d
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/RenderModes/ObiBlueprintRenderModeParticles.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: b51ea2becbebe48ba9d77e9d28403f51
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints/RenderModes/ObiBlueprintRenderModeShapeMatchingConstraints.cs b/Assets/Obi/Editor/Common/Blueprints/RenderModes/ObiBlueprintRenderModeShapeMatchingConstraints.cs
new file mode 100644
index 000000000..582243824
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/RenderModes/ObiBlueprintRenderModeShapeMatchingConstraints.cs
@@ -0,0 +1,54 @@
+using UnityEngine;
+using UnityEditor;
+using System.Collections.Generic;
+
+namespace Obi
+{
+ public class ObiBlueprintRenderModeShapeMatchingConstraints : ObiBlueprintRenderMode
+ {
+ public override string name
+ {
+ get { return "Shape matching clusters"; }
+ }
+
+ public ObiBlueprintRenderModeShapeMatchingConstraints(ObiActorBlueprintEditor editor) : base(editor)
+ {
+ }
+
+ public override void OnSceneRepaint(SceneView sceneView)
+ {
+
+ using (new Handles.DrawingScope(Color.cyan, Matrix4x4.identity))
+ {
+ var constraints = editor.blueprint.GetConstraintsByType(Oni.ConstraintType.ShapeMatching) as ObiConstraints;
+ if (constraints != null)
+ {
+ List lines = new List();
+
+ foreach (var batch in constraints.batches)
+ {
+ for (int i = 0; i < batch.activeConstraintCount; ++i)
+ {
+ int first = batch.firstIndex[i];
+ Vector3 p1 = editor.blueprint.GetParticlePosition(batch.particleIndices[first]);
+
+ for (int j = 1; j < batch.numIndices[i]; ++j)
+ {
+
+ int index = first + j;
+ Vector3 p2 = editor.blueprint.GetParticlePosition(batch.particleIndices[index]);
+
+ lines.Add(p1);
+ lines.Add(p2);
+ }
+
+ }
+ }
+
+ Handles.DrawLines(lines.ToArray());
+ }
+ }
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/Assets/Obi/Editor/Common/Blueprints/RenderModes/ObiBlueprintRenderModeShapeMatchingConstraints.cs.meta b/Assets/Obi/Editor/Common/Blueprints/RenderModes/ObiBlueprintRenderModeShapeMatchingConstraints.cs.meta
new file mode 100644
index 000000000..201059f1d
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/RenderModes/ObiBlueprintRenderModeShapeMatchingConstraints.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: e5ff128cfebee45ffb8266eb3e75522e
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Blueprints/RenderModes/ObiBlueprintRenderModeTetherConstraints.cs b/Assets/Obi/Editor/Common/Blueprints/RenderModes/ObiBlueprintRenderModeTetherConstraints.cs
new file mode 100644
index 000000000..bd33fafd7
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/RenderModes/ObiBlueprintRenderModeTetherConstraints.cs
@@ -0,0 +1,43 @@
+using UnityEngine;
+using UnityEditor;
+using System.Collections.Generic;
+
+namespace Obi
+{
+ public class ObiBlueprintRenderModeTetherConstraints : ObiBlueprintRenderMode
+ {
+ public override string name
+ {
+ get { return "Tether constraints"; }
+ }
+
+ public ObiBlueprintRenderModeTetherConstraints(ObiActorBlueprintEditor editor) : base(editor)
+ {
+ }
+
+ public override void OnSceneRepaint(SceneView sceneView)
+ {
+ using (new Handles.DrawingScope(Color.yellow, Matrix4x4.identity))
+ {
+ var constraints = editor.blueprint.GetConstraintsByType(Oni.ConstraintType.Tether) as ObiConstraints;
+ if (constraints != null)
+ {
+ Vector3[] lines = new Vector3[constraints.GetActiveConstraintCount() * 2];
+ int lineIndex = 0;
+
+ foreach (var batch in constraints.batches)
+ {
+ for (int i = 0; i < batch.activeConstraintCount; ++i)
+ {
+ lines[lineIndex++] = editor.blueprint.GetParticlePosition(batch.particleIndices[i * 2]);
+ lines[lineIndex++] = editor.blueprint.GetParticlePosition(batch.particleIndices[i * 2 + 1]);
+ }
+ }
+
+ Handles.DrawLines(lines);
+ }
+ }
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/Assets/Obi/Editor/Common/Blueprints/RenderModes/ObiBlueprintRenderModeTetherConstraints.cs.meta b/Assets/Obi/Editor/Common/Blueprints/RenderModes/ObiBlueprintRenderModeTetherConstraints.cs.meta
new file mode 100644
index 000000000..948860366
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Blueprints/RenderModes/ObiBlueprintRenderModeTetherConstraints.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 63054cbedb75c4aa7906bf1c24552085
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Collisions.meta b/Assets/Obi/Editor/Common/Collisions.meta
new file mode 100644
index 000000000..e3f2bc768
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Collisions.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 5759f1c7beafc485489fb47abffaa269
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Collisions/ObiColliderEditor.cs b/Assets/Obi/Editor/Common/Collisions/ObiColliderEditor.cs
new file mode 100644
index 000000000..548574a92
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Collisions/ObiColliderEditor.cs
@@ -0,0 +1,110 @@
+using UnityEditor;
+using UnityEngine;
+
+namespace Obi
+{
+
+ [CustomEditor(typeof(ObiColliderBase), true), CanEditMultipleObjects]
+ public class ObiColliderEditor : Editor
+ {
+
+ ObiColliderBase collider;
+ SerializedProperty collisionFilter;
+
+ public void OnEnable()
+ {
+ collider = (ObiColliderBase)target;
+ collisionFilter = serializedObject.FindProperty("filter");
+ }
+
+ protected void NonReadableMeshWarning(Mesh mesh)
+ {
+ EditorGUILayout.BeginVertical(EditorStyles.helpBox);
+ Texture2D icon = EditorGUIUtility.Load("icons/console.erroricon.png") as Texture2D;
+ EditorGUILayout.LabelField(new GUIContent("The input mesh is not readable. Read/Write must be enabled in the mesh import settings.", icon), EditorStyles.wordWrappedMiniLabel);
+
+ EditorGUILayout.BeginHorizontal();
+ GUILayout.FlexibleSpace();
+ if (GUILayout.Button("Fix now", GUILayout.MaxWidth(100), GUILayout.MinHeight(32)))
+ {
+ string assetPath = AssetDatabase.GetAssetPath(mesh);
+ ModelImporter modelImporter = AssetImporter.GetAtPath(assetPath) as ModelImporter;
+ if (modelImporter != null)
+ {
+ modelImporter.isReadable = true;
+ }
+ modelImporter.SaveAndReimport();
+ }
+ EditorGUILayout.EndHorizontal();
+ EditorGUILayout.EndVertical();
+ }
+
+ public override void OnInspectorGUI()
+ {
+
+ serializedObject.UpdateIfRequiredOrScript();
+
+ foreach (ObiColliderBase t in targets)
+ {
+ ObiMeshShapeTracker meshTracker = t.Tracker as ObiMeshShapeTracker;
+ if (meshTracker != null)
+ {
+ if (meshTracker.targetMesh != null && !meshTracker.targetMesh.isReadable)
+ NonReadableMeshWarning(meshTracker.targetMesh);
+ }
+ }
+
+ var rect = EditorGUILayout.GetControlRect();
+ var label = EditorGUI.BeginProperty(rect, new GUIContent("Collision category"), collisionFilter);
+ rect = EditorGUI.PrefixLabel(rect, label);
+
+ EditorGUI.BeginChangeCheck();
+ var newCategory = EditorGUI.Popup(rect, ObiUtils.GetCategoryFromFilter(collider.Filter), ObiUtils.categoryNames);
+ if (EditorGUI.EndChangeCheck())
+ {
+ foreach (ObiColliderBase t in targets)
+ {
+ Undo.RecordObject(t, "Set collision category");
+ t.Filter = ObiUtils.MakeFilter(ObiUtils.GetMaskFromFilter(t.Filter), newCategory);
+ PrefabUtility.RecordPrefabInstancePropertyModifications(t);
+ }
+ }
+ EditorGUI.EndProperty();
+
+ rect = EditorGUILayout.GetControlRect();
+ label = EditorGUI.BeginProperty(rect, new GUIContent("Collides with"), collisionFilter);
+ rect = EditorGUI.PrefixLabel(rect, label);
+
+ EditorGUI.BeginChangeCheck();
+ var newMask = EditorGUI.MaskField(rect, ObiUtils.GetMaskFromFilter(collider.Filter), ObiUtils.categoryNames);
+ if (EditorGUI.EndChangeCheck())
+ {
+ foreach (ObiColliderBase t in targets)
+ {
+ Undo.RecordObject(t, "Set collision mask");
+ t.Filter = ObiUtils.MakeFilter(newMask, ObiUtils.GetCategoryFromFilter(t.Filter));
+ PrefabUtility.RecordPrefabInstancePropertyModifications(t);
+ }
+ }
+ EditorGUI.EndProperty();
+
+ DrawPropertiesExcluding(serializedObject, "m_Script", "CollisionMaterial", "filter", "Thickness", "Inverted");
+
+ foreach (ObiColliderBase t in targets)
+ {
+ if (!t.gameObject.isStatic)
+ t.ForceUpdate();
+ }
+
+ // Apply changes to the serializedProperty
+ if (GUI.changed)
+ {
+ serializedObject.ApplyModifiedProperties();
+ }
+
+ }
+
+ }
+}
+
+
diff --git a/Assets/Obi/Editor/Common/Collisions/ObiColliderEditor.cs.meta b/Assets/Obi/Editor/Common/Collisions/ObiColliderEditor.cs.meta
new file mode 100644
index 000000000..0373df8a6
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Collisions/ObiColliderEditor.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 7c99a0a8358754501b3c8089185b0e6f
+timeCreated: 1502034385
+licenseType: Store
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Collisions/ObiDistanceFieldEditor.cs b/Assets/Obi/Editor/Common/Collisions/ObiDistanceFieldEditor.cs
new file mode 100644
index 000000000..1ca4989cb
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Collisions/ObiDistanceFieldEditor.cs
@@ -0,0 +1,178 @@
+using UnityEngine;
+using UnityEditor;
+using System.IO;
+using System.Collections;
+
+namespace Obi{
+ [CustomEditor(typeof(ObiDistanceField))]
+ public class ObiDistanceFieldEditor : Editor
+ {
+
+ ObiDistanceField distanceField;
+
+ PreviewHelpers previewHelper;
+ Vector2 previewDir;
+ Material previewMaterial;
+
+ Mesh previewMesh;
+ Texture3D volumeTexture;
+
+ protected IEnumerator routine;
+
+ private void UpdatePreview(){
+
+ CleanupPreview();
+
+ if (distanceField.InputMesh != null){
+
+ previewMesh = CreateMeshForBounds(distanceField.FieldBounds);
+ previewMesh.hideFlags = HideFlags.HideAndDontSave;
+
+ volumeTexture = distanceField.GetVolumeTexture(64);
+ volumeTexture.hideFlags = HideFlags.HideAndDontSave;
+
+ previewMaterial = Resources.Load("DistanceFieldPreview");
+ previewMaterial.SetTexture("_Volume",volumeTexture);
+ previewMaterial.SetVector("_AABBMin",-distanceField.FieldBounds.extents);
+ previewMaterial.SetVector("_AABBMax",distanceField.FieldBounds.extents);
+ }
+
+ }
+
+ private void CleanupPreview(){
+ GameObject.DestroyImmediate(previewMesh);
+ GameObject.DestroyImmediate(volumeTexture);
+ }
+
+ public void OnEnable(){
+ distanceField = (ObiDistanceField) target;
+ previewHelper = new PreviewHelpers();
+ UpdatePreview();
+ }
+
+ public void OnDisable(){
+ EditorUtility.ClearProgressBar();
+ previewHelper.Cleanup();
+ CleanupPreview();
+ }
+
+ public override void OnInspectorGUI() {
+
+ serializedObject.UpdateIfRequiredOrScript();
+
+ Editor.DrawPropertiesExcluding(serializedObject,"m_Script");
+
+ GUI.enabled = (distanceField.InputMesh != null);
+ if (GUILayout.Button("Generate")){
+ // Start a coroutine job in the editor.
+ EditorUtility.SetDirty(target);
+ CoroutineJob job = new CoroutineJob();
+ routine = job.Start( distanceField.Generate());
+ EditorCoroutine.ShowCoroutineProgressBar("Generating distance field", routine);
+ UpdatePreview();
+ EditorGUIUtility.ExitGUI();
+ }
+ GUI.enabled = true;
+
+ int nodeCount = (distanceField.nodes != null ? distanceField.nodes.Count : 0);
+ float resolution = distanceField.FieldBounds.size.x / distanceField.EffectiveSampleSize;
+ EditorGUILayout.HelpBox("Nodes: "+ nodeCount+"\n"+
+ "Size in memory: "+ (nodeCount * 0.062f).ToString("0.#") +" kB\n"+
+ "Compressed to: " + (nodeCount / Mathf.Pow(resolution,3) * 100).ToString("0.##") + "%",MessageType.Info);
+
+ if (GUI.changed)
+ serializedObject.ApplyModifiedProperties();
+
+ }
+
+ public override bool HasPreviewGUI(){
+ return true;
+ }
+
+ public override void OnInteractivePreviewGUI(Rect region, GUIStyle background)
+ {
+ previewDir = PreviewHelpers.Drag2D(previewDir, region);
+
+ if (Event.current.type != EventType.Repaint || previewMesh == null)
+ {
+ return;
+ }
+
+ Quaternion quaternion = Quaternion.Euler(this.previewDir.y, 0f, 0f) * Quaternion.Euler(0f, this.previewDir.x, 0f) * Quaternion.Euler(0, 120, -20f);
+
+ previewHelper.BeginPreview(region, background);
+
+ Bounds bounds = previewMesh.bounds;
+ float magnitude = Mathf.Sqrt(bounds.extents.sqrMagnitude);
+ float num = 4f * magnitude;
+ previewHelper.m_Camera.transform.position = -Vector3.forward * num;
+ previewHelper.m_Camera.transform.rotation = Quaternion.identity;
+ previewHelper.m_Camera.nearClipPlane = num - magnitude * 1.1f;
+ previewHelper.m_Camera.farClipPlane = num + magnitude * 1.1f;
+
+ // Compute matrix to rotate the mesh around the center of its bounds:
+ Matrix4x4 matrix = Matrix4x4.TRS(Vector3.zero,quaternion,Vector3.one) * Matrix4x4.TRS(-bounds.center,Quaternion.identity,Vector3.one);
+
+ Graphics.DrawMesh(previewMesh, matrix, previewMaterial,1, previewHelper.m_Camera, 0);
+
+ Texture texture = previewHelper.EndPreview();
+ GUI.DrawTexture(region, texture, ScaleMode.StretchToFill, true);
+
+ }
+
+ /**
+ * Creates a solid mesh from some Bounds. This is used to display the distance field volumetric preview.
+ */
+ private Mesh CreateMeshForBounds(Bounds b){
+ Mesh m = new Mesh();
+
+ /** Indices of bounds corners:
+
+ Y
+ 2 6
+ +------+
+ 3 .'| 7 .'|
+ +---+--+' |
+ | | | |
+ | +--+---+ X
+ | .' 0 | .' 4
+ +------+'
+ Z 1 5
+
+ */
+ Vector3[] vertices = new Vector3[8]{
+ b.center + new Vector3(-b.extents.x,-b.extents.y,-b.extents.z), //0
+ b.center + new Vector3(-b.extents.x,-b.extents.y,b.extents.z), //1
+ b.center + new Vector3(-b.extents.x,b.extents.y,-b.extents.z), //2
+ b.center + new Vector3(-b.extents.x,b.extents.y,b.extents.z), //3
+ b.center + new Vector3(b.extents.x,-b.extents.y,-b.extents.z), //4
+ b.center + new Vector3(b.extents.x,-b.extents.y,b.extents.z), //5
+ b.center + new Vector3(b.extents.x,b.extents.y,-b.extents.z), //6
+ b.center + new Vector3(b.extents.x,b.extents.y,b.extents.z) //7
+ };
+ int[] triangles = new int[36]{
+ 2,3,7,
+ 6,2,7,
+
+ 7,5,4,
+ 6,7,4,
+
+ 3,1,5,
+ 7,3,5,
+
+ 2,0,3,
+ 3,0,1,
+
+ 6,4,2,
+ 2,4,0,
+
+ 4,5,0,
+ 5,1,0
+ };
+
+ m.vertices = vertices;
+ m.triangles = triangles;
+ return m;
+ }
+ }
+}
diff --git a/Assets/Obi/Editor/Common/Collisions/ObiDistanceFieldEditor.cs.meta b/Assets/Obi/Editor/Common/Collisions/ObiDistanceFieldEditor.cs.meta
new file mode 100644
index 000000000..60e8555ce
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Collisions/ObiDistanceFieldEditor.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 5d47dd3a8215841aca1fe5b272cb24f2
+timeCreated: 1507046737
+licenseType: Store
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Collisions/ObiForceZoneEditor.cs b/Assets/Obi/Editor/Common/Collisions/ObiForceZoneEditor.cs
new file mode 100644
index 000000000..884ac4c0e
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Collisions/ObiForceZoneEditor.cs
@@ -0,0 +1,30 @@
+using UnityEditor;
+using UnityEngine;
+
+namespace Obi
+{
+
+ /**
+ * Custom inspector for ObiForceZone component.
+ */
+
+ [CustomEditor(typeof(ObiForceZone)), CanEditMultipleObjects]
+ public class ObiForceZoneEditor : Editor
+ {
+
+ public override void OnInspectorGUI()
+ {
+
+ serializedObject.UpdateIfRequiredOrScript();
+
+ DrawPropertiesExcluding(serializedObject, "m_Script");
+
+ // Apply changes to the serializedProperty
+ if (GUI.changed)
+ serializedObject.ApplyModifiedProperties();
+ }
+
+ }
+
+}
+
diff --git a/Assets/Obi/Editor/Common/Collisions/ObiForceZoneEditor.cs.meta b/Assets/Obi/Editor/Common/Collisions/ObiForceZoneEditor.cs.meta
new file mode 100644
index 000000000..99479b1eb
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Collisions/ObiForceZoneEditor.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 724435a7a84154b27bb0c8ea49b611df
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Constraints.meta b/Assets/Obi/Editor/Common/Constraints.meta
new file mode 100644
index 000000000..8cfd63c92
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Constraints.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: cf28ba8ff6a7140e6a7e50a5030ff3e7
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Constraints/ObiConstraintParametersDrawer.cs b/Assets/Obi/Editor/Common/Constraints/ObiConstraintParametersDrawer.cs
new file mode 100644
index 000000000..579843b35
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Constraints/ObiConstraintParametersDrawer.cs
@@ -0,0 +1,73 @@
+using UnityEngine;
+using UnityEditor;
+using System;
+
+namespace Obi
+{
+
+ [CustomPropertyDrawer(typeof(Oni.ConstraintParameters))]
+ public class ObiConstraintParametersDrawer : PropertyDrawer
+ {
+ public static float padding = 4;
+
+ public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
+ {
+ float propHeight = EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
+
+ EditorGUI.BeginProperty(position, label, property);
+
+ SerializedProperty enabled = property.FindPropertyRelative("enabled");
+ Rect contRect = new Rect(position.x+padding, position.y+padding, position.width-padding*2, propHeight);
+
+ // Draw a box around the parameters:
+ GUI.enabled = enabled.boolValue;
+ GUI.Box(position,"",ObiEditorUtils.GetToggleablePropertyGroupStyle());
+ GUI.enabled = true;
+
+ // Draw main constraint toggle:
+ EditorGUI.BeginProperty(position, label, enabled);
+ EditorGUI.BeginChangeCheck();
+ var newEnabled = EditorGUI.ToggleLeft(contRect, label.text, enabled.boolValue, EditorStyles.boldLabel);
+ // Only assign the value back if it was actually changed by the user.
+ // Otherwise a single value will be assigned to all objects when multi-object editing,
+ // even when the user didn't touch the control.
+ if (EditorGUI.EndChangeCheck())
+ {
+ enabled.boolValue = newEnabled;
+ }
+ EditorGUI.EndProperty();
+
+ if (enabled.boolValue){
+
+ Rect evalRect = new Rect(position.x+padding, position.y+propHeight+padding, position.width-padding*2, propHeight);
+ Rect iterRect = new Rect(position.x+padding, position.y+propHeight*2+padding, position.width-padding*2, propHeight);
+ Rect sorRect = new Rect(position.x+padding, position.y+propHeight*3+padding, position.width-padding*2, EditorGUIUtility.singleLineHeight);
+
+ EditorGUI.indentLevel++;
+ Rect evalCtrl = EditorGUI.PrefixLabel(evalRect,new GUIContent("Evaluation"));
+ EditorGUI.PropertyField(evalCtrl, property.FindPropertyRelative("evaluationOrder"),GUIContent.none);
+
+ Rect iterCtrl = EditorGUI.PrefixLabel(iterRect,new GUIContent("Iterations"));
+ EditorGUI.PropertyField(iterCtrl, property.FindPropertyRelative("iterations"),GUIContent.none);
+
+ Rect sorCtrl = EditorGUI.PrefixLabel(sorRect,new GUIContent("Relaxation"));
+ EditorGUI.PropertyField(sorCtrl, property.FindPropertyRelative("SORFactor"),GUIContent.none);
+ EditorGUI.indentLevel--;
+
+ }
+
+ EditorGUI.EndProperty();
+ }
+
+ public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
+ {
+ SerializedProperty enabled = property.FindPropertyRelative("enabled");
+ if (enabled.boolValue)
+ return EditorGUIUtility.singleLineHeight*4 + EditorGUIUtility.standardVerticalSpacing*3 + padding*2;
+ else
+ return EditorGUIUtility.singleLineHeight + padding*2;
+ }
+ }
+
+}
+
diff --git a/Assets/Obi/Editor/Common/Constraints/ObiConstraintParametersDrawer.cs.meta b/Assets/Obi/Editor/Common/Constraints/ObiConstraintParametersDrawer.cs.meta
new file mode 100644
index 000000000..ec24a9697
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Constraints/ObiConstraintParametersDrawer.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: bc70cbc4838a4467687180e4d555b069
+timeCreated: 1515057027
+licenseType: Store
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/ObiAboutWindow.cs b/Assets/Obi/Editor/Common/ObiAboutWindow.cs
new file mode 100644
index 000000000..e7b22a08c
--- /dev/null
+++ b/Assets/Obi/Editor/Common/ObiAboutWindow.cs
@@ -0,0 +1,73 @@
+
+using System;
+using UnityEditor;
+using UnityEngine;
+
+namespace Obi
+{
+ public class ObiAboutWindow : EditorWindow
+ {
+
+ [MenuItem ("Window/Obi/About")]
+ public static void Init()
+ {
+ ObiAboutWindow window = (ObiAboutWindow)EditorWindow.GetWindow(typeof(ObiAboutWindow),true,"Welcome to Obi!");
+ window.position = new Rect(Screen.width / 2, Screen.height / 2, 380, 300);
+ window.maxSize = window.minSize = new Vector2(380,300);
+ window.ShowPopup();
+ }
+
+ void OnGUI()
+ {
+ // Draw logo and copyright notice:
+ EditorGUILayout.BeginHorizontal();
+
+ GUILayout.Label(Resources.Load("obi_editor_logo"));
+
+ EditorGUILayout.BeginVertical(GUILayout.MaxHeight(119.0f/EditorGUIUtility.pixelsPerPoint));
+
+ GUILayout.FlexibleSpace();
+
+ Color oldColor = GUI.contentColor;
+ GUI.contentColor = Color.black;
+ GUILayout.Label("Obi - Unified particle physics",EditorStyles.centeredGreyMiniLabel);
+ GUI.contentColor = oldColor;
+
+ GUILayout.Label("© Copyright Virtual Method, 2015-2016.\nAll rights reserved.",EditorStyles.centeredGreyMiniLabel);
+
+ GUILayout.FlexibleSpace();
+
+ EditorGUILayout.EndVertical();
+
+ EditorGUILayout.EndHorizontal();
+
+ DrawAboutGUI();
+
+ }
+
+ void DrawAboutGUI(){
+
+ GUILayout.FlexibleSpace();
+
+ EditorGUILayout.LabelField("Programming:",EditorStyles.centeredGreyMiniLabel);
+ EditorGUILayout.LabelField("José María Méndez González",EditorStyles.centeredGreyMiniLabel);
+
+ EditorGUILayout.LabelField("Additional resources:",EditorStyles.centeredGreyMiniLabel);
+ EditorGUILayout.LabelField("Lidia Martínez Prado",EditorStyles.centeredGreyMiniLabel);
+
+ GUILayout.FlexibleSpace();
+
+ if (GUILayout.Button("Manual",EditorStyles.toolbarButton))
+ Application.OpenURL("http://obi.virtualmethodstudio.com/tutorials/");
+ if (GUILayout.Button("API docs",EditorStyles.toolbarButton))
+ Application.OpenURL("http://obi.virtualmethodstudio.com/docs/");
+ if (GUILayout.Button("visit www.virtualmethodstudio.com",EditorStyles.toolbarButton))
+ Application.OpenURL("http://www.virtualmethodstudio.com");
+ if (GUILayout.Button("Create preferences file", EditorStyles.toolbarButton))
+ ObiEditorSettings.GetOrCreateSettings();
+
+ }
+ }
+}
+
+
diff --git a/Assets/Obi/Editor/Common/ObiAboutWindow.cs.meta b/Assets/Obi/Editor/Common/ObiAboutWindow.cs.meta
new file mode 100644
index 000000000..6166f573a
--- /dev/null
+++ b/Assets/Obi/Editor/Common/ObiAboutWindow.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: c6764c51caa004a25ab49afc9865d2b3
+timeCreated: 1498062614
+licenseType: Store
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/ObiSettingsProvider.cs b/Assets/Obi/Editor/Common/ObiSettingsProvider.cs
new file mode 100644
index 000000000..a03cb52b5
--- /dev/null
+++ b/Assets/Obi/Editor/Common/ObiSettingsProvider.cs
@@ -0,0 +1,81 @@
+using System.Collections.Generic;
+using System.IO;
+using UnityEditor;
+using UnityEngine;
+
+namespace Obi
+{
+ class ObiSettingsProvider : SettingsProvider
+ {
+ private SerializedObject m_ObiSettings;
+
+ class Styles
+ {
+ public static GUIContent particleBrush = new GUIContent("Brush");
+ public static GUIContent brushWireframe = new GUIContent("Brush wireframe");
+ public static GUIContent particle = new GUIContent("Particle");
+ public static GUIContent selectedParticle = new GUIContent("Selected particle");
+ public static GUIContent activeParticle = new GUIContent("Active particle");
+ public static GUIContent propertyGradient = new GUIContent("Property gradient");
+ public static GUIContent particlePicking = new GUIContent("Particle GO picking");
+ }
+
+ const string m_ObiEditorSettingsPath = "Assets/ObiEditorSettings.asset";
+ public ObiSettingsProvider(string path, SettingsScope scope = SettingsScope.User)
+ : base(path, scope) { }
+
+ public static bool IsSettingsAvailable()
+ {
+ return File.Exists(m_ObiEditorSettingsPath);
+ }
+
+#if UNITY_2019_1_OR_NEWER
+ public override void OnActivate(string searchContext, UnityEngine.UIElements.VisualElement rootElement)
+#else
+ public override void OnActivate(string searchContext, UnityEngine.Experimental.UIElements.VisualElement rootElement)
+#endif
+ {
+ // This function is called when the user clicks on the MyCustom element in the Settings window.
+ m_ObiSettings = ObiEditorSettings.GetSerializedSettings();
+ }
+
+ public override void OnDeactivate()
+ {
+ base.OnDeactivate();
+
+ if (m_ObiSettings != null)
+ m_ObiSettings.ApplyModifiedProperties();
+ }
+
+ public override void OnGUI(string searchContext)
+ {
+ EditorGUILayout.LabelField("Colors", EditorStyles.boldLabel);
+ EditorGUILayout.PropertyField(m_ObiSettings.FindProperty("m_ParticleBrush"), Styles.particleBrush);
+ EditorGUILayout.PropertyField(m_ObiSettings.FindProperty("m_BrushWireframe"),Styles.brushWireframe);
+ EditorGUILayout.PropertyField(m_ObiSettings.FindProperty("m_Particle"),Styles.particle);
+ EditorGUILayout.PropertyField(m_ObiSettings.FindProperty("m_SelectedParticle"),Styles.selectedParticle);
+ EditorGUILayout.PropertyField(m_ObiSettings.FindProperty("m_ActiveParticle"), Styles.activeParticle);
+ EditorGUILayout.PropertyField(m_ObiSettings.FindProperty("m_PropertyGradient"), Styles.propertyGradient);
+
+ EditorGUILayout.LabelField("Scene view", EditorStyles.boldLabel);
+ EditorGUILayout.PropertyField(m_ObiSettings.FindProperty("m_ParticlePicking"), Styles.particlePicking);
+ }
+
+ // Register the SettingsProvider
+ [SettingsProvider]
+ public static SettingsProvider CreateMyCustomSettingsProvider()
+ {
+ if (IsSettingsAvailable())
+ {
+ var provider = new ObiSettingsProvider("Preferences/Obi", SettingsScope.User);
+
+ // Automatically extract all keywords from the Styles.
+ provider.keywords = GetSearchKeywordsFromGUIContentProperties();
+ return provider;
+ }
+
+ // Settings Asset doesn't exist yet; no need to display anything in the Settings window.
+ return null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/Obi/Editor/Common/ObiSettingsProvider.cs.meta b/Assets/Obi/Editor/Common/ObiSettingsProvider.cs.meta
new file mode 100644
index 000000000..7c37da331
--- /dev/null
+++ b/Assets/Obi/Editor/Common/ObiSettingsProvider.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 19ac664f594284b3c92ddb354155d814
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Rendering.meta b/Assets/Obi/Editor/Common/Rendering.meta
new file mode 100644
index 000000000..07c70140c
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Rendering.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 60a71308789c34bb8a53415b380a6706
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Rendering/ObiParticleRendererEditor.cs b/Assets/Obi/Editor/Common/Rendering/ObiParticleRendererEditor.cs
new file mode 100644
index 000000000..310ac05e3
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Rendering/ObiParticleRendererEditor.cs
@@ -0,0 +1,32 @@
+using UnityEditor;
+using UnityEngine;
+
+namespace Obi{
+
+ /**
+ * Custom inspector for ObiParticleRenderer component.
+ */
+
+ [CustomEditor(typeof(ObiParticleRenderer)), CanEditMultipleObjects]
+ public class ObiParticleHandleEditor : Editor
+ {
+
+ public override void OnInspectorGUI() {
+
+ serializedObject.UpdateIfRequiredOrScript();
+
+ Editor.DrawPropertiesExcluding(serializedObject,"m_Script");
+
+ // Apply changes to the serializedProperty
+ if (GUI.changed){
+
+ serializedObject.ApplyModifiedProperties();
+
+ }
+
+ }
+
+ }
+
+}
+
diff --git a/Assets/Obi/Editor/Common/Rendering/ObiParticleRendererEditor.cs.meta b/Assets/Obi/Editor/Common/Rendering/ObiParticleRendererEditor.cs.meta
new file mode 100644
index 000000000..e249bdb53
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Rendering/ObiParticleRendererEditor.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 2a7e6fcc51ab349e687aa6ca5bdf6739
+timeCreated: 1463090765
+licenseType: Store
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Solver.meta b/Assets/Obi/Editor/Common/Solver.meta
new file mode 100644
index 000000000..0d6cdda63
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Solver.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: d82f874c48e764fb8b49f1767f76a94a
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Solver/ObiSolverEditor.cs b/Assets/Obi/Editor/Common/Solver/ObiSolverEditor.cs
new file mode 100644
index 000000000..bf3eebebb
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Solver/ObiSolverEditor.cs
@@ -0,0 +1,406 @@
+using UnityEditor;
+using UnityEngine;
+using UnityEditor.IMGUI.Controls;
+using UnityEditorInternal;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace Obi
+{
+
+ /**
+ * Custom inspector for ObiSolver components.
+ * Allows particle selection and constraint edition.
+ *
+ * Selection:
+ *
+ * - To select a particle, left-click on it.
+ * - You can select multiple particles by holding shift while clicking.
+ * - To deselect all particles, click anywhere on the object except a particle.
+ *
+ * Constraints:
+ *
+ * - To edit particle constraints, select the particles you wish to edit.
+ * - Constraints affecting any of the selected particles will appear in the inspector.
+ * - To add a new pin constraint to the selected particle(s), click on "Add Pin Constraint".
+ *
+ */
+ [CustomEditor(typeof(ObiSolver)), CanEditMultipleObjects]
+ public class ObiSolverEditor : Editor
+ {
+
+ [MenuItem("GameObject/3D Object/Obi/Obi Solver", false, 100)]
+ static void CreateObiSolver(MenuCommand menuCommand)
+ {
+ GameObject go = ObiEditorUtils.CreateNewSolver();
+ GameObjectUtility.SetParentAndAlign(go, menuCommand.context as GameObject);
+ Selection.activeGameObject = go;
+ }
+
+ ObiSolver solver;
+
+ SerializedProperty backend;
+ SerializedProperty substeps;
+ SerializedProperty maxStepsPerFrame;
+ SerializedProperty synchronization;
+ SerializedProperty simulateWhenInvisible;
+ SerializedProperty parameters;
+ SerializedProperty gravity;
+ SerializedProperty gravitySpace;
+ SerializedProperty ambientWind;
+ SerializedProperty windSpace;
+ SerializedProperty useLimits;
+ SerializedProperty boundaryLimits;
+ SerializedProperty killOffLimitsParticles;
+ SerializedProperty worldLinearInertiaScale;
+ SerializedProperty worldAngularInertiaScale;
+
+ SerializedProperty foamSubsteps;
+ SerializedProperty foamMinNeighbors;
+ SerializedProperty foamCollisions;
+ SerializedProperty foamRadiusScale;
+ SerializedProperty foamVolumeDensity;
+ SerializedProperty foamAmbientDensity;
+ SerializedProperty foamScatterColor;
+ SerializedProperty foamAmbientColor;
+ SerializedProperty maxFoamVelocityStretch;
+ SerializedProperty foamFade;
+ SerializedProperty foamAccelAgingRange;
+ SerializedProperty foamAccelAging;
+
+ SerializedProperty distanceConstraintParameters;
+ SerializedProperty bendingConstraintParameters;
+ SerializedProperty particleCollisionConstraintParameters;
+ SerializedProperty particleFrictionConstraintParameters;
+ SerializedProperty collisionConstraintParameters;
+ SerializedProperty frictionConstraintParameters;
+ SerializedProperty skinConstraintParameters;
+ SerializedProperty volumeConstraintParameters;
+ SerializedProperty shapeMatchingConstraintParameters;
+ SerializedProperty tetherConstraintParameters;
+ SerializedProperty pinConstraintParameters;
+ SerializedProperty pinholeConstraintParameters;
+ SerializedProperty stitchConstraintParameters;
+ SerializedProperty densityConstraintParameters;
+ SerializedProperty stretchShearConstraintParameters;
+ SerializedProperty bendTwistConstraintParameters;
+ SerializedProperty chainConstraintParameters;
+
+ SerializedProperty maxSurfaceChunks;
+ SerializedProperty maxQueryResults;
+ SerializedProperty maxFoamParticles;
+ SerializedProperty maxParticleNeighbors;
+ SerializedProperty maxParticleContacts;
+
+ BooleanPreference solverFoldout;
+ BooleanPreference simulationFoldout;
+ BooleanPreference advectionFoldout;
+ BooleanPreference collisionsFoldout;
+ BooleanPreference constraintsFoldout;
+ BooleanPreference memoryFoldout;
+
+ GUIContent constraintLabelContent;
+
+ BoxBoundsHandle limitsBoxHandle;
+
+ public void OnEnable()
+ {
+ solver = (ObiSolver)target;
+ constraintLabelContent = new GUIContent();
+ limitsBoxHandle = new BoxBoundsHandle();
+
+ solverFoldout = new BooleanPreference($"{target.GetType()}.solverFoldout", true);
+ simulationFoldout = new BooleanPreference($"{target.GetType()}.simulationFoldout", false);
+ advectionFoldout = new BooleanPreference($"{target.GetType()}.advectionFoldout", false);
+ collisionsFoldout = new BooleanPreference($"{target.GetType()}.collisionsFoldout", false);
+ constraintsFoldout = new BooleanPreference($"{target.GetType()}.constraintsFoldout", false);
+ memoryFoldout = new BooleanPreference($"{target.GetType()}.memoryFoldout", false);
+
+ backend = serializedObject.FindProperty("m_Backend");
+ substeps = serializedObject.FindProperty("substeps");
+ maxStepsPerFrame = serializedObject.FindProperty("maxStepsPerFrame");
+ synchronization = serializedObject.FindProperty("synchronization");
+ simulateWhenInvisible = serializedObject.FindProperty("simulateWhenInvisible");
+ parameters = serializedObject.FindProperty("parameters");
+ gravity = serializedObject.FindProperty("gravity");
+ gravitySpace = serializedObject.FindProperty("gravitySpace");
+ ambientWind = serializedObject.FindProperty("ambientWind");
+ windSpace = serializedObject.FindProperty("windSpace");
+ useLimits = serializedObject.FindProperty("useLimits");
+ boundaryLimits = serializedObject.FindProperty("boundaryLimits");
+ killOffLimitsParticles = serializedObject.FindProperty("killOffLimitsParticles");
+ worldLinearInertiaScale = serializedObject.FindProperty("worldLinearInertiaScale");
+ worldAngularInertiaScale = serializedObject.FindProperty("worldAngularInertiaScale");
+
+ foamSubsteps = serializedObject.FindProperty("foamSubsteps");
+ foamMinNeighbors = serializedObject.FindProperty("foamMinNeighbors");
+ foamCollisions = serializedObject.FindProperty("foamCollisions");
+ foamRadiusScale = serializedObject.FindProperty("foamRadiusScale");
+ foamVolumeDensity = serializedObject.FindProperty("foamVolumeDensity");
+ foamAmbientDensity = serializedObject.FindProperty("foamAmbientDensity");
+ foamScatterColor = serializedObject.FindProperty("foamScatterColor");
+ foamAmbientColor = serializedObject.FindProperty("foamAmbientColor");
+ maxFoamVelocityStretch = serializedObject.FindProperty("maxFoamVelocityStretch");
+ foamFade = serializedObject.FindProperty("foamFade");
+ foamAccelAgingRange = serializedObject.FindProperty("foamAccelAgingRange");
+ foamAccelAging = serializedObject.FindProperty("foamAccelAging");
+
+ distanceConstraintParameters = serializedObject.FindProperty("distanceConstraintParameters");
+ bendingConstraintParameters = serializedObject.FindProperty("bendingConstraintParameters");
+ particleCollisionConstraintParameters = serializedObject.FindProperty("particleCollisionConstraintParameters");
+ particleFrictionConstraintParameters = serializedObject.FindProperty("particleFrictionConstraintParameters");
+ collisionConstraintParameters = serializedObject.FindProperty("collisionConstraintParameters");
+ frictionConstraintParameters = serializedObject.FindProperty("frictionConstraintParameters");
+ skinConstraintParameters = serializedObject.FindProperty("skinConstraintParameters");
+ volumeConstraintParameters = serializedObject.FindProperty("volumeConstraintParameters");
+ shapeMatchingConstraintParameters = serializedObject.FindProperty("shapeMatchingConstraintParameters");
+ tetherConstraintParameters = serializedObject.FindProperty("tetherConstraintParameters");
+ pinConstraintParameters = serializedObject.FindProperty("pinConstraintParameters");
+ pinholeConstraintParameters = serializedObject.FindProperty("pinholeConstraintParameters");
+ stitchConstraintParameters = serializedObject.FindProperty("stitchConstraintParameters");
+ densityConstraintParameters = serializedObject.FindProperty("densityConstraintParameters");
+ stretchShearConstraintParameters = serializedObject.FindProperty("stretchShearConstraintParameters");
+ bendTwistConstraintParameters = serializedObject.FindProperty("bendTwistConstraintParameters");
+ chainConstraintParameters = serializedObject.FindProperty("chainConstraintParameters");
+
+ maxSurfaceChunks = serializedObject.FindProperty("m_MaxSurfaceChunks");
+ maxQueryResults = serializedObject.FindProperty("maxQueryResults");
+ maxFoamParticles = serializedObject.FindProperty("maxFoamParticles");
+ maxParticleNeighbors = serializedObject.FindProperty("maxParticleNeighbors");
+ maxParticleContacts = serializedObject.FindProperty("maxParticleContacts");
+ }
+
+ public void OnSceneGUI()
+ {
+ if (solver.useLimits)
+ {
+ using (new Handles.DrawingScope(Color.red, solver.transform.localToWorldMatrix))
+ {
+ limitsBoxHandle.center = solver.boundaryLimits.center;
+ limitsBoxHandle.size = solver.boundaryLimits.size;
+
+ EditorGUI.BeginChangeCheck();
+ limitsBoxHandle.DrawHandle();
+ if (EditorGUI.EndChangeCheck())
+ {
+ solver.boundaryLimits = new Bounds(limitsBoxHandle.center, limitsBoxHandle.size);
+ EditorUtility.SetDirty(target);
+ }
+ }
+ }
+ }
+
+ public override void OnInspectorGUI()
+ {
+ serializedObject.UpdateIfRequiredOrScript();
+ EditorGUILayout.HelpBox("Particles:" + solver.allocParticleCount + "\n" +
+ "Simplices:" + solver.simplexCounts.simplexCount + "\n" +
+ "Contacts:" + solver.contactCount + "\n" +
+ "Simplex contacts:" + solver.particleContactCount, MessageType.None);
+
+ solverFoldout.value = EditorGUILayout.BeginFoldoutHeaderGroup(solverFoldout, "Solver settings");
+ if (solverFoldout)
+ {
+ EditorGUI.BeginChangeCheck();
+ EditorGUILayout.PropertyField(backend);
+
+#if !(OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
+ if (backend.enumValueIndex == (int)ObiSolver.BackendType.Burst)
+ EditorGUILayout.HelpBox("The Burst backend depends on the following packages: Mathematics, Collections, Jobs and Burst. Please install the required dependencies. The solver will try to fall back to the Compute backend instead.", MessageType.Warning);
+#endif
+ if (!SystemInfo.supportsComputeShaders)
+ {
+ EditorGUILayout.HelpBox("This platform doesn't support compute shaders. Please switch to the Burst backend.", MessageType.Error);
+ }
+
+
+ if (EditorGUI.EndChangeCheck())
+ {
+ serializedObject.ApplyModifiedProperties();
+ foreach (var t in targets)
+ (t as ObiSolver).UpdateBackend();
+ }
+
+ EditorGUILayout.PropertyField(parameters.FindPropertyRelative("mode"));
+ EditorGUILayout.PropertyField(parameters.FindPropertyRelative("interpolation"));
+ EditorGUILayout.PropertyField(synchronization);
+ EditorGUILayout.PropertyField(substeps);
+ EditorGUILayout.PropertyField(maxStepsPerFrame);
+ }
+ EditorGUILayout.EndFoldoutHeaderGroup();
+
+ simulationFoldout.value = EditorGUILayout.BeginFoldoutHeaderGroup(simulationFoldout, "Simulation settings");
+ if (simulationFoldout)
+ {
+ EditorGUILayout.PropertyField(gravitySpace);
+ EditorGUILayout.PropertyField(gravity);
+ EditorGUILayout.PropertyField(windSpace);
+ EditorGUILayout.PropertyField(ambientWind);
+ EditorGUILayout.PropertyField(parameters.FindPropertyRelative("sleepThreshold"));
+ EditorGUILayout.PropertyField(parameters.FindPropertyRelative("maxVelocity"));
+ EditorGUILayout.PropertyField(parameters.FindPropertyRelative("maxAngularVelocity"));
+ EditorGUILayout.PropertyField(parameters.FindPropertyRelative("damping"));
+ EditorGUILayout.PropertyField(worldLinearInertiaScale);
+ EditorGUILayout.PropertyField(worldAngularInertiaScale);
+ EditorGUILayout.PropertyField(parameters.FindPropertyRelative("maxAnisotropy"));
+ EditorGUILayout.PropertyField(simulateWhenInvisible);
+ EditorGUILayout.PropertyField(useLimits);
+ if (useLimits.boolValue)
+ {
+ EditorGUI.indentLevel++;
+ EditorGUILayout.PropertyField(killOffLimitsParticles);
+ EditorGUILayout.PropertyField(boundaryLimits);
+ EditorGUI.indentLevel--;
+ }
+ }
+ EditorGUILayout.EndFoldoutHeaderGroup();
+
+ advectionFoldout.value = EditorGUILayout.BeginFoldoutHeaderGroup(advectionFoldout, "Foam settings");
+ if (advectionFoldout)
+ {
+ EditorGUILayout.PropertyField(foamSubsteps);
+ EditorGUILayout.PropertyField(foamMinNeighbors);
+ EditorGUILayout.PropertyField(foamCollisions, new GUIContent("Foam Collisions (Compute only)"));
+ EditorGUILayout.PropertyField(foamRadiusScale);
+ EditorGUILayout.PropertyField(foamVolumeDensity);
+ EditorGUILayout.PropertyField(foamAmbientDensity);
+ EditorGUILayout.PropertyField(foamScatterColor);
+ EditorGUILayout.PropertyField(foamAmbientColor);
+ EditorGUILayout.PropertyField(maxFoamVelocityStretch);
+ EditorGUILayout.PropertyField(parameters.FindPropertyRelative("foamGravityScale"));
+ EditorGUILayout.PropertyField(foamFade);
+ EditorGUILayout.PropertyField(foamAccelAgingRange);
+ EditorGUILayout.PropertyField(foamAccelAging);
+ }
+ EditorGUILayout.EndFoldoutHeaderGroup();
+
+ collisionsFoldout.value = EditorGUILayout.BeginFoldoutHeaderGroup(collisionsFoldout, "Collision settings");
+ if (collisionsFoldout)
+ {
+ EditorGUILayout.PropertyField(parameters.FindPropertyRelative("colliderCCD"));
+ EditorGUILayout.PropertyField(parameters.FindPropertyRelative("particleCCD"));
+ EditorGUILayout.PropertyField(parameters.FindPropertyRelative("collisionMargin"));
+ EditorGUILayout.PropertyField(parameters.FindPropertyRelative("maxDepenetration"));
+ EditorGUILayout.PropertyField(parameters.FindPropertyRelative("shockPropagation"));
+ EditorGUILayout.PropertyField(parameters.FindPropertyRelative("surfaceCollisionIterations"));
+ EditorGUILayout.PropertyField(parameters.FindPropertyRelative("surfaceCollisionTolerance"));
+ EditorGUILayout.PropertyField(parameters.FindPropertyRelative("diffusionMask"));
+ }
+ EditorGUILayout.EndFoldoutHeaderGroup();
+
+ constraintsFoldout.value = EditorGUILayout.BeginFoldoutHeaderGroup(constraintsFoldout, "Constraint settings");
+ if (constraintsFoldout)
+ {
+ constraintLabelContent.text = "Distance";
+ EditorGUILayout.PropertyField(distanceConstraintParameters, constraintLabelContent);
+
+ constraintLabelContent.text = "Bending";
+ EditorGUILayout.PropertyField(bendingConstraintParameters, constraintLabelContent);
+
+ constraintLabelContent.text = "Particle collision / Queries";
+ EditorGUILayout.PropertyField(particleCollisionConstraintParameters, constraintLabelContent);
+
+ constraintLabelContent.text = "Particle friction";
+ EditorGUILayout.PropertyField(particleFrictionConstraintParameters, constraintLabelContent);
+
+ constraintLabelContent.text = "Collision";
+ EditorGUILayout.PropertyField(collisionConstraintParameters, constraintLabelContent);
+
+ constraintLabelContent.text = "Friction";
+ EditorGUILayout.PropertyField(frictionConstraintParameters, constraintLabelContent);
+
+ constraintLabelContent.text = "Skin";
+ EditorGUILayout.PropertyField(skinConstraintParameters, constraintLabelContent);
+
+ constraintLabelContent.text = "Volume";
+ EditorGUILayout.PropertyField(volumeConstraintParameters, constraintLabelContent);
+
+ constraintLabelContent.text = "Shape matching";
+ EditorGUILayout.PropertyField(shapeMatchingConstraintParameters, constraintLabelContent);
+
+ constraintLabelContent.text = "Tether";
+ EditorGUILayout.PropertyField(tetherConstraintParameters, constraintLabelContent);
+
+ constraintLabelContent.text = "Pin";
+ EditorGUILayout.PropertyField(pinConstraintParameters, constraintLabelContent);
+
+ constraintLabelContent.text = "Pinhole";
+ EditorGUILayout.PropertyField(pinholeConstraintParameters, constraintLabelContent);
+
+ constraintLabelContent.text = "Stitch";
+ EditorGUILayout.PropertyField(stitchConstraintParameters, constraintLabelContent);
+
+ constraintLabelContent.text = "Density";
+ EditorGUILayout.PropertyField(densityConstraintParameters, constraintLabelContent);
+
+ constraintLabelContent.text = "Stretch & Shear";
+ EditorGUILayout.PropertyField(stretchShearConstraintParameters, constraintLabelContent);
+
+ constraintLabelContent.text = "Bend & Twist";
+ EditorGUILayout.PropertyField(bendTwistConstraintParameters, constraintLabelContent);
+
+ constraintLabelContent.text = "Chain";
+ EditorGUILayout.PropertyField(chainConstraintParameters, constraintLabelContent);
+ }
+ EditorGUILayout.EndFoldoutHeaderGroup();
+
+ memoryFoldout.value = EditorGUILayout.BeginFoldoutHeaderGroup(memoryFoldout, "Memory budget");
+ if (memoryFoldout)
+ {
+ EditorGUILayout.PropertyField(maxQueryResults);
+ EditorGUILayout.PropertyField(maxFoamParticles);
+
+ EditorGUI.BeginChangeCheck();
+ EditorGUILayout.PropertyField(maxSurfaceChunks);
+ if (EditorGUI.EndChangeCheck())
+ {
+ serializedObject.ApplyModifiedProperties();
+ foreach (var t in targets)
+ (t as ObiSolver).dirtyRendering |= (int)Oni.RenderingSystemType.Fluid;
+ }
+
+ EditorGUILayout.PropertyField(maxParticleNeighbors);
+ EditorGUILayout.PropertyField(maxParticleContacts);
+
+ uint usedChunks = solver.usedSurfaceChunks;
+ float usagePercentage = usedChunks / (float)maxSurfaceChunks.intValue;
+ uint foamParticles = solver.initialized ? solver.implementation.activeFoamParticleCount : 0;
+
+ // memory consumption per chunk:
+ // (8 + 12 + 64*4 + 64*6*4 + 64*16) = 2836 bytes
+ EditorGUILayout.HelpBox("Active foam particles: " + foamParticles + "/" + maxFoamParticles.intValue + "\n"+
+ "Surface memory (Mb): " + string.Format("{0:N2}", maxSurfaceChunks.intValue * 0.002836f)+ "\n"+
+ "Used surface chunks: "+ usedChunks + "/"+ maxSurfaceChunks.intValue + ", hashtable usage "+ string.Format("{0:N1}", usagePercentage * 100) + "%", MessageType.None);
+
+ if (usagePercentage >= 0.5f)
+ {
+ EditorGUILayout.HelpBox("Hashtable usage should be below 50% for best performance. Increase max surface chunks if % is too high.", MessageType.Warning);
+ }
+ }
+ EditorGUILayout.EndFoldoutHeaderGroup();
+
+ // Apply changes to the serializedProperty
+ if (GUI.changed)
+ {
+ serializedObject.ApplyModifiedProperties();
+ solver.PushSolverParameters();
+ }
+
+ }
+
+ [DrawGizmo(GizmoType.InSelectionHierarchy | GizmoType.Selected)]
+ static void DrawGizmoForSolver(ObiSolver solver, GizmoType gizmoType)
+ {
+ if ((gizmoType & GizmoType.InSelectionHierarchy) != 0)
+ {
+ Gizmos.color = new Color(1, 1, 1, 0.5f);
+ var bounds = solver.bounds;
+ Gizmos.DrawWireCube(bounds.center, bounds.size);
+ }
+ }
+
+ }
+}
+
+
diff --git a/Assets/Obi/Editor/Common/Solver/ObiSolverEditor.cs.meta b/Assets/Obi/Editor/Common/Solver/ObiSolverEditor.cs.meta
new file mode 100644
index 000000000..07e52a910
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Solver/ObiSolverEditor.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: d776094922a7647ccb5194d08e93ceaf
+timeCreated: 1444024856
+licenseType: Store
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Utils.meta b/Assets/Obi/Editor/Common/Utils.meta
new file mode 100644
index 000000000..b00896037
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Utils.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: b7a80ed0e578946aaad351df0313281a
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Utils/BooleanPreference.cs b/Assets/Obi/Editor/Common/Utils/BooleanPreference.cs
new file mode 100644
index 000000000..d74b8dc46
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Utils/BooleanPreference.cs
@@ -0,0 +1,46 @@
+
+using UnityEditor;
+
+namespace Obi
+{
+ public class BooleanPreference
+ {
+ bool m_Value;
+ string m_Name;
+ bool m_Loaded;
+
+ public BooleanPreference(string name, bool value)
+ {
+ m_Name = name;
+ m_Loaded = false;
+ m_Value = value;
+ }
+
+ private void Load()
+ {
+ if (m_Loaded)
+ return;
+
+ m_Loaded = true;
+ m_Value = EditorPrefs.GetBool(m_Name, m_Value);
+ }
+
+ public bool value
+ {
+ get { Load(); return m_Value; }
+ set
+ {
+ Load();
+ if (m_Value == value)
+ return;
+ m_Value = value;
+ EditorPrefs.SetBool(m_Name, value);
+ }
+ }
+
+ public static implicit operator bool(BooleanPreference s)
+ {
+ return s.value;
+ }
+ }
+}
diff --git a/Assets/Obi/Editor/Common/Utils/BooleanPreference.cs.meta b/Assets/Obi/Editor/Common/Utils/BooleanPreference.cs.meta
new file mode 100644
index 000000000..f74e188c6
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Utils/BooleanPreference.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 4af60554659c94226a5b3cf0b5987a5f
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Utils/ObiEditorUtils.cs b/Assets/Obi/Editor/Common/Utils/ObiEditorUtils.cs
new file mode 100644
index 000000000..be05d5a30
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Utils/ObiEditorUtils.cs
@@ -0,0 +1,254 @@
+using System;
+using UnityEngine;
+using UnityEngine.SceneManagement;
+using UnityEditor;
+using UnityEditor.SceneManagement;
+using System.IO;
+using UnityEngine.Rendering;
+
+namespace Obi{
+
+ public static class ObiEditorUtils
+ {
+ static GUIStyle separatorLine;
+ static GUIStyle toggleablePropertyGroup;
+ static GUIStyle boldToggle;
+
+ public static GUIStyle GetSeparatorLineStyle()
+ {
+ if (separatorLine == null)
+ {
+ separatorLine = new GUIStyle(EditorGUIUtility.GetBuiltinSkin(EditorSkin.Scene).box);
+ separatorLine.normal.background = Resources.Load("SeparatorLine");
+ separatorLine.border = new RectOffset(3, 3, 0, 0);
+ separatorLine.padding = new RectOffset(0, 0, 0, 0);
+ separatorLine.margin = new RectOffset(0, 0, 0, 0);
+ separatorLine.fixedHeight = 3;
+ separatorLine.stretchWidth = true;
+ }
+ return separatorLine;
+ }
+
+ public static GUIStyle GetToggleablePropertyGroupStyle()
+ {
+ if (toggleablePropertyGroup == null)
+ {
+ toggleablePropertyGroup = new GUIStyle();
+ toggleablePropertyGroup.normal.background = Resources.Load("ToggleableGroupBg");
+ toggleablePropertyGroup.border = new RectOffset(3, 3, 3, 3);
+ toggleablePropertyGroup.padding = new RectOffset(0, 0, 0, 0);
+ toggleablePropertyGroup.margin = new RectOffset(0, 0, 3, 3);
+ }
+ return toggleablePropertyGroup;
+ }
+
+ public static GUIStyle GetBoldToggleStyle()
+ {
+ if (boldToggle == null)
+ {
+ boldToggle = new GUIStyle(EditorStyles.toggle);
+ boldToggle.fontStyle = FontStyle.Bold;
+ }
+ return boldToggle;
+ }
+
+ public static void SaveMesh (Mesh mesh, string title, string name, bool makeNewInstance = true, bool optimizeMesh = true) {
+
+ string path = EditorUtility.SaveFilePanel(title, "Assets/", name, "asset");
+ if (string.IsNullOrEmpty(path)) return;
+
+ path = FileUtil.GetProjectRelativePath(path);
+
+ Mesh meshToSave = (makeNewInstance) ? GameObject.Instantiate(mesh) as Mesh : mesh;
+
+ if (optimizeMesh)
+ MeshUtility.Optimize(meshToSave);
+
+ AssetDatabase.CreateAsset(meshToSave, path);
+ AssetDatabase.SaveAssets();
+ }
+
+ public static void PlaceActorRoot(GameObject element, MenuCommand menuCommand)
+ {
+ GameObject parent = menuCommand.context as GameObject;
+
+ if (parent == null)
+ {
+ parent = GetOrCreateSolverObject();
+ }
+
+ if (parent.GetComponentsInParent(true).Length == 0)
+ {
+ // Create solver under context GameObject,
+ // and make that be the parent which actor is added under.
+ GameObject solver = CreateNewSolver();
+ solver.transform.SetParent(parent.transform, false);
+ parent = solver;
+ }
+
+ // The element needs to be already in its destination scene when the
+ // RegisterCreatedObjectUndo is performed; otherwise the scene it was created in is dirtied.
+ SceneManager.MoveGameObjectToScene(element, parent.scene);
+
+ Undo.RegisterCreatedObjectUndo(element, "Create " + element.name);
+
+ if (element.transform.parent == null)
+ Undo.SetTransformParent(element.transform, parent.transform, "Parent " + element.name);
+
+ GameObjectUtility.EnsureUniqueNameForSibling(element);
+
+ // We have to fix up the undo name since the name of the object was only known after reparenting it.
+ Undo.SetCurrentGroupName("Create " + element.name);
+
+ GameObjectUtility.SetParentAndAlign(element, parent);
+ Selection.activeGameObject = element;
+ }
+
+ // Helper function that returns a Solver GameObject; preferably a parent of the selection, or other existing Canvas.
+ private static GameObject GetOrCreateSolverObject()
+ {
+ GameObject selectedGo = Selection.activeGameObject;
+
+ // Try to find a gameobject that is the selected GO or one if its parents.
+ ObiSolver solver = (selectedGo != null) ? selectedGo.GetComponentInParent() : null;
+ if (IsValidSolver(solver))
+ return solver.gameObject;
+
+ // No solver in selection or its parents? Then use any valid solver.
+ // We have to find all loaded solvers, not just the ones in main scenes.
+ ObiSolver[] solverArray = StageUtility.GetCurrentStageHandle().FindComponentsOfType();
+ for (int i = 0; i < solverArray.Length; i++)
+ if (IsValidSolver(solverArray[i]))
+ return solverArray[i].gameObject;
+
+ // No solver in the scene at all? Then create a new one.
+ return CreateNewSolver();
+ }
+
+ public static GameObject CreateNewSolver()
+ {
+ // Root for the actors.
+ var root = new GameObject("Obi Solver", typeof(ObiSolver));
+
+ // Works for all stages.
+ StageUtility.PlaceGameObjectInCurrentStage(root);
+ Undo.RegisterCreatedObjectUndo(root, "Create " + root.name);
+
+ return root;
+ }
+
+ static bool IsValidSolver(ObiSolver solver)
+ {
+ if (solver == null || !solver.gameObject.activeInHierarchy)
+ return false;
+
+ if (EditorUtility.IsPersistent(solver) || (solver.hideFlags & HideFlags.HideInHierarchy) != 0)
+ return false;
+
+ if (StageUtility.GetStageHandle(solver.gameObject) != StageUtility.GetCurrentStageHandle())
+ return false;
+
+ return true;
+ }
+
+ public static void DoPropertyGroup(GUIContent content, System.Action action)
+ {
+ EditorGUILayout.BeginVertical(GetToggleablePropertyGroupStyle());
+ {
+ EditorGUILayout.BeginHorizontal();
+ EditorGUILayout.LabelField(content, EditorStyles.boldLabel);
+ EditorGUILayout.EndHorizontal();
+
+ if (action != null)
+ {
+ EditorGUI.indentLevel++;
+ action();
+ EditorGUI.indentLevel--;
+ }
+ }
+ EditorGUILayout.EndVertical();
+ }
+
+ public static void DoToggleablePropertyGroup(SerializedProperty enabledProperty, GUIContent content, System.Action action)
+ {
+ bool enabled = GUI.enabled;
+ GUI.enabled &= enabledProperty.boolValue;
+ EditorGUILayout.BeginVertical(GetToggleablePropertyGroupStyle());
+ GUI.enabled = enabled;
+ {
+ EditorGUILayout.BeginHorizontal();
+ enabledProperty.boolValue = EditorGUILayout.ToggleLeft(content,enabledProperty.boolValue,EditorStyles.boldLabel);
+ EditorGUILayout.EndHorizontal();
+
+ if (enabledProperty.boolValue && action != null)
+ {
+ EditorGUI.indentLevel++;
+ action();
+ EditorGUI.indentLevel--;
+ }
+ }
+ EditorGUILayout.EndVertical();
+ }
+
+ public static int DoToolBar(int selected, GUIContent[] items)
+ {
+ // Keep the selected index within the bounds of the items array
+ selected = selected < 0 ? 0 : selected >= items.Length ? items.Length - 1 : selected;
+
+ GUIStyle style = GUI.skin.FindStyle("Button");
+
+ EditorGUILayout.BeginHorizontal();
+ GUILayout.FlexibleSpace();
+ for (int i = 0; i < items.Length; i++)
+ {
+ if (i == 0 && items.Length > 1)
+ style = GUI.skin.FindStyle("ButtonLeft");
+ else if (items.Length > 1 && i == items.Length-1)
+ style = GUI.skin.FindStyle("ButtonRight");
+ else if (i > 0)
+ style = GUI.skin.FindStyle("ButtonMid");
+
+
+ // Display toggle. Get if toggle changed.
+ bool change = GUILayout.Toggle(selected == i, items[i],style,GUILayout.Height(24));
+ // If changed, set selected to current index.
+ if (change)
+ selected = i;
+ }
+ GUILayout.FlexibleSpace();
+ EditorGUILayout.EndHorizontal();
+
+ // Return the currently selected item's index
+ return selected;
+ }
+
+ public static void DrawArrowHandle(Vector3 posA, Vector3 posB, float headAngle = 30, float headLength = 0.18f)
{
+ Handles.DrawLine(posA, posB);
+
+ var look = Quaternion.LookRotation(posA - posB, Camera.current.transform.forward);
+ var one = look * Quaternion.Euler(0, 180 + headAngle, 0) * new Vector3(0, 0, 1);
+ var two = look * Quaternion.Euler(0, 180 - headAngle, 0) * new Vector3(0, 0, 1);
+
+ var sizeA = HandleUtility.GetHandleSize(posA) * headLength;
+ Handles.DrawLine(posA, posA + one * sizeA);
+ Handles.DrawLine(posA, posA + two * sizeA);
+
+ var sizeB = HandleUtility.GetHandleSize(posB) * headLength;
+ Handles.DrawLine(posB, posB - one * sizeB);
+ Handles.DrawLine(posB, posB - two * sizeB);
}
+
+ public static Material GetDefaultMaterial()
+ {
+ if (GraphicsSettings.defaultRenderPipeline != null)
+ {
+ return GraphicsSettings.defaultRenderPipeline.defaultMaterial;
+ }
+ else
+ {
+ return AssetDatabase.GetBuiltinExtraResource("Default-Diffuse.mat");
+ }
+ }
+ }
+}
+
+
diff --git a/Assets/Obi/Editor/Common/Utils/ObiEditorUtils.cs.meta b/Assets/Obi/Editor/Common/Utils/ObiEditorUtils.cs.meta
new file mode 100644
index 000000000..582e66409
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Utils/ObiEditorUtils.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 57c936f7a4f99456d944beed51c5b935
+timeCreated: 1452817402
+licenseType: Store
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Utils/ObiFoamGeneratorEditor.cs b/Assets/Obi/Editor/Common/Utils/ObiFoamGeneratorEditor.cs
new file mode 100644
index 000000000..42d4e21df
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Utils/ObiFoamGeneratorEditor.cs
@@ -0,0 +1,24 @@
+using UnityEditor;
+using UnityEngine;
+
+namespace Obi
+{
+
+ [CustomEditor(typeof(ObiFoamGenerator)), CanEditMultipleObjects]
+ public class ObiFoamGeneratorEditor : Editor
+ {
+ public override void OnInspectorGUI()
+ {
+ serializedObject.UpdateIfRequiredOrScript();
+
+ DrawPropertiesExcluding(serializedObject, "m_Script");
+
+ // Apply changes to the serializedProperty
+ if (GUI.changed)
+ serializedObject.ApplyModifiedProperties();
+ }
+
+ }
+
+}
+
diff --git a/Assets/Obi/Editor/Common/Utils/ObiFoamGeneratorEditor.cs.meta b/Assets/Obi/Editor/Common/Utils/ObiFoamGeneratorEditor.cs.meta
new file mode 100644
index 000000000..baab18072
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Utils/ObiFoamGeneratorEditor.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: b9656e2c54d9e4c478c74ca6d97428f8
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Utils/ObiParticleAttachmentEditor.cs b/Assets/Obi/Editor/Common/Utils/ObiParticleAttachmentEditor.cs
new file mode 100644
index 000000000..b9f0bf988
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Utils/ObiParticleAttachmentEditor.cs
@@ -0,0 +1,124 @@
+using UnityEditor;
+using UnityEditorInternal;
+using UnityEngine;
+using System.Collections.Generic;
+using System.Linq;
+
+
+namespace Obi
+{
+
+ [CustomEditor(typeof(ObiParticleAttachment))]
+ public class ObiParticleAttachmentEditor : Editor
+ {
+
+ SerializedProperty targetTransform;
+ SerializedProperty particleGroup;
+ SerializedProperty attachmentType;
+ SerializedProperty projectPosition;
+ SerializedProperty constrainOrientation;
+ SerializedProperty compliance;
+ SerializedProperty breakThreshold;
+
+ ObiParticleAttachment attachment;
+
+ public void OnEnable()
+ {
+
+ attachment = target as ObiParticleAttachment;
+ targetTransform = serializedObject.FindProperty("m_Target");
+ particleGroup = serializedObject.FindProperty("m_ParticleGroup");
+ attachmentType = serializedObject.FindProperty("m_AttachmentType");
+ projectPosition = serializedObject.FindProperty("m_Projection");
+ constrainOrientation = serializedObject.FindProperty("m_ConstrainOrientation");
+ compliance = serializedObject.FindProperty("m_Compliance");
+ breakThreshold = serializedObject.FindProperty("breakThreshold");
+ }
+
+ public override void OnInspectorGUI()
+ {
+
+ serializedObject.UpdateIfRequiredOrScript();
+
+ // warn about incorrect setups:
+ if (!attachmentType.hasMultipleDifferentValues && !targetTransform.hasMultipleDifferentValues)
+ {
+ if (attachmentType.enumValueIndex == (int)ObiParticleAttachment.AttachmentType.Dynamic)
+ {
+ var targetValue = targetTransform.objectReferenceValue as UnityEngine.Component;
+ if (targetValue != null)
+ {
+ var collider = targetValue.GetComponent();
+ if (collider == null)
+ {
+ EditorGUILayout.HelpBox("Dynamic attachments require the target object to have a ObiCollider component. Either add one, or change the attachment type to Static.", MessageType.Warning);
+ }
+ }
+ }
+ }
+
+ EditorGUI.BeginChangeCheck();
+ Transform trget = EditorGUILayout.ObjectField("Target", attachment.target, typeof(Transform), true) as Transform;
+ if (EditorGUI.EndChangeCheck())
+ {
+ Undo.RecordObject(attachment, "Set target");
+ attachment.target = trget;
+ PrefabUtility.RecordPrefabInstancePropertyModifications(attachment);
+ }
+
+
+ var blueprint = attachment.actor.sourceBlueprint;
+
+ if (blueprint != null)
+ {
+ var rect = EditorGUILayout.GetControlRect();
+ var label = EditorGUI.BeginProperty(rect, new GUIContent("Particle group"), particleGroup);
+ rect = EditorGUI.PrefixLabel(rect, label);
+
+ if (GUI.Button(rect, attachment.particleGroup != null ? attachment.particleGroup.name : "None", EditorStyles.popup))
+ {
+ // create the menu and add items to it
+ GenericMenu menu = new GenericMenu();
+ menu.allowDuplicateNames = true;
+
+ for (int i = 0; i < blueprint.groups.Count; ++i)
+ {
+ menu.AddItem(new GUIContent(blueprint.groups[i].name), blueprint.groups[i] == attachment.particleGroup, OnParticleGroupSelected, blueprint.groups[i]);
+ }
+
+ // display the menu
+ menu.DropDown(rect);
+ }
+
+ EditorGUI.EndProperty();
+ }
+
+ EditorGUILayout.PropertyField(attachmentType, new GUIContent("Type"));
+
+ if (attachment.actor.usesOrientedParticles)
+ EditorGUILayout.PropertyField(constrainOrientation, new GUIContent("Constraint Orientation"));
+
+ if (attachment.attachmentType == ObiParticleAttachment.AttachmentType.Dynamic)
+ {
+ EditorGUILayout.PropertyField(projectPosition, new GUIContent("Projection"));
+ EditorGUILayout.PropertyField(compliance, new GUIContent("Compliance"));
+ EditorGUILayout.PropertyField(breakThreshold, new GUIContent("Break threshold"));
+ }
+
+ if (GUI.changed)
+ serializedObject.ApplyModifiedProperties();
+
+ }
+
+ // the GenericMenu.MenuFunction2 event handler for when a menu item is selected
+ void OnParticleGroupSelected(object index)
+ {
+ Undo.RecordObject(attachment, "Set particle group");
+ attachment.particleGroup = index as ObiParticleGroup;
+ PrefabUtility.RecordPrefabInstancePropertyModifications(attachment);
+ }
+ }
+
+}
+
+
diff --git a/Assets/Obi/Editor/Common/Utils/ObiParticleAttachmentEditor.cs.meta b/Assets/Obi/Editor/Common/Utils/ObiParticleAttachmentEditor.cs.meta
new file mode 100644
index 000000000..4d17dbba7
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Utils/ObiParticleAttachmentEditor.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 1587d981fa96c4b2291e19484a5a5b13
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Utils/ObiRaycastHit.cs b/Assets/Obi/Editor/Common/Utils/ObiRaycastHit.cs
new file mode 100644
index 000000000..d56e32775
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Utils/ObiRaycastHit.cs
@@ -0,0 +1,26 @@
+using UnityEngine;
+using System.Collections.Generic;
+
+namespace Obi
+{
+ public class ObiRaycastHit
+ {
+
+ /// Distance from the Raycast origin to the point of impact.
+ public float distance;
+ /// The position in model space where a raycast intercepted a triangle.
+ public Vector3 position;
+ /// The normal in model space of the triangle that this raycast hit.
+ public Vector3 normal;
+ /// The triangle index of the hit face.
+ public int triangle;
+
+ public ObiRaycastHit(float distance, Vector3 position, Vector3 normal, int triangle)
+ {
+ this.distance = distance;
+ this.position = position;
+ this.normal = normal;
+ this.triangle = triangle;
+ }
+ }
+}
diff --git a/Assets/Obi/Editor/Common/Utils/ObiRaycastHit.cs.meta b/Assets/Obi/Editor/Common/Utils/ObiRaycastHit.cs.meta
new file mode 100644
index 000000000..27e33591e
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Utils/ObiRaycastHit.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 2eb47a91b4f7c4f4aa52d4b914caa96e
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Common/Utils/PreviewHelpers.cs b/Assets/Obi/Editor/Common/Utils/PreviewHelpers.cs
new file mode 100644
index 000000000..5ba601a90
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Utils/PreviewHelpers.cs
@@ -0,0 +1,150 @@
+using System;
+using UnityEditor;
+using UnityEngine;
+
+namespace Obi{
+
+ class PreviewHelpers
+ {
+
+ // Preview interaction related stuff:
+ static int sliderHash = "Slider".GetHashCode();
+ public static Vector2 Drag2D(Vector2 scrollPosition, Rect position)
+ {
+ int controlID = GUIUtility.GetControlID(PreviewHelpers.sliderHash, FocusType.Passive);
+ Event current = Event.current;
+ switch (current.GetTypeForControl(controlID))
+ {
+ case EventType.MouseDown:
+ if (position.Contains(current.mousePosition) && position.width > 50f)
+ {
+ GUIUtility.hotControl = controlID;
+ current.Use();
+ EditorGUIUtility.SetWantsMouseJumping(1);
+ }
+ break;
+ case EventType.MouseUp:
+ if (GUIUtility.hotControl == controlID)
+ {
+ GUIUtility.hotControl = 0;
+ }
+ EditorGUIUtility.SetWantsMouseJumping(0);
+ break;
+ case EventType.MouseDrag:
+ if (GUIUtility.hotControl == controlID)
+ {
+ scrollPosition -= current.delta * (float)((!current.shift) ? 1 : 3) / Mathf.Min(position.width, position.height) * 140f;
+ scrollPosition.y = Mathf.Clamp(scrollPosition.y, -90f, 90f);
+ current.Use();
+ GUI.changed = true;
+ }
+ break;
+ }
+ return scrollPosition;
+ }
+
+ public Camera m_Camera;
+ public float m_CameraFieldOfView = 30f;
+ public Light[] m_Light = new Light[2];
+ internal RenderTexture m_RenderTexture;
+ public PreviewHelpers() : this(false)
+ {
+ }
+ public PreviewHelpers(bool renderFullScene)
+ {
+ GameObject gameObject = EditorUtility.CreateGameObjectWithHideFlags("PreRenderCamera", HideFlags.HideAndDontSave, new Type[]
+ {
+ typeof(Camera)
+ });
+ this.m_Camera = gameObject.GetComponent();
+ this.m_Camera.fieldOfView = this.m_CameraFieldOfView;
+ this.m_Camera.cullingMask = 1 << 1;
+ this.m_Camera.enabled = false;
+ this.m_Camera.clearFlags = CameraClearFlags.SolidColor;
+ this.m_Camera.farClipPlane = 10f;
+ this.m_Camera.nearClipPlane = 1f;
+ this.m_Camera.backgroundColor = new Color(0.192156866f, 0.192156866f, 0.192156866f, 0);
+ this.m_Camera.renderingPath = RenderingPath.Forward;
+ this.m_Camera.useOcclusionCulling = false;
+
+ for (int i = 0; i < 2; i++)
+ {
+ GameObject gameObject2 = EditorUtility.CreateGameObjectWithHideFlags("PreRenderLight", HideFlags.HideAndDontSave, new Type[]
+ {
+ typeof(Light)
+ });
+ this.m_Light[i] = gameObject2.GetComponent();
+ this.m_Light[i].type = LightType.Directional;
+ this.m_Light[i].intensity = 1f;
+ this.m_Light[i].enabled = false;
+ }
+
+ this.m_Light[0].color = new Color(0.4f, 0.4f, 0.45f, 0f);
+ this.m_Light[1].transform.rotation = Quaternion.Euler(340f, 218f, 177f);
+ this.m_Light[1].color = new Color(0.4f, 0.4f, 0.45f, 0f) * 0.7f;
+ }
+ public void Cleanup()
+ {
+ if (this.m_Camera)
+ {
+ UnityEngine.Object.DestroyImmediate(this.m_Camera.gameObject, true);
+ }
+ if (this.m_RenderTexture)
+ {
+ UnityEngine.Object.DestroyImmediate(this.m_RenderTexture);
+ this.m_RenderTexture = null;
+ }
+ Light[] light = this.m_Light;
+ for (int i = 0; i < light.Length; i++)
+ {
+ Light light2 = light[i];
+ if (light2)
+ {
+ UnityEngine.Object.DestroyImmediate(light2.gameObject, true);
+ }
+ }
+ }
+
+ private void InitPreview(Rect r)
+ {
+ int num = (int)r.width;
+ int num2 = (int)r.height;
+ if (!this.m_RenderTexture || this.m_RenderTexture.width != num || this.m_RenderTexture.height != num2)
+ {
+ if (this.m_RenderTexture)
+ {
+ UnityEngine.Object.DestroyImmediate(this.m_RenderTexture);
+ this.m_RenderTexture = null;
+ }
+ float scaleFactor = this.GetScaleFactor((float)num, (float)num2);
+ this.m_RenderTexture = new RenderTexture((int)((float)num * scaleFactor), (int)((float)num2 * scaleFactor), 16);
+ this.m_RenderTexture.hideFlags = HideFlags.HideAndDontSave;
+ this.m_Camera.targetTexture = this.m_RenderTexture;
+ }
+ float num3 = (this.m_RenderTexture.width > 0) ? Mathf.Max(1f, (float)this.m_RenderTexture.height / (float)this.m_RenderTexture.width) : 1f;
+ this.m_Camera.fieldOfView = Mathf.Atan(num3 * Mathf.Tan(this.m_CameraFieldOfView * 0.5f * 0.0174532924f)) * 57.29578f * 2f;
+
+ }
+ public float GetScaleFactor(float width, float height)
+ {
+ float a = Mathf.Max(Mathf.Min(width * 2f, 1024f), width) / width;
+ float b = Mathf.Max(Mathf.Min(height * 2f, 1024f), height) / height;
+ return Mathf.Min(a, b);
+ }
+
+ public void BeginPreview(Rect r, GUIStyle previewBackground)
+ {
+ this.InitPreview(r);
+ if (previewBackground == null || previewBackground == GUIStyle.none)
+ {
+ return;
+ }
+ }
+ public Texture EndPreview()
+ {
+ m_Camera.Render();
+ return this.m_RenderTexture;
+ }
+
+ }
+}
diff --git a/Assets/Obi/Editor/Common/Utils/PreviewHelpers.cs.meta b/Assets/Obi/Editor/Common/Utils/PreviewHelpers.cs.meta
new file mode 100644
index 000000000..8ff77efc9
--- /dev/null
+++ b/Assets/Obi/Editor/Common/Utils/PreviewHelpers.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 886ef4783c97a4dac9034b48a6c94b6c
+timeCreated: 1438171037
+licenseType: Store
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Obi.Editor.asmdef b/Assets/Obi/Editor/Obi.Editor.asmdef
new file mode 100644
index 000000000..3c97604ac
--- /dev/null
+++ b/Assets/Obi/Editor/Obi.Editor.asmdef
@@ -0,0 +1,33 @@
+{
+ "name": "Obi.Editor",
+ "references": [
+ "GUID:da7abd44cdeea48609605c1c2c9609c0"
+ ],
+ "includePlatforms": [
+ "Editor"
+ ],
+ "excludePlatforms": [],
+ "allowUnsafeCode": false,
+ "overrideReferences": false,
+ "precompiledReferences": [],
+ "autoReferenced": true,
+ "defineConstraints": [],
+ "versionDefines": [
+ {
+ "name": "com.unity.collections",
+ "expression": "0.8.0-preview.5",
+ "define": "OBI_COLLECTIONS"
+ },
+ {
+ "name": "com.unity.burst",
+ "expression": "1.2.3-verified",
+ "define": "OBI_BURST"
+ },
+ {
+ "name": "com.unity.mathematics",
+ "expression": "1.0.1",
+ "define": "OBI_MATHEMATICS"
+ }
+ ],
+ "noEngineReferences": false
+}
\ No newline at end of file
diff --git a/Assets/Obi/Editor/Obi.Editor.asmdef.meta b/Assets/Obi/Editor/Obi.Editor.asmdef.meta
new file mode 100644
index 000000000..770027d79
--- /dev/null
+++ b/Assets/Obi/Editor/Obi.Editor.asmdef.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 180639cf42b5c450c8fdad7e31d2ec13
+AssemblyDefinitionImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/ObiParticleSelection.cs b/Assets/Obi/Editor/ObiParticleSelection.cs
new file mode 100644
index 000000000..06f1bb9d6
--- /dev/null
+++ b/Assets/Obi/Editor/ObiParticleSelection.cs
@@ -0,0 +1,186 @@
+using UnityEngine;
+using UnityEditor;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace Obi
+{
+
+ public static class ObiParticleSelection
+ {
+
+ static int particleSelectorHash = "ObiParticleSelectorHash".GetHashCode();
+
+ static Vector2 startPos;
+ static Vector2 currentPos;
+ static bool dragging = false;
+ static Rect marquee;
+
+ public static bool DoSelection(Vector3[] positions,
+ bool[] selectionStatus,
+ bool[] facingCamera)
+ {
+
+ Matrix4x4 cachedMatrix = Handles.matrix;
+
+ int controlID = GUIUtility.GetControlID(particleSelectorHash, FocusType.Passive);
+ int selectedParticleIndex = -1;
+ bool selectionStatusChanged = false;
+
+ // select vertex on mouse click:
+ switch (Event.current.GetTypeForControl(controlID))
+ {
+
+ case EventType.MouseDown:
+
+ if (Event.current.button != 0) break;
+
+ startPos = Event.current.mousePosition;
+ marquee.Set(0, 0, 0, 0);
+
+ // If the user is not pressing shift, clear selection.
+ if ((Event.current.modifiers & EventModifiers.Shift) == 0 && (Event.current.modifiers & EventModifiers.Alt) == 0)
+ {
+ for (int i = 0; i < selectionStatus.Length; i++)
+ selectionStatus[i] = false;
+ }
+
+ // Allow use of marquee selection
+ if (Event.current.modifiers == EventModifiers.None || (Event.current.modifiers & EventModifiers.Shift) != 0)
+ GUIUtility.hotControl = controlID;
+
+ float minSqrDistance = System.Single.MaxValue;
+
+ for (int i = 0; i < positions.Length; i++)
+ {
+ // skip not selectable particles:
+ //if (!facingCamera[i] && (selectBackfaces & ObiActorBlueprintEditor.ParticleCulling.Back) != 0) continue;
+ //if (facingCamera[i] && (selectBackfaces & ObiActorBlueprintEditor.ParticleCulling.Front) != 0) continue;
+
+ // get particle position in gui space:
+ Vector2 pos = HandleUtility.WorldToGUIPoint(positions[i]);
+
+ // get distance from mouse position to particle position:
+ float sqrDistance = Vector2.SqrMagnitude(startPos - pos);
+
+ // check if this particle is closer to the cursor that any previously considered particle.
+ if (sqrDistance < 100 && sqrDistance < minSqrDistance)
+ { //magic number 100 = 10*10, where 10 is min distance in pixels to select a particle.
+ minSqrDistance = sqrDistance;
+ selectedParticleIndex = i;
+ }
+
+ }
+
+ if (selectedParticleIndex >= 0)
+ { // toggle particle selection status.
+
+ selectionStatus[selectedParticleIndex] = !selectionStatus[selectedParticleIndex];
+ selectionStatusChanged = true;
+ GUIUtility.hotControl = controlID;
+ Event.current.Use();
+
+ }
+ else if (Event.current.modifiers == EventModifiers.None)
+ { // deselect all particles:
+ for (int i = 0; i < selectionStatus.Length; i++)
+ selectionStatus[i] = false;
+
+ selectionStatusChanged = true;
+ }
+
+ break;
+
+ case EventType.MouseMove:
+ SceneView.RepaintAll();
+ break;
+
+ case EventType.MouseDrag:
+
+ if (GUIUtility.hotControl == controlID)
+ {
+
+ currentPos = Event.current.mousePosition;
+ if (!dragging && Vector2.Distance(startPos, currentPos) > 5)
+ {
+ dragging = true;
+ }
+ else
+ {
+ GUIUtility.hotControl = controlID;
+ Event.current.Use();
+ }
+
+ //update marquee rect:
+ float left = Mathf.Min(startPos.x, currentPos.x);
+ float right = Mathf.Max(startPos.x, currentPos.x);
+ float bottom = Mathf.Min(startPos.y, currentPos.y);
+ float top = Mathf.Max(startPos.y, currentPos.y);
+
+ marquee = new Rect(left, bottom, right - left, top - bottom);
+
+ }
+
+ break;
+
+ case EventType.MouseUp:
+
+ if (GUIUtility.hotControl == controlID)
+ {
+
+ dragging = false;
+
+ for (int i = 0; i < positions.Length; i++)
+ {
+
+ // skip not selectable particles:
+ //switch (selectBackfaces)
+ {
+ //case ObiActorBlueprintEditor.ParticleCulling.Back: if (!facingCamera[i]) continue; break;
+ //case ObiActorBlueprintEditor.ParticleCulling.Front: if (facingCamera[i]) continue; break;
+ }
+
+ // get particle position in gui space:
+ Vector2 pos = HandleUtility.WorldToGUIPoint(positions[i]);
+
+ if (pos.x > marquee.xMin && pos.x < marquee.xMax && pos.y > marquee.yMin && pos.y < marquee.yMax)
+ {
+ selectionStatus[i] = true;
+ selectionStatusChanged = true;
+ }
+
+ }
+
+ GUIUtility.hotControl = 0;
+ Event.current.Use();
+ }
+
+ break;
+
+ case EventType.Repaint:
+
+ Handles.matrix = Matrix4x4.identity;
+
+ if (dragging)
+ {
+ GUISkin oldSkin = GUI.skin;
+ GUI.skin = EditorGUIUtility.GetBuiltinSkin(EditorSkin.Scene);
+ Handles.BeginGUI();
+ GUI.Box(new Rect(marquee.xMin, marquee.yMin, marquee.width, marquee.height), "");
+ Handles.EndGUI();
+ GUI.skin = oldSkin;
+ }
+
+ Handles.matrix = cachedMatrix;
+
+ break;
+
+ }
+
+ return selectionStatusChanged;
+ }
+
+ }
+}
+
diff --git a/Assets/Obi/Editor/ObiParticleSelection.cs.meta b/Assets/Obi/Editor/ObiParticleSelection.cs.meta
new file mode 100644
index 000000000..c877a037d
--- /dev/null
+++ b/Assets/Obi/Editor/ObiParticleSelection.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 7020925dabebf42b7915da74e58c3b5e
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/ObiStitcherEditor.cs b/Assets/Obi/Editor/ObiStitcherEditor.cs
new file mode 100644
index 000000000..0c4b395ba
--- /dev/null
+++ b/Assets/Obi/Editor/ObiStitcherEditor.cs
@@ -0,0 +1,287 @@
+using UnityEditor;
+using UnityEngine;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Obi{
+
+ /**
+ * Custom inspector for ObiStitcher component.
+ */
+
+ [CustomEditor(typeof(ObiStitcher))]
+ public class ObiStitcherEditor : Editor
+ {
+
+ ObiStitcher stitcher;
+ static public bool editing = false;
+
+ static public Vector3 sewingToolHandle1 = Vector3.zero;
+ static public Vector3 sewingToolHandle2 = Vector3.one;
+
+ static public bool[] selectionStatus = new bool[0];
+
+ public void OnEnable(){
+ stitcher = (ObiStitcher)target;
+
+ // initialize sewing tool to sensible values:
+ if (stitcher.Actor1 != null && stitcher.Actor2 != null){
+ sewingToolHandle1 = stitcher.Actor1.transform.position;
+ sewingToolHandle2 = stitcher.Actor2.transform.position;
+ }
+ }
+
+ public override void OnInspectorGUI() {
+
+ serializedObject.UpdateIfRequiredOrScript();
+
+ EditorGUI.BeginChangeCheck();
+ ObiActor actor1 = EditorGUILayout.ObjectField("First actor",stitcher.Actor1, typeof(ObiActor),true) as ObiActor;
+ if (EditorGUI.EndChangeCheck()){
+ Undo.RecordObject(stitcher, "Set first actor");
+ stitcher.Actor1 = actor1;
+ if (actor1 != null)
+ sewingToolHandle1 = actor1.transform.position;
+ PrefabUtility.RecordPrefabInstancePropertyModifications(stitcher);
+ }
+
+ EditorGUI.BeginChangeCheck();
+ ObiActor actor2 = EditorGUILayout.ObjectField("Second actor",stitcher.Actor2, typeof(ObiActor),true) as ObiActor;
+ if (EditorGUI.EndChangeCheck()){
+ Undo.RecordObject(stitcher, "Set second actor");
+ stitcher.Actor2 = actor2;
+ if (actor2 != null)
+ sewingToolHandle2 = actor2.transform.position;
+ PrefabUtility.RecordPrefabInstancePropertyModifications(stitcher);
+ }
+
+ if (stitcher.Actor1 != null && stitcher.Actor2 != null && stitcher.Actor1.solver != stitcher.Actor2.solver){
+ EditorGUILayout.HelpBox("Both actors must be managed by the same solver.",MessageType.Error);
+ }
+
+ EditorGUILayout.HelpBox("Stitch count: " + stitcher.StitchCount,MessageType.None);
+
+ // edit mode:
+ GUI.enabled = stitcher.Actor1 != null && stitcher.Actor2 != null;
+ editing = GUILayout.Toggle(editing,"Edit","LargeButton");
+
+ if (editing){
+
+ // Clear all stitches
+ if (GUILayout.Button("Clear all stitches")){
+ if (EditorUtility.DisplayDialog("Clearing stitches","Are you sure you want to remove all stitches?","Ok","Cancel")){
+ Undo.RecordObject(stitcher, "Clear all stitches");
+ stitcher.Clear();
+ PrefabUtility.RecordPrefabInstancePropertyModifications(stitcher);
+ }
+ }
+
+ // Remove selected stitches
+ if (GUILayout.Button("Remove selected stitches")){
+
+ List removedStitches = new List();
+
+ for(int i = 0; i < selectionStatus.Length; ++i){
+ if (selectionStatus[i]){
+ removedStitches.Add(i);
+ selectionStatus[i] = false;
+ }
+ }
+
+ if (removedStitches.Count > 0){
+
+ Undo.RecordObject(stitcher, "Remove stitches");
+
+ // Remove from last to first, to avoid throwing off subsequent indices:
+ foreach(int i in removedStitches.OrderByDescending(i => i)){
+ stitcher.RemoveStitch(i);
+ }
+ PrefabUtility.RecordPrefabInstancePropertyModifications(stitcher);
+ }
+ }
+
+ // Add stitch:
+ if (GUILayout.Button("Add Stitch"))
+ {
+ FindClosestParticles(out int particle1, out int particle2);
+
+ if (particle1 >= 0 && particle2 >= 0)
+ {
+ Undo.RecordObject(stitcher, "Add stitch");
+ stitcher.AddStitch(particle1, particle2);
+ PrefabUtility.RecordPrefabInstancePropertyModifications(stitcher);
+ }
+ }
+ }
+ GUI.enabled = true;
+
+ // Apply changes to the serializedProperty
+ if (GUI.changed){
+
+ serializedObject.ApplyModifiedProperties();
+
+ //stitcher.PushDataToSolver(ParticleData.NONE);
+
+ }
+
+ }
+
+ public void FindClosestParticles(out int particle1, out int particle2)
+ {
+ particle1 = -1;
+ particle2 = -1;
+ float minDistance = float.MaxValue;
+
+ if (stitcher.Actor1 == null || stitcher.Actor2 == null)
+ return;
+
+ var handle1 = HandleUtility.WorldToGUIPointWithDepth(sewingToolHandle1);
+ var handle2 = HandleUtility.WorldToGUIPointWithDepth(sewingToolHandle2);
+
+ if (stitcher.Actor1 == stitcher.Actor2)
+ {
+ float minDistance2 = float.MaxValue;
+ for (int i = 0; i < stitcher.Actor1.activeParticleCount;++i)
+ {
+ Vector3 pos = stitcher.Actor1.GetParticlePosition(stitcher.Actor1.solverIndices[i]);
+ pos = HandleUtility.WorldToGUIPointWithDepth(pos);
+
+ float distance1 = (pos - handle1).sqrMagnitude;
+ float distance2 = (pos - handle2).sqrMagnitude;
+ if (distance1 < minDistance){
+ minDistance = distance1;
+ particle1 = i;
+ }
+ if (distance2 < minDistance2){
+ minDistance2 = distance2;
+ particle2 = i;
+ }
+ }
+ }else{
+
+ // find closest particle to each end of the sewing tool:
+ for (int i = 0; i < stitcher.Actor1.activeParticleCount; ++i)
+ {
+ Vector3 pos = stitcher.Actor1.GetParticlePosition(stitcher.Actor1.solverIndices[i]);
+ pos = HandleUtility.WorldToGUIPointWithDepth(pos);
+
+ float min = (pos - handle1).sqrMagnitude;
+ if (min < minDistance)
+ {
+ minDistance = min;
+ particle1 = i;
+ }
+ }
+
+ minDistance = float.MaxValue;
+ for (int i = 0; i < stitcher.Actor2.activeParticleCount; ++i)
+ {
+ Vector3 pos = stitcher.Actor2.GetParticlePosition(stitcher.Actor2.solverIndices[i]);
+ pos = HandleUtility.WorldToGUIPointWithDepth(pos);
+
+ float min = (pos - handle2).sqrMagnitude;
+ if (min < minDistance)
+ {
+ minDistance = min;
+ particle2 = i;
+ }
+ }
+ }
+ }
+
+ public void DrawSewingTool()
+ {
+
+ FindClosestParticles(out int particle1, out int particle2);
+
+ if (particle1 >= 0 && particle2 >= 0)
+ {
+ sewingToolHandle1 = stitcher.Actor1.GetParticlePosition(stitcher.Actor1.solverIndices[particle1]);
+ sewingToolHandle2 = stitcher.Actor2.GetParticlePosition(stitcher.Actor2.solverIndices[particle2]);
+
+ float radius1 = stitcher.Actor1.GetParticleMaxRadius(stitcher.Actor1.solverIndices[particle1]);
+ float radius2 = stitcher.Actor2.GetParticleMaxRadius(stitcher.Actor2.solverIndices[particle2]);
+
+ Handles.color = Color.white;
+#if (UNITY_2022_1_OR_NEWER)
+ sewingToolHandle1 = Handles.FreeMoveHandle(sewingToolHandle1, radius1 * 2, new Vector3(.5f,.5f,.5f),Handles.SphereHandleCap);
+ sewingToolHandle2 = Handles.FreeMoveHandle(sewingToolHandle2, radius2 * 2, new Vector3(.5f,.5f,.5f),Handles.SphereHandleCap);
+#else
+ sewingToolHandle1 = Handles.FreeMoveHandle(sewingToolHandle1, Quaternion.identity, radius1 * 2, new Vector3(.5f, .5f, .5f), Handles.SphereHandleCap);
+ sewingToolHandle2 = Handles.FreeMoveHandle(sewingToolHandle2, Quaternion.identity, radius2 * 2, new Vector3(.5f, .5f, .5f), Handles.SphereHandleCap);
+#endif
+
+ Vector3 direction = Vector3.Normalize(sewingToolHandle2 - sewingToolHandle1);
+ Handles.color = Color.yellow;
+ ObiEditorUtils.DrawArrowHandle(sewingToolHandle1 + direction*(radius1 + 0.05f), sewingToolHandle2 - direction*(radius2+0.05f));
+ }
+ }
+
+ /**
+ * Draws selected stitches in the scene view and allows their selection.
+ */
+ public void OnSceneGUI(){
+
+ Array.Resize(ref selectionStatus,stitcher.StitchCount);
+
+ if (!editing)
+ return;
+
+ DrawSewingTool();
+
+ if (stitcher.Actor1 != null && stitcher.Actor2 != null){
+
+ int controlID = GUIUtility.GetControlID("stitcher".GetHashCode(),FocusType.Passive);
+ float distanceToClosest = float.MaxValue;
+ int selectedIndex = -1;
+ int i = 0;
+
+ foreach(ObiStitcher.Stitch stitch in stitcher.Stitches){
+
+ Vector3 pos1 = stitcher.Actor1.GetParticlePosition(stitcher.Actor1.solverIndices[stitch.particleIndex1]);
+ Vector3 pos2 = stitcher.Actor2.GetParticlePosition(stitcher.Actor2.solverIndices[stitch.particleIndex2]);
+
+ switch (Event.current.GetTypeForControl(controlID)){
+ case EventType.MouseDown:
+
+ if (Event.current.button != 0) break;
+
+ // If the user is pressing shift, accumulate selection.
+ if ((Event.current.modifiers & EventModifiers.Shift) == 0 && (Event.current.modifiers & EventModifiers.Alt) == 0){
+ for(int j = 0; j < selectionStatus.Length; j++)
+ selectionStatus[j] = false;
+ }
+
+ float distance = HandleUtility.DistanceToLine(pos1,pos2);
+ if (distance < 10 && distance < distanceToClosest){
+
+ distanceToClosest = distance;
+ selectedIndex = i;
+
+ // Prevent deselection if we have selected a stitch:
+ GUIUtility.hotControl = controlID;
+ Event.current.Use();
+
+ }
+ break;
+ case EventType.Repaint:
+ Handles.color = selectionStatus[i]?Color.red:Color.cyan;
+ Handles.DrawDottedLine(pos1,pos2,2);
+ break;
+ }
+ ++i;
+ }
+
+ if (selectedIndex >= 0){
+ selectionStatus[selectedIndex] = !selectionStatus[selectedIndex];
+ }
+
+ }
+
+ }
+
+ }
+}
+
diff --git a/Assets/Obi/Editor/ObiStitcherEditor.cs.meta b/Assets/Obi/Editor/ObiStitcherEditor.cs.meta
new file mode 100644
index 000000000..b0c18e2e1
--- /dev/null
+++ b/Assets/Obi/Editor/ObiStitcherEditor.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 7d360f36068814e1a9e2835455e6be61
+timeCreated: 1489407253
+licenseType: Store
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources.meta b/Assets/Obi/Editor/Resources.meta
new file mode 100644
index 000000000..2f133580a
--- /dev/null
+++ b/Assets/Obi/Editor/Resources.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: a89eef02b8abc42e2b56e6150832233d
+folderAsset: yes
+timeCreated: 1498032496
+licenseType: Store
+DefaultImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/AddControlPoint.psd b/Assets/Obi/Editor/Resources/AddControlPoint.psd
new file mode 100644
index 000000000..d968222e8
Binary files /dev/null and b/Assets/Obi/Editor/Resources/AddControlPoint.psd differ
diff --git a/Assets/Obi/Editor/Resources/AddControlPoint.psd.meta b/Assets/Obi/Editor/Resources/AddControlPoint.psd.meta
new file mode 100644
index 000000000..5dbc55215
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/AddControlPoint.psd.meta
@@ -0,0 +1,59 @@
+fileFormatVersion: 2
+guid: 6d2b606052e73408595395e402a926e1
+timeCreated: 1478799645
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 2
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ linearTexture: 1
+ correctGamma: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 0
+ cubemapConvolution: 0
+ cubemapConvolutionSteps: 7
+ cubemapConvolutionExponent: 1.5
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ rGBM: 0
+ compressionQuality: 50
+ allowsAlphaSplitting: 0
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ buildTargetSettings: []
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/AddIcon.psd b/Assets/Obi/Editor/Resources/AddIcon.psd
new file mode 100644
index 000000000..b4142a483
Binary files /dev/null and b/Assets/Obi/Editor/Resources/AddIcon.psd differ
diff --git a/Assets/Obi/Editor/Resources/AddIcon.psd.meta b/Assets/Obi/Editor/Resources/AddIcon.psd.meta
new file mode 100644
index 000000000..4ac9b4eda
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/AddIcon.psd.meta
@@ -0,0 +1,55 @@
+fileFormatVersion: 2
+guid: d11f3f1468cd5453d961042f3ae9799d
+timeCreated: 1440144040
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 2
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ linearTexture: 1
+ correctGamma: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: .25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 0
+ cubemapConvolution: 0
+ cubemapConvolutionSteps: 8
+ cubemapConvolutionExponent: 1.5
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ rGBM: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: .5, y: .5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaIsTransparency: 1
+ textureType: 2
+ buildTargetSettings: []
+ spriteSheet:
+ sprites: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/AddTetherButton.psd b/Assets/Obi/Editor/Resources/AddTetherButton.psd
new file mode 100644
index 000000000..f0f2cd2aa
Binary files /dev/null and b/Assets/Obi/Editor/Resources/AddTetherButton.psd differ
diff --git a/Assets/Obi/Editor/Resources/AddTetherButton.psd.meta b/Assets/Obi/Editor/Resources/AddTetherButton.psd.meta
new file mode 100644
index 000000000..9cf24278a
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/AddTetherButton.psd.meta
@@ -0,0 +1,59 @@
+fileFormatVersion: 2
+guid: c8a8952cc5f5744e88c765ee83f6a865
+timeCreated: 1478799531
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 2
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ linearTexture: 1
+ correctGamma: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 0
+ cubemapConvolution: 0
+ cubemapConvolutionSteps: 7
+ cubemapConvolutionExponent: 1.5
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ rGBM: 0
+ compressionQuality: 50
+ allowsAlphaSplitting: 0
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ buildTargetSettings: []
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/BackfacesButton.psd b/Assets/Obi/Editor/Resources/BackfacesButton.psd
new file mode 100644
index 000000000..325bbf2ec
Binary files /dev/null and b/Assets/Obi/Editor/Resources/BackfacesButton.psd differ
diff --git a/Assets/Obi/Editor/Resources/BackfacesButton.psd.meta b/Assets/Obi/Editor/Resources/BackfacesButton.psd.meta
new file mode 100644
index 000000000..9e88b6687
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/BackfacesButton.psd.meta
@@ -0,0 +1,59 @@
+fileFormatVersion: 2
+guid: 6463b09cd29e543a49c1e2ea87b121f3
+timeCreated: 1478799645
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 2
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ linearTexture: 1
+ correctGamma: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 0
+ cubemapConvolution: 0
+ cubemapConvolutionSteps: 7
+ cubemapConvolutionExponent: 1.5
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ rGBM: 0
+ compressionQuality: 50
+ allowsAlphaSplitting: 0
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ buildTargetSettings: []
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/BranchButton.png b/Assets/Obi/Editor/Resources/BranchButton.png
new file mode 100644
index 000000000..c389a9735
Binary files /dev/null and b/Assets/Obi/Editor/Resources/BranchButton.png differ
diff --git a/Assets/Obi/Editor/Resources/BranchButton.png.meta b/Assets/Obi/Editor/Resources/BranchButton.png.meta
new file mode 100644
index 000000000..6a4866bcd
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/BranchButton.png.meta
@@ -0,0 +1,117 @@
+fileFormatVersion: 2
+guid: 4bb29d51ae50c4ee4acac3acc8c0cb18
+TextureImporter:
+ fileIDToRecycleName: {}
+ externalObjects: {}
+ serializedVersion: 5
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapU: 1
+ wrapV: 1
+ wrapW: -1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - serializedVersion: 2
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ - serializedVersion: 2
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ - serializedVersion: 2
+ buildTarget: iPhone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ - serializedVersion: 2
+ buildTarget: Android
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/BrushHandle.psd b/Assets/Obi/Editor/Resources/BrushHandle.psd
new file mode 100644
index 000000000..43cd79c00
Binary files /dev/null and b/Assets/Obi/Editor/Resources/BrushHandle.psd differ
diff --git a/Assets/Obi/Editor/Resources/BrushHandle.psd.meta b/Assets/Obi/Editor/Resources/BrushHandle.psd.meta
new file mode 100644
index 000000000..812e50ad4
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/BrushHandle.psd.meta
@@ -0,0 +1,55 @@
+fileFormatVersion: 2
+guid: 5cbb736fc86b64409b40fe7050933899
+timeCreated: 1441952145
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 2
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ linearTexture: 1
+ correctGamma: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: .25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 0
+ cubemapConvolution: 0
+ cubemapConvolutionSteps: 8
+ cubemapConvolutionExponent: 1.5
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ rGBM: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: .5, y: .5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaIsTransparency: 1
+ textureType: 2
+ buildTargetSettings: []
+ spriteSheet:
+ sprites: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/BrushIcon.psd b/Assets/Obi/Editor/Resources/BrushIcon.psd
new file mode 100644
index 000000000..b3bbf8bd8
Binary files /dev/null and b/Assets/Obi/Editor/Resources/BrushIcon.psd differ
diff --git a/Assets/Obi/Editor/Resources/BrushIcon.psd.meta b/Assets/Obi/Editor/Resources/BrushIcon.psd.meta
new file mode 100644
index 000000000..aa215c88b
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/BrushIcon.psd.meta
@@ -0,0 +1,55 @@
+fileFormatVersion: 2
+guid: 652e8f881c4764ec9a7705aac5ed0e84
+timeCreated: 1442227627
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 2
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ linearTexture: 1
+ correctGamma: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: .25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 0
+ cubemapConvolution: 0
+ cubemapConvolutionSteps: 8
+ cubemapConvolutionExponent: 1.5
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ rGBM: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: .5, y: .5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaIsTransparency: 1
+ textureType: 2
+ buildTargetSettings: []
+ spriteSheet:
+ sprites: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/ClearButton.psd b/Assets/Obi/Editor/Resources/ClearButton.psd
new file mode 100644
index 000000000..fca2599fc
Binary files /dev/null and b/Assets/Obi/Editor/Resources/ClearButton.psd differ
diff --git a/Assets/Obi/Editor/Resources/ClearButton.psd.meta b/Assets/Obi/Editor/Resources/ClearButton.psd.meta
new file mode 100644
index 000000000..ec97fbfbc
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/ClearButton.psd.meta
@@ -0,0 +1,59 @@
+fileFormatVersion: 2
+guid: e6e3e5775eebd49e6aee6abb8470baa9
+timeCreated: 1478799645
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 2
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ linearTexture: 1
+ correctGamma: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 0
+ cubemapConvolution: 0
+ cubemapConvolutionSteps: 7
+ cubemapConvolutionExponent: 1.5
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ rGBM: 0
+ compressionQuality: 50
+ allowsAlphaSplitting: 0
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ buildTargetSettings: []
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/ClearTethersButton.psd b/Assets/Obi/Editor/Resources/ClearTethersButton.psd
new file mode 100644
index 000000000..12467dd84
Binary files /dev/null and b/Assets/Obi/Editor/Resources/ClearTethersButton.psd differ
diff --git a/Assets/Obi/Editor/Resources/ClearTethersButton.psd.meta b/Assets/Obi/Editor/Resources/ClearTethersButton.psd.meta
new file mode 100644
index 000000000..b06e21fb1
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/ClearTethersButton.psd.meta
@@ -0,0 +1,59 @@
+fileFormatVersion: 2
+guid: 0458bb2ee7da84bf6b990ed5679e8e22
+timeCreated: 1478799645
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 2
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ linearTexture: 1
+ correctGamma: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 0
+ cubemapConvolution: 0
+ cubemapConvolutionSteps: 7
+ cubemapConvolutionExponent: 1.5
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ rGBM: 0
+ compressionQuality: 50
+ allowsAlphaSplitting: 0
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ buildTargetSettings: []
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/DistanceFieldPreview.mat b/Assets/Obi/Editor/Resources/DistanceFieldPreview.mat
new file mode 100644
index 000000000..8c7ff52c5
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/DistanceFieldPreview.mat
@@ -0,0 +1,91 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!21 &2100000
+Material:
+ serializedVersion: 8
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_Name: DistanceFieldPreview
+ m_Shader: {fileID: 4800000, guid: f667dd333ac88440587339a2a1ac0027, type: 3}
+ m_Parent: {fileID: 0}
+ m_ModifiedSerializedProperties: 0
+ m_ValidKeywords: []
+ m_InvalidKeywords: []
+ m_LightmapFlags: 5
+ m_EnableInstancingVariants: 0
+ m_DoubleSidedGI: 0
+ m_CustomRenderQueue: -1
+ stringTagMap: {}
+ disabledShaderPasses: []
+ m_LockedProperties:
+ m_SavedProperties:
+ serializedVersion: 3
+ m_TexEnvs:
+ - _BumpMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _DetailAlbedoMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _DetailMask:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _DetailNormalMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _EmissionMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _MainTex:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _MetallicGlossMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _OcclusionMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _ParallaxMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _Volume:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ m_Ints: []
+ m_Floats:
+ - _Absorption: 2
+ - _BumpScale: 1
+ - _Cutoff: 0.5
+ - _DetailNormalMapScale: 1
+ - _DstBlend: 0
+ - _Glossiness: 0.5
+ - _MaxSteps: 300
+ - _Metallic: 0
+ - _Mode: 0
+ - _OcclusionStrength: 1
+ - _Parallax: 0.02
+ - _SrcBlend: 1
+ - _StepSize: 0.01
+ - _UVSec: 0
+ - _ZWrite: 1
+ m_Colors:
+ - _AABBMax: {r: 1.1746451, g: 1.1746451, b: 1.1746451, a: 0}
+ - _AABBMin: {r: -1.1746451, g: -1.1746451, b: -1.1746451, a: 0}
+ - _Color: {r: 1, g: 1, b: 1, a: 1}
+ - _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
+ - _InsideColor: {r: 1, g: 1, b: 1, a: 1}
+ - _OutsideColor: {r: 0, g: 0, b: 0, a: 1}
+ m_BuildTextureStacks: []
+ m_AllowLocking: 1
diff --git a/Assets/Obi/Editor/Resources/DistanceFieldPreview.mat.meta b/Assets/Obi/Editor/Resources/DistanceFieldPreview.mat.meta
new file mode 100644
index 000000000..0e5f4b005
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/DistanceFieldPreview.mat.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 5dde1f45f471c48a1a13fc4b8c0b5b43
+timeCreated: 1438180916
+licenseType: Store
+NativeFormatImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/DistanceFieldPreview.shader b/Assets/Obi/Editor/Resources/DistanceFieldPreview.shader
new file mode 100644
index 000000000..5b6de21f6
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/DistanceFieldPreview.shader
@@ -0,0 +1,121 @@
+// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
+
+// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'
+
+
+Shader "Obi/Distance Field Preview" {
+ Properties {
+ _Volume ("Texture", 3D) = "" {}
+ _AABBMin("AABB Min",Vector) = (-0.5,-0.5,-0.5)
+ _AABBMax("AABB Max",Vector) = (0.5,0.5,0.5)
+ _InsideColor("Inside color",Color) = (1,1,1,1)
+ _OutsideColor("Outside color",Color) = (0,0,0,1)
+ _Absorption("Absorption",Float) = 1.5
+ _StepSize("Step size",Float) = 0.01
+ _MaxSteps("Max steps",Int) = 300
+ }
+ SubShader {
+ Pass {
+
+ CGPROGRAM
+ #pragma vertex vert
+ #pragma fragment frag
+ #pragma exclude_renderers flash gles
+
+ #include "UnityCG.cginc"
+
+ struct vs_input {
+ float4 vertex : POSITION;
+ };
+
+ struct ps_input {
+ float4 pos : SV_POSITION;
+ float3 eyeOrigin : TEXCOORD0;
+ float3 eyeDir : TEXCOORD1;
+ };
+
+
+ ps_input vert (vs_input v)
+ {
+ ps_input o;
+ o.pos = UnityObjectToClipPos (v.vertex);
+
+ o.eyeOrigin = mul((float3x3)unity_WorldToObject, _WorldSpaceCameraPos); // object space eye origin
+ o.eyeDir = -ObjSpaceViewDir(v.vertex); // object space eye direction
+ return o;
+ }
+
+ sampler3D _Volume;
+ float3 _AABBMin;
+ float3 _AABBMax;
+ float _Absorption;
+ float _StepSize;
+ int _MaxSteps;
+ half4 _InsideColor;
+ half4 _OutsideColor;
+
+ bool IntersectBox(float3 rayOrigin, float3 rayDir, float3 aabbMin, float3 aabbMax, out float t0, out float t1)
+ {
+ float3 invR = 1.0 / rayDir;
+ float3 tbot = invR * (aabbMin-rayOrigin);
+ float3 ttop = invR * (aabbMax-rayOrigin);
+ float3 tmin = min(ttop, tbot);
+ float3 tmax = max(ttop, tbot);
+ float2 t = max(tmin.xx, tmin.yz);
+ t0 = max(t.x, t.y);
+ t = min(tmax.xx, tmax.yz);
+ t1 = min(t.x, t.y);
+ return t0 <= t1;
+ }
+
+
+ float4 frag (ps_input input) : COLOR
+ {
+ float4 dst = float4(0.0, 0.0, 0.0, 0.0);
+
+ // Calculate ray direction
+ float3 eyeDirection = normalize(input.eyeDir);
+
+ //Calculate intersection with bounding box:
+ float tnear, tfar;
+ if (IntersectBox(input.eyeOrigin,eyeDirection,_AABBMin,_AABBMax,tnear,tfar)){
+ if (tnear < 0.0) tnear = 0.0;
+
+ //Calculate ray start and stop positions:
+ float3 rayStart = input.eyeOrigin + eyeDirection * tnear;
+ float3 rayStop = input.eyeOrigin + eyeDirection * tfar;
+
+ // Transform from object space bounds to texture coordinate space:
+ float3 aabbSize = _AABBMax-_AABBMin;
+ rayStart = (rayStart-_AABBMin) / aabbSize;
+ rayStop = (rayStop-_AABBMin) / aabbSize;
+
+ // Raytrace:
+ float3 pos = rayStart;
+ float3 step = normalize(rayStop-rayStart) * _StepSize;
+ float travel = distance(rayStop,rayStart);
+
+ for (int i=0; i < _MaxSteps && travel > 0.0; ++i, pos += step, travel -= _StepSize) {
+
+ float value = tex3Dlod(_Volume, float4(pos,0)).a;
+ float4 color;
+ if (value > 0.5){ //outside the surface.
+ color = _OutsideColor * (1 - value) * 2;
+ }else{ //inside the surface.
+ color = _InsideColor * value * 2;
+ }
+ dst += color * _StepSize * _Absorption;
+
+ }
+ }
+
+ return dst;
+ }
+
+ ENDCG
+
+ }
+ }
+
+ Fallback "VertexLit"
+}
\ No newline at end of file
diff --git a/Assets/Obi/Editor/Resources/DistanceFieldPreview.shader.meta b/Assets/Obi/Editor/Resources/DistanceFieldPreview.shader.meta
new file mode 100644
index 000000000..84621625c
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/DistanceFieldPreview.shader.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: f667dd333ac88440587339a2a1ac0027
+timeCreated: 1438180827
+licenseType: Store
+ShaderImporter:
+ defaultTextures: []
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/EditCurves.psd b/Assets/Obi/Editor/Resources/EditCurves.psd
new file mode 100644
index 000000000..2a82cde45
Binary files /dev/null and b/Assets/Obi/Editor/Resources/EditCurves.psd differ
diff --git a/Assets/Obi/Editor/Resources/EditCurves.psd.meta b/Assets/Obi/Editor/Resources/EditCurves.psd.meta
new file mode 100644
index 000000000..e2d484986
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/EditCurves.psd.meta
@@ -0,0 +1,116 @@
+fileFormatVersion: 2
+guid: 5de08540b1d0e4ed9b02351ecf5fb429
+TextureImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 11
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ sRGBTexture: 1
+ linearTexture: 1
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: 1
+ aniso: 1
+ mipBias: 0
+ wrapU: 1
+ wrapV: 1
+ wrapW: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ applyGammaDecoding: 1
+ platformSettings:
+ - serializedVersion: 3
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: iPhone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ spritePackingTag:
+ pSDRemoveMatte: 1
+ pSDShowRemoveMatteOption: 1
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/EditParticles.psd b/Assets/Obi/Editor/Resources/EditParticles.psd
new file mode 100644
index 000000000..14a51cef1
Binary files /dev/null and b/Assets/Obi/Editor/Resources/EditParticles.psd differ
diff --git a/Assets/Obi/Editor/Resources/EditParticles.psd.meta b/Assets/Obi/Editor/Resources/EditParticles.psd.meta
new file mode 100644
index 000000000..f5ed72827
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/EditParticles.psd.meta
@@ -0,0 +1,57 @@
+fileFormatVersion: 2
+guid: 8ec838b6f6b4a49c5b127c7342c6657b
+timeCreated: 1450429847
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 2
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ linearTexture: 1
+ correctGamma: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 0
+ cubemapConvolution: 0
+ cubemapConvolutionSteps: 7
+ cubemapConvolutionExponent: 1.5
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ rGBM: 0
+ compressionQuality: 50
+ allowsAlphaSplitting: 0
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaIsTransparency: 1
+ textureType: 2
+ buildTargetSettings: []
+ spriteSheet:
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/EditorLineShader.shader b/Assets/Obi/Editor/Resources/EditorLineShader.shader
new file mode 100644
index 000000000..d44991f8b
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/EditorLineShader.shader
@@ -0,0 +1,17 @@
+Shader "Obi/EditorLines"
+{
+ SubShader
+ {
+ Pass
+ {
+ Blend SrcAlpha OneMinusSrcAlpha
+ Cull Off
+ ZTest Always
+ Fog { Mode Off }
+ BindChannels
+ {
+ Bind "vertex", vertex Bind "color", color
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/Obi/Editor/Resources/EditorLineShader.shader.meta b/Assets/Obi/Editor/Resources/EditorLineShader.shader.meta
new file mode 100644
index 000000000..f880ee9a0
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/EditorLineShader.shader.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 80a01a94e9fdb445a9e6dff54db02fa9
+timeCreated: 1470908721
+licenseType: Store
+ShaderImporter:
+ defaultTextures: []
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/EditorLines.mat b/Assets/Obi/Editor/Resources/EditorLines.mat
new file mode 100644
index 000000000..c27133a91
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/EditorLines.mat
@@ -0,0 +1,85 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!21 &2100000
+Material:
+ serializedVersion: 8
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_Name: EditorLines
+ m_Shader: {fileID: 4800000, guid: 80a01a94e9fdb445a9e6dff54db02fa9, type: 3}
+ m_Parent: {fileID: 0}
+ m_ModifiedSerializedProperties: 0
+ m_ValidKeywords: []
+ m_InvalidKeywords:
+ - _EMISSION
+ m_LightmapFlags: 1
+ m_EnableInstancingVariants: 0
+ m_DoubleSidedGI: 0
+ m_CustomRenderQueue: -1
+ stringTagMap: {}
+ disabledShaderPasses: []
+ m_LockedProperties:
+ m_SavedProperties:
+ serializedVersion: 3
+ m_TexEnvs:
+ - _BumpMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _DetailAlbedoMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _DetailMask:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _DetailNormalMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _EmissionMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _MainTex:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _MetallicGlossMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _OcclusionMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _ParallaxMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ m_Ints: []
+ m_Floats:
+ - _BumpScale: 1
+ - _Cutoff: 0.5
+ - _DetailNormalMapScale: 1
+ - _DstBlend: 0
+ - _GlossMapScale: 1
+ - _Glossiness: 0.5
+ - _GlossyReflections: 1
+ - _Metallic: 0
+ - _Mode: 0
+ - _OcclusionStrength: 1
+ - _Parallax: 0.02
+ - _SmoothnessTextureChannel: 0
+ - _SpecularHighlights: 1
+ - _SrcBlend: 1
+ - _UVSec: 0
+ - _ZWrite: 1
+ m_Colors:
+ - _Color: {r: 1, g: 1, b: 1, a: 1}
+ - _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
+ m_BuildTextureStacks: []
+ m_AllowLocking: 1
diff --git a/Assets/Obi/Editor/Resources/EditorLines.mat.meta b/Assets/Obi/Editor/Resources/EditorLines.mat.meta
new file mode 100644
index 000000000..a41900376
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/EditorLines.mat.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: f3999384313644fe3b9ba16589efe636
+timeCreated: 1470908872
+licenseType: Store
+NativeFormatImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/EditorParticle.mat b/Assets/Obi/Editor/Resources/EditorParticle.mat
new file mode 100644
index 000000000..926057759
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/EditorParticle.mat
@@ -0,0 +1,80 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!21 &2100000
+Material:
+ serializedVersion: 8
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_Name: EditorParticle
+ m_Shader: {fileID: 4800000, guid: a16859f14873144e2b41f2bd03a84bbc, type: 3}
+ m_Parent: {fileID: 0}
+ m_ModifiedSerializedProperties: 0
+ m_ValidKeywords: []
+ m_InvalidKeywords: []
+ m_LightmapFlags: 5
+ m_EnableInstancingVariants: 0
+ m_DoubleSidedGI: 0
+ m_CustomRenderQueue: -1
+ stringTagMap: {}
+ disabledShaderPasses: []
+ m_LockedProperties:
+ m_SavedProperties:
+ serializedVersion: 3
+ m_TexEnvs:
+ - _BumpMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _DetailAlbedoMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _DetailMask:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _DetailNormalMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _EmissionMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _MainTex:
+ m_Texture: {fileID: 2800000, guid: 7e271617753294f4aaf5d79862c5d182, type: 3}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _MetallicGlossMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _OcclusionMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _ParallaxMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ m_Ints: []
+ m_Floats:
+ - _BumpScale: 1
+ - _Cutoff: 0.5
+ - _DetailNormalMapScale: 1
+ - _DstBlend: 0
+ - _Glossiness: 0.5
+ - _Metallic: 0
+ - _Mode: 0
+ - _OcclusionStrength: 1
+ - _Parallax: 0.02
+ - _SrcBlend: 1
+ - _UVSec: 0
+ - _ZWrite: 1
+ m_Colors:
+ - _Color: {r: 1, g: 1, b: 1, a: 1}
+ - _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
+ m_BuildTextureStacks: []
+ m_AllowLocking: 1
diff --git a/Assets/Obi/Editor/Resources/EditorParticle.mat.meta b/Assets/Obi/Editor/Resources/EditorParticle.mat.meta
new file mode 100644
index 000000000..c04a62200
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/EditorParticle.mat.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 8c668cf76c548481c80404cce80ab834
+timeCreated: 1445287098
+licenseType: Store
+NativeFormatImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/EditorParticle.shader b/Assets/Obi/Editor/Resources/EditorParticle.shader
new file mode 100644
index 000000000..214d6e40b
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/EditorParticle.shader
@@ -0,0 +1,60 @@
+Shader "Obi/EditorPoint"
+{
+ SubShader
+ {
+ Blend One OneMinusSrcAlpha
+ ZWrite Off
+ ZTest always
+ Cull Back
+
+ Pass
+ {
+ CGPROGRAM
+ #pragma vertex vert
+ #pragma fragment frag
+
+ #include "UnityCG.cginc"
+
+ struct appdata
+ {
+ float4 vertex : POSITION;
+ float3 corner : NORMAL;
+ fixed4 color : COLOR;
+ float4 t0 : TEXCOORD0; // ellipsoid t1 vector
+ };
+
+ struct v2f
+ {
+ float4 pos : SV_POSITION;
+ fixed4 color : COLOR;
+ float2 texcoord : TEXCOORD0;
+ };
+
+ v2f vert (appdata v)
+ {
+ v2f o;
+
+ // particle positions are passed in world space, no need to use modelview matrix, just view.
+ float radius = v.t0.w * distance(mul(unity_ObjectToWorld, v.vertex), _WorldSpaceCameraPos);
+ float4 viewpos = mul(UNITY_MATRIX_V, v.vertex) + float4(v.corner.x, v.corner.y, 0, 0) * radius;
+ o.pos = mul(UNITY_MATRIX_P, viewpos);
+
+ o.texcoord = float3(v.corner.x*0.5, v.corner.y*0.5, radius);
+ o.color = v.color;
+
+ return o;
+ }
+
+ fixed4 frag (v2f i) : SV_Target
+ {
+ // antialiased circle:
+ float dist = length(i.texcoord);
+ float pwidth = fwidth(dist);
+ float alpha = i.color.a * saturate((0.5 - dist) / pwidth);
+
+ return fixed4(i.color.rgb * alpha, alpha);
+ }
+ ENDCG
+ }
+ }
+}
diff --git a/Assets/Obi/Editor/Resources/EditorParticle.shader.meta b/Assets/Obi/Editor/Resources/EditorParticle.shader.meta
new file mode 100644
index 000000000..3dd4ff7c4
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/EditorParticle.shader.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: a16859f14873144e2b41f2bd03a84bbc
+timeCreated: 1445287084
+licenseType: Store
+ShaderImporter:
+ defaultTextures: []
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/EditorParticleShader.shader b/Assets/Obi/Editor/Resources/EditorParticleShader.shader
new file mode 100644
index 000000000..5db70c755
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/EditorParticleShader.shader
@@ -0,0 +1,133 @@
+Shader "Obi/EditorParticles" {
+
+ Properties {
+ _Color ("Particle color", Color) = (1,1,1,1)
+ _RadiusScale("Radius scale",float) = 1
+ }
+
+ SubShader {
+
+ Pass {
+
+ Name "EditorParticle"
+ Tags {"Queue"="Geometry" "IgnoreProjector"="True" "RenderType"="Opaque"}
+ Blend SrcAlpha OneMinusSrcAlpha
+
+ CGPROGRAM
+ #pragma vertex vert
+ #pragma fragment frag
+ #pragma fragmentoption ARB_precision_hint_fastest
+
+ #include "../../Resources/ObiMaterials/Common/ObiEllipsoids.cginc"
+ #include "../../Resources/ObiMaterials/Common/ObiUtils.cginc"
+
+ fixed4 _Color;
+
+ struct vin{
+ float4 vertex : POSITION;
+ float3 corner : NORMAL;
+ fixed4 color : COLOR;
+
+ float4 t0 : TEXCOORD0; // ellipsoid t1 vector
+ float4 t1 : TEXCOORD1; // ellipsoid t2 vector
+ float4 t2 : TEXCOORD2; // ellipsoid t3 vector
+ };
+
+ struct v2f
+ {
+ float4 pos : SV_POSITION;
+ fixed4 color : COLOR;
+ float4 mapping : TEXCOORD0;
+ float3 viewRay : TEXCOORD1;
+ float3 lightDir : TEXCOORD2;
+ float3 a2 : TEXCOORD3;
+ float3 a3 : TEXCOORD4;
+ //float3x3 P : TEXCOORD5;
+ };
+
+ struct fout
+ {
+ half4 color : SV_Target;
+ float depth : SV_Depth;
+ };
+
+ v2f vert(vin v)
+ {
+ float3x3 P, IP;
+ BuildParameterSpaceMatrices(v.t0,v.t1,v.t2,P,IP);
+
+ float3 worldPos;
+ float3 view;
+ float3 eye;
+ float radius = BuildEllipsoidBillboard(v.vertex,v.corner,P,IP,worldPos,view,eye);
+
+ v2f o;
+ o.pos = mul(UNITY_MATRIX_VP, float4(worldPos,v.vertex.w));
+ o.mapping = float4(v.corner.xy,1/length(eye),radius); // A[1]
+ o.viewRay = mul((float3x3)UNITY_MATRIX_V,view); // A[0]
+ o.color = v.color * _Color;
+ //o.P = float3x3(v.t0.xyz,v.t1.xyz,v.t2.xyz);
+
+ BuildAuxiliaryNormalVectors(v.vertex,worldPos,view,P,IP,o.a2,o.a3);
+
+ o.lightDir = mul((float3x3)UNITY_MATRIX_MV, float3(0.5f,0.5f,0.5f));
+
+ return o;
+ }
+
+ fout frag(v2f i)
+ {
+ fout fo;
+
+ fo.color = half4(0,0,0,i.color.a);
+
+ // generate sphere normals:
+ float3 p,n;
+ IntersectEllipsoid(i.viewRay,i.mapping, i.a2,i.a3,p, n);
+
+ // clip space position:
+ float4 pos = mul(UNITY_MATRIX_P,float4(p,1.0));
+
+ // local space normal, use to calculate UVs
+ /*float3 ln = mul(mul((float3x3)i.P,UNITY_MATRIX_I_V) ,n);
+
+ float2 uv = float2(
+ // atan returns a value between -pi and pi
+ // so we divide by pi * 2 to get -0.5 to 0.5
+ atan2(ln.x, ln.y) / (3.1415 * 2.0),
+ // acos returns 0.0 at the top, pi at the bottom
+ // so we flip the y to align with Unity's OpenGL style
+ // texture UVs so 0.0 is at the bottom
+ acos(-ln.z) / 3.1415
+ );*/
+
+ // simple lighting: ambient
+ float3 modelUp = mul (UNITY_MATRIX_IT_MV,float3(0,1,0));
+ float vecHemi = dot(n, modelUp) * 0.5f + 0.5f;
+ half3 amb = 0.6f * lerp(float3(0.5f,0.48f,0.45f), float3(0.8f,0.9f,1), vecHemi);
+
+ // simple lighting: diffuse
+ float ndotl = saturate( dot( n, normalize(i.lightDir) ) );
+
+ // final lit color:
+ fo.color.rgb = i.color * (0.5f * ndotl + amb);
+
+ // normalized device coordinates:
+ fo.depth = pos.z/pos.w;
+
+ // in openGL calculated depth range is <-1,1> map it to <0,1>
+ #if SHADER_API_OPENGL || SHADER_API_GLCORE || SHADER_API_GLES || SHADER_API_GLES3
+ fo.depth = 0.5*fo.depth + 0.5;
+ #endif
+
+ return fo;
+ }
+
+ ENDCG
+
+ }
+
+ }
+FallBack "Diffuse"
+}
+
diff --git a/Assets/Obi/Editor/Resources/EditorParticleShader.shader.meta b/Assets/Obi/Editor/Resources/EditorParticleShader.shader.meta
new file mode 100644
index 000000000..7e76c5afa
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/EditorParticleShader.shader.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: f909e74f185674832ad45806b9c6e60f
+timeCreated: 1438934781
+licenseType: Store
+ShaderImporter:
+ defaultTextures: []
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/FillButton.psd b/Assets/Obi/Editor/Resources/FillButton.psd
new file mode 100644
index 000000000..ee57c7baf
Binary files /dev/null and b/Assets/Obi/Editor/Resources/FillButton.psd differ
diff --git a/Assets/Obi/Editor/Resources/FillButton.psd.meta b/Assets/Obi/Editor/Resources/FillButton.psd.meta
new file mode 100644
index 000000000..70102da78
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/FillButton.psd.meta
@@ -0,0 +1,59 @@
+fileFormatVersion: 2
+guid: 5aa30f0cf5bab4c7dab839a28bd5a3b8
+timeCreated: 1478802054
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 2
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ linearTexture: 1
+ correctGamma: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 0
+ cubemapConvolution: 0
+ cubemapConvolutionSteps: 7
+ cubemapConvolutionExponent: 1.5
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ rGBM: 0
+ compressionQuality: 50
+ allowsAlphaSplitting: 0
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ buildTargetSettings: []
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/FrontfacesButton.psd b/Assets/Obi/Editor/Resources/FrontfacesButton.psd
new file mode 100644
index 000000000..391194698
Binary files /dev/null and b/Assets/Obi/Editor/Resources/FrontfacesButton.psd differ
diff --git a/Assets/Obi/Editor/Resources/FrontfacesButton.psd.meta b/Assets/Obi/Editor/Resources/FrontfacesButton.psd.meta
new file mode 100644
index 000000000..188af017e
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/FrontfacesButton.psd.meta
@@ -0,0 +1,95 @@
+fileFormatVersion: 2
+guid: 5f827adfcd494429faa0357b10a2b866
+TextureImporter:
+ fileIDToRecycleName: {}
+ externalObjects: {}
+ serializedVersion: 5
+ 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
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapU: 1
+ wrapV: 1
+ wrapW: -1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - serializedVersion: 2
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ - serializedVersion: 2
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/GaussianButton.psd b/Assets/Obi/Editor/Resources/GaussianButton.psd
new file mode 100644
index 000000000..42afd4259
Binary files /dev/null and b/Assets/Obi/Editor/Resources/GaussianButton.psd differ
diff --git a/Assets/Obi/Editor/Resources/GaussianButton.psd.meta b/Assets/Obi/Editor/Resources/GaussianButton.psd.meta
new file mode 100644
index 000000000..8d580bc48
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/GaussianButton.psd.meta
@@ -0,0 +1,55 @@
+fileFormatVersion: 2
+guid: 23303a76d97ac4435b47284e747a1e8f
+timeCreated: 1442227197
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 2
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ linearTexture: 1
+ correctGamma: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: .25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 0
+ cubemapConvolution: 0
+ cubemapConvolutionSteps: 8
+ cubemapConvolutionExponent: 1.5
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ rGBM: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: .5, y: .5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaIsTransparency: 1
+ textureType: 2
+ buildTargetSettings: []
+ spriteSheet:
+ sprites: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/HandleButton.psd b/Assets/Obi/Editor/Resources/HandleButton.psd
new file mode 100644
index 000000000..3b65a0f9b
Binary files /dev/null and b/Assets/Obi/Editor/Resources/HandleButton.psd differ
diff --git a/Assets/Obi/Editor/Resources/HandleButton.psd.meta b/Assets/Obi/Editor/Resources/HandleButton.psd.meta
new file mode 100644
index 000000000..a6a595845
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/HandleButton.psd.meta
@@ -0,0 +1,59 @@
+fileFormatVersion: 2
+guid: 25ef265869b174c41bd35bcb371e0fa9
+timeCreated: 1478802054
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 2
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ linearTexture: 1
+ correctGamma: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 0
+ cubemapConvolution: 0
+ cubemapConvolutionSteps: 7
+ cubemapConvolutionExponent: 1.5
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ rGBM: 0
+ compressionQuality: 50
+ allowsAlphaSplitting: 0
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ buildTargetSettings: []
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons.meta b/Assets/Obi/Editor/Resources/Icons.meta
new file mode 100644
index 000000000..3382ebe47
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 292753011b5614e38934aacb2697fd86
+folderAsset: yes
+timeCreated: 1482921919
+licenseType: Store
+DefaultImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiActorBlueprint Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiActorBlueprint Icon.png
new file mode 100644
index 000000000..850ee5f48
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiActorBlueprint Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiActorBlueprint Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiActorBlueprint Icon.png.meta
new file mode 100644
index 000000000..0e77ce1c7
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiActorBlueprint Icon.png.meta
@@ -0,0 +1,117 @@
+fileFormatVersion: 2
+guid: d0123218ec6144d0983c099fc7339924
+TextureImporter:
+ fileIDToRecycleName: {}
+ externalObjects: {}
+ serializedVersion: 5
+ 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
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapU: 1
+ wrapV: 1
+ wrapW: -1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - serializedVersion: 2
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ - serializedVersion: 2
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ - serializedVersion: 2
+ buildTarget: iPhone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ - serializedVersion: 2
+ buildTarget: Android
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiAerodynamicConstraints Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiAerodynamicConstraints Icon.png
new file mode 100644
index 000000000..ae0f69a06
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiAerodynamicConstraints Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiAerodynamicConstraints Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiAerodynamicConstraints Icon.png.meta
new file mode 100644
index 000000000..fa9e5e66f
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiAerodynamicConstraints Icon.png.meta
@@ -0,0 +1,92 @@
+fileFormatVersion: 2
+guid: 8626b43f419d1466a9dc1c1509308b13
+timeCreated: 1448330601
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 4
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 0
+ linearTexture: 1
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Standalone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: iPhone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Android
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiBendConstraints Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiBendConstraints Icon.png
new file mode 100644
index 000000000..a07cacc4a
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiBendConstraints Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiBendConstraints Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiBendConstraints Icon.png.meta
new file mode 100644
index 000000000..0fd78b8cd
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiBendConstraints Icon.png.meta
@@ -0,0 +1,92 @@
+fileFormatVersion: 2
+guid: f9aac3aba3ca7456d807e7fab120eb8a
+timeCreated: 1448835892
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 4
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 0
+ linearTexture: 1
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Standalone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: iPhone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Android
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiBendTwistConstraints Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiBendTwistConstraints Icon.png
new file mode 100644
index 000000000..63cbd0049
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiBendTwistConstraints Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiBendTwistConstraints Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiBendTwistConstraints Icon.png.meta
new file mode 100644
index 000000000..a3012cd3e
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiBendTwistConstraints Icon.png.meta
@@ -0,0 +1,95 @@
+fileFormatVersion: 2
+guid: 91de8d14a7b7a42d88d336323c428b20
+TextureImporter:
+ fileIDToRecycleName: {}
+ externalObjects: {}
+ serializedVersion: 5
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapU: 1
+ wrapV: 1
+ wrapW: -1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - serializedVersion: 2
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ - serializedVersion: 2
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiBone Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiBone Icon.png
new file mode 100644
index 000000000..6ddf89c7d
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiBone Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiBone Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiBone Icon.png.meta
new file mode 100644
index 000000000..9ec7609e3
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiBone Icon.png.meta
@@ -0,0 +1,140 @@
+fileFormatVersion: 2
+guid: 0a18e0376cc184a9b96ebb3bf0175cc2
+TextureImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 11
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: -1
+ aniso: 1
+ mipBias: -100
+ wrapU: 1
+ wrapV: 1
+ wrapW: -1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ applyGammaDecoding: 0
+ platformSettings:
+ - serializedVersion: 3
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: iPhone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Android
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: WebGL
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ spritePackingTag:
+ pSDRemoveMatte: 0
+ pSDShowRemoveMatteOption: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiChainConstraints Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiChainConstraints Icon.png
new file mode 100644
index 000000000..a07d2cd33
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiChainConstraints Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiChainConstraints Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiChainConstraints Icon.png.meta
new file mode 100644
index 000000000..1596bcb0a
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiChainConstraints Icon.png.meta
@@ -0,0 +1,95 @@
+fileFormatVersion: 2
+guid: 1a42905220c3544c99b3ec98f88b080b
+TextureImporter:
+ fileIDToRecycleName: {}
+ externalObjects: {}
+ serializedVersion: 5
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapU: 1
+ wrapV: 1
+ wrapW: -1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - serializedVersion: 2
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ - serializedVersion: 2
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiCloth Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiCloth Icon.png
new file mode 100644
index 000000000..5c4c59c8a
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiCloth Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiCloth Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiCloth Icon.png.meta
new file mode 100644
index 000000000..c6f8494ad
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiCloth Icon.png.meta
@@ -0,0 +1,92 @@
+fileFormatVersion: 2
+guid: 3970b32a4b80e4a9290b7ac8a8cf2619
+timeCreated: 1502052646
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 4
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 0
+ linearTexture: 1
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: -3
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: 1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 0
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Standalone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 0
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: iPhone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 0
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Android
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 0
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiClothRenderer Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiClothRenderer Icon.png
new file mode 100644
index 000000000..ce6b6bd9a
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiClothRenderer Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiClothRenderer Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiClothRenderer Icon.png.meta
new file mode 100644
index 000000000..b6a8abd88
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiClothRenderer Icon.png.meta
@@ -0,0 +1,103 @@
+fileFormatVersion: 2
+guid: 503f012f470234e44952b01da62590d2
+TextureImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 10
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: -1
+ aniso: 1
+ mipBias: -100
+ wrapU: 1
+ wrapV: 1
+ wrapW: -1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - serializedVersion: 3
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ spritePackingTag:
+ pSDRemoveMatte: 0
+ pSDShowRemoveMatteOption: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiCollider Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiCollider Icon.png
new file mode 100644
index 000000000..d769edbd9
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiCollider Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiCollider Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiCollider Icon.png.meta
new file mode 100644
index 000000000..dbadf1f99
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiCollider Icon.png.meta
@@ -0,0 +1,92 @@
+fileFormatVersion: 2
+guid: 6da22d6bce08a4f3d86542bb903de689
+timeCreated: 1502054757
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 4
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 0
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: -1
+ mipBias: -1
+ wrapMode: -1
+ nPOTScale: 1
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Standalone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: iPhone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Android
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiCollider2D Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiCollider2D Icon.png
new file mode 100644
index 000000000..e08dcb4f9
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiCollider2D Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiCollider2D Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiCollider2D Icon.png.meta
new file mode 100644
index 000000000..8e7ac34da
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiCollider2D Icon.png.meta
@@ -0,0 +1,92 @@
+fileFormatVersion: 2
+guid: e7185d0557058412db2fc499de3a0739
+timeCreated: 1503509205
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 4
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 0
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: -1
+ mipBias: -1
+ wrapMode: -1
+ nPOTScale: 1
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Standalone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: iPhone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Android
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiCollisionMaterial Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiCollisionMaterial Icon.png
new file mode 100644
index 000000000..87f714018
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiCollisionMaterial Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiCollisionMaterial Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiCollisionMaterial Icon.png.meta
new file mode 100644
index 000000000..569974129
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiCollisionMaterial Icon.png.meta
@@ -0,0 +1,92 @@
+fileFormatVersion: 2
+guid: e101664ae1c454916896aaaa3199221c
+timeCreated: 1450304914
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 4
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 0
+ linearTexture: 1
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Standalone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: iPhone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Android
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiCurve Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiCurve Icon.png
new file mode 100644
index 000000000..00ebdb8a2
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiCurve Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiCurve Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiCurve Icon.png.meta
new file mode 100644
index 000000000..c0a6c7cbe
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiCurve Icon.png.meta
@@ -0,0 +1,92 @@
+fileFormatVersion: 2
+guid: ed34a2f317b874412ad24d7bab730ad5
+timeCreated: 1466751256
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 4
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 0
+ linearTexture: 1
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Standalone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: iPhone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Android
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiDistanceConstraints Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiDistanceConstraints Icon.png
new file mode 100644
index 000000000..2ab4ac8bc
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiDistanceConstraints Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiDistanceConstraints Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiDistanceConstraints Icon.png.meta
new file mode 100644
index 000000000..7194cc7c4
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiDistanceConstraints Icon.png.meta
@@ -0,0 +1,92 @@
+fileFormatVersion: 2
+guid: 8be685232a6ad41508d8bbe9d003a892
+timeCreated: 1447902275
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 4
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 0
+ linearTexture: 1
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Standalone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: iPhone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Android
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiDistanceField Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiDistanceField Icon.png
new file mode 100644
index 000000000..b3f52ee66
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiDistanceField Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiDistanceField Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiDistanceField Icon.png.meta
new file mode 100644
index 000000000..fb4c6b08d
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiDistanceField Icon.png.meta
@@ -0,0 +1,92 @@
+fileFormatVersion: 2
+guid: a83ed40096e3a40efa85f35b091e6298
+timeCreated: 1516041722
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 4
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 0
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: -1
+ mipBias: -1
+ wrapMode: -1
+ nPOTScale: 1
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Standalone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: iPhone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Android
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiDistanceFieldRenderer Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiDistanceFieldRenderer Icon.png
new file mode 100644
index 000000000..d5c420dbd
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiDistanceFieldRenderer Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiDistanceFieldRenderer Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiDistanceFieldRenderer Icon.png.meta
new file mode 100644
index 000000000..137973681
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiDistanceFieldRenderer Icon.png.meta
@@ -0,0 +1,92 @@
+fileFormatVersion: 2
+guid: 41cb9d55de5b24458b45e5465606249a
+timeCreated: 1516041845
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 4
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 0
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: -1
+ mipBias: -1
+ wrapMode: -1
+ nPOTScale: 1
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Standalone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: iPhone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Android
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiEmitter Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiEmitter Icon.png
new file mode 100644
index 000000000..51b410b3d
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiEmitter Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiEmitter Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiEmitter Icon.png.meta
new file mode 100644
index 000000000..52988e56f
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiEmitter Icon.png.meta
@@ -0,0 +1,92 @@
+fileFormatVersion: 2
+guid: d1048d188bf4d4e32ac7395da95aedd4
+timeCreated: 1466752717
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 4
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 0
+ linearTexture: 1
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Standalone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: iPhone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Android
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiEmitterMaterialFluid Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiEmitterMaterialFluid Icon.png
new file mode 100644
index 000000000..6a8ebdffb
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiEmitterMaterialFluid Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiEmitterMaterialFluid Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiEmitterMaterialFluid Icon.png.meta
new file mode 100644
index 000000000..81bcc5693
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiEmitterMaterialFluid Icon.png.meta
@@ -0,0 +1,92 @@
+fileFormatVersion: 2
+guid: ea94643102f314a62a9fab85aaf9c559
+timeCreated: 1487699460
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 4
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 0
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Standalone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: iPhone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Android
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiEmitterMaterialGranular Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiEmitterMaterialGranular Icon.png
new file mode 100644
index 000000000..38f11f203
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiEmitterMaterialGranular Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiEmitterMaterialGranular Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiEmitterMaterialGranular Icon.png.meta
new file mode 100644
index 000000000..6a243bbe6
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiEmitterMaterialGranular Icon.png.meta
@@ -0,0 +1,92 @@
+fileFormatVersion: 2
+guid: 7cf34d3db0e2e4a009f29fe06a4240d4
+timeCreated: 1487699330
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 4
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 0
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Standalone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: iPhone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Android
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiEmitterShapeCube Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiEmitterShapeCube Icon.png
new file mode 100644
index 000000000..0f82ff7b2
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiEmitterShapeCube Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiEmitterShapeCube Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiEmitterShapeCube Icon.png.meta
new file mode 100644
index 000000000..4b084eff5
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiEmitterShapeCube Icon.png.meta
@@ -0,0 +1,92 @@
+fileFormatVersion: 2
+guid: 8723f934b6ce94aa698b20cae91c61bd
+timeCreated: 1465712532
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 4
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 0
+ linearTexture: 1
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Standalone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: iPhone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Android
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiEmitterShapeDisk Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiEmitterShapeDisk Icon.png
new file mode 100644
index 000000000..4ab4dbc10
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiEmitterShapeDisk Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiEmitterShapeDisk Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiEmitterShapeDisk Icon.png.meta
new file mode 100644
index 000000000..e97895184
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiEmitterShapeDisk Icon.png.meta
@@ -0,0 +1,92 @@
+fileFormatVersion: 2
+guid: 84f2a1eb2e3bf40edbbfa365ba480de5
+timeCreated: 1465712532
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 4
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 0
+ linearTexture: 1
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Standalone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: iPhone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Android
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiEmitterShapeEdge Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiEmitterShapeEdge Icon.png
new file mode 100644
index 000000000..520c263c5
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiEmitterShapeEdge Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiEmitterShapeEdge Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiEmitterShapeEdge Icon.png.meta
new file mode 100644
index 000000000..382e0513d
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiEmitterShapeEdge Icon.png.meta
@@ -0,0 +1,92 @@
+fileFormatVersion: 2
+guid: 42373f4f9c4d04bc18125f69cf225dc0
+timeCreated: 1465712532
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 4
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 0
+ linearTexture: 1
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Standalone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: iPhone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Android
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiEmitterShapeMesh Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiEmitterShapeMesh Icon.png
new file mode 100644
index 000000000..bb1366c01
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiEmitterShapeMesh Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiEmitterShapeMesh Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiEmitterShapeMesh Icon.png.meta
new file mode 100644
index 000000000..87b746397
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiEmitterShapeMesh Icon.png.meta
@@ -0,0 +1,128 @@
+fileFormatVersion: 2
+guid: aadcf43cc18b74da587fc0fbe4fc019a
+TextureImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 11
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: -1
+ aniso: 1
+ mipBias: -100
+ wrapU: 1
+ wrapV: 1
+ wrapW: -1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ applyGammaDecoding: 0
+ platformSettings:
+ - serializedVersion: 3
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: iPhone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: WebGL
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ spritePackingTag:
+ pSDRemoveMatte: 0
+ pSDShowRemoveMatteOption: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiEmitterShapeSphere Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiEmitterShapeSphere Icon.png
new file mode 100644
index 000000000..29aac3f70
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiEmitterShapeSphere Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiEmitterShapeSphere Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiEmitterShapeSphere Icon.png.meta
new file mode 100644
index 000000000..28402b89f
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiEmitterShapeSphere Icon.png.meta
@@ -0,0 +1,92 @@
+fileFormatVersion: 2
+guid: 882466012f5c44b69b035a407aa63e16
+timeCreated: 1465712839
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 4
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 0
+ linearTexture: 1
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Standalone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: iPhone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Android
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiEmitterShapeSquare Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiEmitterShapeSquare Icon.png
new file mode 100644
index 000000000..6f60ed85a
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiEmitterShapeSquare Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiEmitterShapeSquare Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiEmitterShapeSquare Icon.png.meta
new file mode 100644
index 000000000..767c55041
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiEmitterShapeSquare Icon.png.meta
@@ -0,0 +1,100 @@
+fileFormatVersion: 2
+guid: 775a8b8dbdc9a4bb9b5e06b22255ab80
+timeCreated: 1490861263
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 4
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 0
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Standalone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: iPhone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Android
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: WebGL
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiFluidRenderer Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiFluidRenderer Icon.png
new file mode 100644
index 000000000..8bbace701
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiFluidRenderer Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiFluidRenderer Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiFluidRenderer Icon.png.meta
new file mode 100644
index 000000000..5699caa0e
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiFluidRenderer Icon.png.meta
@@ -0,0 +1,92 @@
+fileFormatVersion: 2
+guid: d1aaaa02ae8dd4da2a59227f5e4a3689
+timeCreated: 1487699364
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 4
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 0
+ linearTexture: 1
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Standalone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: iPhone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Android
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiFoamGenerator Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiFoamGenerator Icon.png
new file mode 100644
index 000000000..4a6c6a697
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiFoamGenerator Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiFoamGenerator Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiFoamGenerator Icon.png.meta
new file mode 100644
index 000000000..9e9122967
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiFoamGenerator Icon.png.meta
@@ -0,0 +1,122 @@
+fileFormatVersion: 2
+guid: b7cec6e680e3a479ca03a89eccd4e052
+TextureImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 11
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ vTOnly: 0
+ ignoreMasterTextureLimit: 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: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ singleChannelComponent: 0
+ flipbookRows: 1
+ flipbookColumns: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ ignorePngGamma: 0
+ applyGammaDecoding: 0
+ platformSettings:
+ - serializedVersion: 3
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Server
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ nameFileIdTable: {}
+ spritePackingTag:
+ pSDRemoveMatte: 0
+ pSDShowRemoveMatteOption: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiForceZone Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiForceZone Icon.png
new file mode 100644
index 000000000..f8ffcb82f
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiForceZone Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiForceZone Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiForceZone Icon.png.meta
new file mode 100644
index 000000000..0790eb996
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiForceZone Icon.png.meta
@@ -0,0 +1,92 @@
+fileFormatVersion: 2
+guid: d7b67d3b64785476bb7520aa3190fee3
+timeCreated: 1482503923
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 4
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 0
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Standalone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: iPhone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Android
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiMeshTopology Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiMeshTopology Icon.png
new file mode 100644
index 000000000..7926bff21
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiMeshTopology Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiMeshTopology Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiMeshTopology Icon.png.meta
new file mode 100644
index 000000000..95d97f436
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiMeshTopology Icon.png.meta
@@ -0,0 +1,92 @@
+fileFormatVersion: 2
+guid: 8e5266f7a0df04a17a5505a19aa2d4d1
+timeCreated: 1452221150
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 4
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 0
+ linearTexture: 1
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Standalone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: iPhone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Android
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiParticleHandle Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiParticleHandle Icon.png
new file mode 100644
index 000000000..e50bb19e5
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiParticleHandle Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiParticleHandle Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiParticleHandle Icon.png.meta
new file mode 100644
index 000000000..f6ce7de1f
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiParticleHandle Icon.png.meta
@@ -0,0 +1,92 @@
+fileFormatVersion: 2
+guid: 528d201bc10084452b24974deb16a423
+timeCreated: 1464049002
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 4
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 0
+ linearTexture: 1
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Standalone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: iPhone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Android
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiParticlePicker Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiParticlePicker Icon.png
new file mode 100644
index 000000000..75f706cfd
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiParticlePicker Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiParticlePicker Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiParticlePicker Icon.png.meta
new file mode 100644
index 000000000..0c23c24ff
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiParticlePicker Icon.png.meta
@@ -0,0 +1,92 @@
+fileFormatVersion: 2
+guid: 0f9d020f7c659443a93327a34ede18b4
+timeCreated: 1484584318
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 4
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 0
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Standalone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: iPhone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Android
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiParticleRenderer Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiParticleRenderer Icon.png
new file mode 100644
index 000000000..b234cb105
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiParticleRenderer Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiParticleRenderer Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiParticleRenderer Icon.png.meta
new file mode 100644
index 000000000..743e09c4f
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiParticleRenderer Icon.png.meta
@@ -0,0 +1,92 @@
+fileFormatVersion: 2
+guid: f424a87c9f03240c2870a664731ac9aa
+timeCreated: 1447901223
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 4
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 0
+ linearTexture: 1
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Standalone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: iPhone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Android
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiPathSmoother Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiPathSmoother Icon.png
new file mode 100644
index 000000000..939d32095
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiPathSmoother Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiPathSmoother Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiPathSmoother Icon.png.meta
new file mode 100644
index 000000000..61b9afb8d
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiPathSmoother Icon.png.meta
@@ -0,0 +1,122 @@
+fileFormatVersion: 2
+guid: 8791eecf125744cbeadea65319c29d5a
+TextureImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 11
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ vTOnly: 0
+ ignoreMasterTextureLimit: 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: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ singleChannelComponent: 0
+ flipbookRows: 1
+ flipbookColumns: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ ignorePngGamma: 0
+ applyGammaDecoding: 0
+ platformSettings:
+ - serializedVersion: 3
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Server
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ nameFileIdTable: {}
+ spritePackingTag:
+ pSDRemoveMatte: 0
+ pSDShowRemoveMatteOption: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiPinConstraints Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiPinConstraints Icon.png
new file mode 100644
index 000000000..81eb89c68
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiPinConstraints Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiPinConstraints Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiPinConstraints Icon.png.meta
new file mode 100644
index 000000000..2861a1fb7
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiPinConstraints Icon.png.meta
@@ -0,0 +1,92 @@
+fileFormatVersion: 2
+guid: 85e4f507907784b9eb4637afe5c2e3a4
+timeCreated: 1450305437
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 4
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 0
+ linearTexture: 1
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Standalone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: iPhone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Android
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiPinhole Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiPinhole Icon.png
new file mode 100644
index 000000000..da8dbd83b
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiPinhole Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiPinhole Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiPinhole Icon.png.meta
new file mode 100644
index 000000000..25f78f309
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiPinhole Icon.png.meta
@@ -0,0 +1,122 @@
+fileFormatVersion: 2
+guid: 214df93f7c2ed4c1094bb6105c050575
+TextureImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 11
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ vTOnly: 0
+ ignoreMasterTextureLimit: 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: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ singleChannelComponent: 0
+ flipbookRows: 1
+ flipbookColumns: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ ignorePngGamma: 0
+ applyGammaDecoding: 0
+ platformSettings:
+ - serializedVersion: 3
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Server
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ nameFileIdTable: {}
+ spritePackingTag:
+ pSDRemoveMatte: 0
+ pSDShowRemoveMatteOption: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiPlant Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiPlant Icon.png
new file mode 100644
index 000000000..bfa508a59
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiPlant Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiPlant Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiPlant Icon.png.meta
new file mode 100644
index 000000000..3522620ff
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiPlant Icon.png.meta
@@ -0,0 +1,117 @@
+fileFormatVersion: 2
+guid: 0edcf127e08404f979b63884bc2c0173
+TextureImporter:
+ fileIDToRecycleName: {}
+ externalObjects: {}
+ serializedVersion: 5
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapU: 1
+ wrapV: 1
+ wrapW: -1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - serializedVersion: 2
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ - serializedVersion: 2
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ - serializedVersion: 2
+ buildTarget: iPhone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ - serializedVersion: 2
+ buildTarget: Android
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiProfiler Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiProfiler Icon.png
new file mode 100644
index 000000000..9bc5433f5
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiProfiler Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiProfiler Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiProfiler Icon.png.meta
new file mode 100644
index 000000000..f4157015a
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiProfiler Icon.png.meta
@@ -0,0 +1,92 @@
+fileFormatVersion: 2
+guid: 1c322d61eeb3640408ee1119729d5c21
+timeCreated: 1482252070
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 4
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 0
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Standalone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: iPhone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Android
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiRigidbody Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiRigidbody Icon.png
new file mode 100644
index 000000000..174c50672
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiRigidbody Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiRigidbody Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiRigidbody Icon.png.meta
new file mode 100644
index 000000000..8d93fea4b
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiRigidbody Icon.png.meta
@@ -0,0 +1,92 @@
+fileFormatVersion: 2
+guid: 1788ce7c914374d949486d9789c9f306
+timeCreated: 1502137043
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 4
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 0
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: -1
+ mipBias: -1
+ wrapMode: -1
+ nPOTScale: 1
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Standalone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: iPhone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Android
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiRigidbody2D Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiRigidbody2D Icon.png
new file mode 100644
index 000000000..58f8861d4
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiRigidbody2D Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiRigidbody2D Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiRigidbody2D Icon.png.meta
new file mode 100644
index 000000000..6f40dad35
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiRigidbody2D Icon.png.meta
@@ -0,0 +1,92 @@
+fileFormatVersion: 2
+guid: 21e01eb398ab24a7abb1f3b493af6b20
+timeCreated: 1517939136
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 4
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 0
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: -1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 1
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Standalone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: iPhone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Android
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiRod Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiRod Icon.png
new file mode 100644
index 000000000..b16bd502b
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiRod Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiRod Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiRod Icon.png.meta
new file mode 100644
index 000000000..edf46095c
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiRod Icon.png.meta
@@ -0,0 +1,95 @@
+fileFormatVersion: 2
+guid: 7125c3eebd3cc4f86aac51cca3ee1592
+TextureImporter:
+ fileIDToRecycleName: {}
+ externalObjects: {}
+ serializedVersion: 5
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapU: 1
+ wrapV: 1
+ wrapW: -1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - serializedVersion: 2
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ - serializedVersion: 2
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiRope Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiRope Icon.png
new file mode 100644
index 000000000..d8490871c
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiRope Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiRope Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiRope Icon.png.meta
new file mode 100644
index 000000000..a4b2cf13e
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiRope Icon.png.meta
@@ -0,0 +1,123 @@
+fileFormatVersion: 2
+guid: 7a860725829a34375a627c13703f0798
+labels:
+- ObiRope
+TextureImporter:
+ fileIDToRecycleName: {}
+ externalObjects: {}
+ serializedVersion: 9
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 1
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: -1
+ aniso: 1
+ mipBias: -100
+ wrapU: 1
+ wrapV: 1
+ wrapW: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - serializedVersion: 2
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ - serializedVersion: 2
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ - serializedVersion: 2
+ buildTarget: iPhone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ - serializedVersion: 2
+ buildTarget: Android
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ spritePackingTag:
+ pSDRemoveMatte: 0
+ pSDShowRemoveMatteOption: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiRopeChainRenderer Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiRopeChainRenderer Icon.png
new file mode 100644
index 000000000..ddd935d58
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiRopeChainRenderer Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiRopeChainRenderer Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiRopeChainRenderer Icon.png.meta
new file mode 100644
index 000000000..976d10a0f
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiRopeChainRenderer Icon.png.meta
@@ -0,0 +1,95 @@
+fileFormatVersion: 2
+guid: 1289c40ad0e7c4fb3bd738f8a3f3e068
+TextureImporter:
+ fileIDToRecycleName: {}
+ externalObjects: {}
+ serializedVersion: 5
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapU: 1
+ wrapV: 1
+ wrapW: -1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - serializedVersion: 2
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ - serializedVersion: 2
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiRopeCursor Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiRopeCursor Icon.png
new file mode 100644
index 000000000..58f15b5ec
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiRopeCursor Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiRopeCursor Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiRopeCursor Icon.png.meta
new file mode 100644
index 000000000..90a6dca20
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiRopeCursor Icon.png.meta
@@ -0,0 +1,100 @@
+fileFormatVersion: 2
+guid: 618cf36eb21e34118ac5697fe77e2c3e
+timeCreated: 1491822329
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 4
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 0
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Standalone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: iPhone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Android
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: WebGL
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiRopeExtrudedRenderer Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiRopeExtrudedRenderer Icon.png
new file mode 100644
index 000000000..2c5b674eb
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiRopeExtrudedRenderer Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiRopeExtrudedRenderer Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiRopeExtrudedRenderer Icon.png.meta
new file mode 100644
index 000000000..99f29747a
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiRopeExtrudedRenderer Icon.png.meta
@@ -0,0 +1,95 @@
+fileFormatVersion: 2
+guid: a552ed0e1c0fd47c38eeff6d60b5b115
+TextureImporter:
+ fileIDToRecycleName: {}
+ externalObjects: {}
+ serializedVersion: 5
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapU: 1
+ wrapV: 1
+ wrapW: -1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - serializedVersion: 2
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ - serializedVersion: 2
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiRopeLineRenderer Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiRopeLineRenderer Icon.png
new file mode 100644
index 000000000..91daeff17
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiRopeLineRenderer Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiRopeLineRenderer Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiRopeLineRenderer Icon.png.meta
new file mode 100644
index 000000000..1345c291f
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiRopeLineRenderer Icon.png.meta
@@ -0,0 +1,95 @@
+fileFormatVersion: 2
+guid: 905a18c273af443d6bc588b59ebd56f6
+TextureImporter:
+ fileIDToRecycleName: {}
+ externalObjects: {}
+ serializedVersion: 5
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapU: 1
+ wrapV: 1
+ wrapW: -1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - serializedVersion: 2
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ - serializedVersion: 2
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiRopeMeshRenderer Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiRopeMeshRenderer Icon.png
new file mode 100644
index 000000000..1e644b1b8
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiRopeMeshRenderer Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiRopeMeshRenderer Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiRopeMeshRenderer Icon.png.meta
new file mode 100644
index 000000000..1cae38b78
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiRopeMeshRenderer Icon.png.meta
@@ -0,0 +1,95 @@
+fileFormatVersion: 2
+guid: c5afdc6c291b44a68be8bf66702358a5
+TextureImporter:
+ fileIDToRecycleName: {}
+ externalObjects: {}
+ serializedVersion: 5
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapU: 1
+ wrapV: 1
+ wrapW: -1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - serializedVersion: 2
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ - serializedVersion: 2
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiRopeSection Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiRopeSection Icon.png
new file mode 100644
index 000000000..60ff7fb41
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiRopeSection Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiRopeSection Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiRopeSection Icon.png.meta
new file mode 100644
index 000000000..4f157733c
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiRopeSection Icon.png.meta
@@ -0,0 +1,92 @@
+fileFormatVersion: 2
+guid: fdb742a900c8d453ea5ce5027e80ad00
+timeCreated: 1464327508
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 4
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 0
+ linearTexture: 1
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Standalone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: iPhone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Android
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiShapeMatchingConstraints Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiShapeMatchingConstraints Icon.png
new file mode 100644
index 000000000..8960a702f
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiShapeMatchingConstraints Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiShapeMatchingConstraints Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiShapeMatchingConstraints Icon.png.meta
new file mode 100644
index 000000000..51d75f592
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiShapeMatchingConstraints Icon.png.meta
@@ -0,0 +1,92 @@
+fileFormatVersion: 2
+guid: a2686776a1c104bfd8868f056a5cd335
+timeCreated: 1530703943
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 4
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 0
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: -1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 1
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Standalone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: iPhone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Android
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiSkinConstraints Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiSkinConstraints Icon.png
new file mode 100644
index 000000000..20c05c30f
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiSkinConstraints Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiSkinConstraints Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiSkinConstraints Icon.png.meta
new file mode 100644
index 000000000..70912d2df
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiSkinConstraints Icon.png.meta
@@ -0,0 +1,92 @@
+fileFormatVersion: 2
+guid: e58e2a3c37c7547a8a791a56e0a1ace6
+timeCreated: 1447902275
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 4
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 0
+ linearTexture: 1
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Standalone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: iPhone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Android
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiSkinnedCloth Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiSkinnedCloth Icon.png
new file mode 100644
index 000000000..b5f4303fb
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiSkinnedCloth Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiSkinnedCloth Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiSkinnedCloth Icon.png.meta
new file mode 100644
index 000000000..fc0c584fb
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiSkinnedCloth Icon.png.meta
@@ -0,0 +1,103 @@
+fileFormatVersion: 2
+guid: 630a97028bd4d4777b63c4f8d7091317
+TextureImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 10
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: -1
+ aniso: 1
+ mipBias: -100
+ wrapU: 1
+ wrapV: 1
+ wrapW: -1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - serializedVersion: 3
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ spritePackingTag:
+ pSDRemoveMatte: 0
+ pSDShowRemoveMatteOption: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiSkinnedClothRenderer Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiSkinnedClothRenderer Icon.png
new file mode 100644
index 000000000..65edf3629
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiSkinnedClothRenderer Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiSkinnedClothRenderer Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiSkinnedClothRenderer Icon.png.meta
new file mode 100644
index 000000000..deba6ac2d
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiSkinnedClothRenderer Icon.png.meta
@@ -0,0 +1,103 @@
+fileFormatVersion: 2
+guid: b876d8c51699543acb2d919b54e8fd7a
+TextureImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 10
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: -1
+ aniso: 1
+ mipBias: -100
+ wrapU: 1
+ wrapV: 1
+ wrapW: -1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - serializedVersion: 3
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ spritePackingTag:
+ pSDRemoveMatte: 0
+ pSDShowRemoveMatteOption: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiSoftbody Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiSoftbody Icon.png
new file mode 100644
index 000000000..c7cf83310
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiSoftbody Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiSoftbody Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiSoftbody Icon.png.meta
new file mode 100644
index 000000000..776e7944e
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiSoftbody Icon.png.meta
@@ -0,0 +1,92 @@
+fileFormatVersion: 2
+guid: 61d065505e09e47bc9f211c93b8d8941
+timeCreated: 1530704861
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 4
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 0
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: -1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 1
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Standalone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: iPhone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Android
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiSoftbodySkinner Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiSoftbodySkinner Icon.png
new file mode 100644
index 000000000..2ff31e964
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiSoftbodySkinner Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiSoftbodySkinner Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiSoftbodySkinner Icon.png.meta
new file mode 100644
index 000000000..dd71bd93d
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiSoftbodySkinner Icon.png.meta
@@ -0,0 +1,117 @@
+fileFormatVersion: 2
+guid: 654315230d2e241c3a9995c1e60507d0
+TextureImporter:
+ fileIDToRecycleName: {}
+ externalObjects: {}
+ serializedVersion: 5
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapU: 1
+ wrapV: 1
+ wrapW: -1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - serializedVersion: 2
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ - serializedVersion: 2
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ - serializedVersion: 2
+ buildTarget: iPhone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ - serializedVersion: 2
+ buildTarget: Android
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiSolver Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiSolver Icon.png
new file mode 100644
index 000000000..8c681727a
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiSolver Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiSolver Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiSolver Icon.png.meta
new file mode 100644
index 000000000..1a22f8ae9
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiSolver Icon.png.meta
@@ -0,0 +1,92 @@
+fileFormatVersion: 2
+guid: 4bb17fa3a0a95413a817e60391d26010
+timeCreated: 1447901223
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 4
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 0
+ linearTexture: 1
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Standalone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: iPhone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Android
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiStitcher Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiStitcher Icon.png
new file mode 100644
index 000000000..60e88bde1
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiStitcher Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiStitcher Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiStitcher Icon.png.meta
new file mode 100644
index 000000000..68420da77
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiStitcher Icon.png.meta
@@ -0,0 +1,100 @@
+fileFormatVersion: 2
+guid: ec05a2c75bb4a4ce5a3a1baa76b4c8d5
+timeCreated: 1489589286
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 4
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 0
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Standalone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: iPhone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Android
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: WebGL
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiStretchShearConstraints Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiStretchShearConstraints Icon.png
new file mode 100644
index 000000000..5ddb1731d
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiStretchShearConstraints Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiStretchShearConstraints Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiStretchShearConstraints Icon.png.meta
new file mode 100644
index 000000000..6b1bb22fd
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiStretchShearConstraints Icon.png.meta
@@ -0,0 +1,95 @@
+fileFormatVersion: 2
+guid: b3583331769a946aab1e4c59859547b2
+TextureImporter:
+ fileIDToRecycleName: {}
+ externalObjects: {}
+ serializedVersion: 5
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapU: 1
+ wrapV: 1
+ wrapW: -1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - serializedVersion: 2
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ - serializedVersion: 2
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiTearableCloth Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiTearableCloth Icon.png
new file mode 100644
index 000000000..6e4149573
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiTearableCloth Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiTearableCloth Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiTearableCloth Icon.png.meta
new file mode 100644
index 000000000..26dc03617
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiTearableCloth Icon.png.meta
@@ -0,0 +1,103 @@
+fileFormatVersion: 2
+guid: b77f723c576a04907a94ed4c1a78f74d
+TextureImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 10
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: -1
+ aniso: 1
+ mipBias: -100
+ wrapU: 1
+ wrapV: 1
+ wrapW: -1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - serializedVersion: 3
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ spritePackingTag:
+ pSDRemoveMatte: 0
+ pSDShowRemoveMatteOption: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiTearableClothRenderer Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiTearableClothRenderer Icon.png
new file mode 100644
index 000000000..1c8b05a62
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiTearableClothRenderer Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiTearableClothRenderer Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiTearableClothRenderer Icon.png.meta
new file mode 100644
index 000000000..8f16f5bba
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiTearableClothRenderer Icon.png.meta
@@ -0,0 +1,103 @@
+fileFormatVersion: 2
+guid: 13f5839d0b38e4abdb0dc5015a82afdc
+TextureImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 10
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: -1
+ aniso: 1
+ mipBias: -100
+ wrapU: 1
+ wrapV: 1
+ wrapW: -1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - serializedVersion: 3
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ spritePackingTag:
+ pSDRemoveMatte: 0
+ pSDShowRemoveMatteOption: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiTetherConstraints Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiTetherConstraints Icon.png
new file mode 100644
index 000000000..85007acf5
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiTetherConstraints Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiTetherConstraints Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiTetherConstraints Icon.png.meta
new file mode 100644
index 000000000..689fd5a3c
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiTetherConstraints Icon.png.meta
@@ -0,0 +1,92 @@
+fileFormatVersion: 2
+guid: 45a4a839cd07d49f698be261ce71ee3c
+timeCreated: 1448331895
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 4
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 0
+ linearTexture: 1
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Standalone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: iPhone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Android
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiVoidZone Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiVoidZone Icon.png
new file mode 100644
index 000000000..595b09c88
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiVoidZone Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiVoidZone Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiVoidZone Icon.png.meta
new file mode 100644
index 000000000..083fee0f9
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiVoidZone Icon.png.meta
@@ -0,0 +1,122 @@
+fileFormatVersion: 2
+guid: eac6271e2e50d4b2dbf2dfeff9b65604
+TextureImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 11
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ vTOnly: 0
+ ignoreMasterTextureLimit: 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: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ singleChannelComponent: 0
+ flipbookRows: 1
+ flipbookColumns: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ ignorePngGamma: 0
+ applyGammaDecoding: 0
+ platformSettings:
+ - serializedVersion: 3
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Server
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ nameFileIdTable: {}
+ spritePackingTag:
+ pSDRemoveMatte: 0
+ pSDShowRemoveMatteOption: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiVolumeConstraints Icon.png b/Assets/Obi/Editor/Resources/Icons/ObiVolumeConstraints Icon.png
new file mode 100644
index 000000000..eefc8ae99
Binary files /dev/null and b/Assets/Obi/Editor/Resources/Icons/ObiVolumeConstraints Icon.png differ
diff --git a/Assets/Obi/Editor/Resources/Icons/ObiVolumeConstraints Icon.png.meta b/Assets/Obi/Editor/Resources/Icons/ObiVolumeConstraints Icon.png.meta
new file mode 100644
index 000000000..3fbf880e7
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/Icons/ObiVolumeConstraints Icon.png.meta
@@ -0,0 +1,92 @@
+fileFormatVersion: 2
+guid: d9d3ddf824bd449e5b405439ee034b12
+timeCreated: 1448433293
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 4
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 0
+ linearTexture: 1
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Standalone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: iPhone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Android
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/InvertButton.psd b/Assets/Obi/Editor/Resources/InvertButton.psd
new file mode 100644
index 000000000..599534295
Binary files /dev/null and b/Assets/Obi/Editor/Resources/InvertButton.psd differ
diff --git a/Assets/Obi/Editor/Resources/InvertButton.psd.meta b/Assets/Obi/Editor/Resources/InvertButton.psd.meta
new file mode 100644
index 000000000..766dfafc8
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/InvertButton.psd.meta
@@ -0,0 +1,59 @@
+fileFormatVersion: 2
+guid: d105dc041854c4b22b26600e565e6dc8
+timeCreated: 1478799531
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 2
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ linearTexture: 1
+ correctGamma: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 0
+ cubemapConvolution: 0
+ cubemapConvolutionSteps: 7
+ cubemapConvolutionExponent: 1.5
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ rGBM: 0
+ compressionQuality: 50
+ allowsAlphaSplitting: 0
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ buildTargetSettings: []
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/LeafButton.png b/Assets/Obi/Editor/Resources/LeafButton.png
new file mode 100644
index 000000000..c097c800b
Binary files /dev/null and b/Assets/Obi/Editor/Resources/LeafButton.png differ
diff --git a/Assets/Obi/Editor/Resources/LeafButton.png.meta b/Assets/Obi/Editor/Resources/LeafButton.png.meta
new file mode 100644
index 000000000..dafc45a7d
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/LeafButton.png.meta
@@ -0,0 +1,117 @@
+fileFormatVersion: 2
+guid: fc6329308ec7e4fa0a7134b8c1294dfd
+TextureImporter:
+ fileIDToRecycleName: {}
+ externalObjects: {}
+ serializedVersion: 5
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapU: 1
+ wrapV: 1
+ wrapW: -1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - serializedVersion: 2
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ - serializedVersion: 2
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ - serializedVersion: 2
+ buildTarget: iPhone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ - serializedVersion: 2
+ buildTarget: Android
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/MaskButton.psd b/Assets/Obi/Editor/Resources/MaskButton.psd
new file mode 100644
index 000000000..5e3c792e8
Binary files /dev/null and b/Assets/Obi/Editor/Resources/MaskButton.psd differ
diff --git a/Assets/Obi/Editor/Resources/MaskButton.psd.meta b/Assets/Obi/Editor/Resources/MaskButton.psd.meta
new file mode 100644
index 000000000..b2c8c9f9c
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/MaskButton.psd.meta
@@ -0,0 +1,59 @@
+fileFormatVersion: 2
+guid: 79009ead5070b47429cdb81d702888c1
+timeCreated: 1478802054
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 2
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ linearTexture: 1
+ correctGamma: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 0
+ cubemapConvolution: 0
+ cubemapConvolutionSteps: 7
+ cubemapConvolutionExponent: 1.5
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ rGBM: 0
+ compressionQuality: 50
+ allowsAlphaSplitting: 0
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ buildTargetSettings: []
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/OpenCloseCurve.psd b/Assets/Obi/Editor/Resources/OpenCloseCurve.psd
new file mode 100644
index 000000000..b315d257d
Binary files /dev/null and b/Assets/Obi/Editor/Resources/OpenCloseCurve.psd differ
diff --git a/Assets/Obi/Editor/Resources/OpenCloseCurve.psd.meta b/Assets/Obi/Editor/Resources/OpenCloseCurve.psd.meta
new file mode 100644
index 000000000..3ca687cf1
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/OpenCloseCurve.psd.meta
@@ -0,0 +1,59 @@
+fileFormatVersion: 2
+guid: 0dd1ebceaea0d43018983f4b506cb72b
+timeCreated: 1478799645
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 2
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ linearTexture: 1
+ correctGamma: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 0
+ cubemapConvolution: 0
+ cubemapConvolutionSteps: 7
+ cubemapConvolutionExponent: 1.5
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ rGBM: 0
+ compressionQuality: 50
+ allowsAlphaSplitting: 0
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ buildTargetSettings: []
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/OptimizeButton.psd b/Assets/Obi/Editor/Resources/OptimizeButton.psd
new file mode 100644
index 000000000..095ff613b
Binary files /dev/null and b/Assets/Obi/Editor/Resources/OptimizeButton.psd differ
diff --git a/Assets/Obi/Editor/Resources/OptimizeButton.psd.meta b/Assets/Obi/Editor/Resources/OptimizeButton.psd.meta
new file mode 100644
index 000000000..ebfc164b1
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/OptimizeButton.psd.meta
@@ -0,0 +1,127 @@
+fileFormatVersion: 2
+guid: 4343e41c062884ff4af81a34ade6d27c
+TextureImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 10
+ 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
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: -1
+ aniso: 1
+ mipBias: -100
+ wrapU: 1
+ wrapV: 1
+ wrapW: -1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - serializedVersion: 3
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: iPhone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Android
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ spritePackingTag:
+ pSDRemoveMatte: 0
+ pSDShowRemoveMatteOption: 1
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/OrientControlPoint.psd b/Assets/Obi/Editor/Resources/OrientControlPoint.psd
new file mode 100644
index 000000000..22d8bf736
Binary files /dev/null and b/Assets/Obi/Editor/Resources/OrientControlPoint.psd differ
diff --git a/Assets/Obi/Editor/Resources/OrientControlPoint.psd.meta b/Assets/Obi/Editor/Resources/OrientControlPoint.psd.meta
new file mode 100644
index 000000000..4717e3529
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/OrientControlPoint.psd.meta
@@ -0,0 +1,59 @@
+fileFormatVersion: 2
+guid: 7727f2388bff242b1bdf55ae7a1abaec
+timeCreated: 1478799645
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 2
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ linearTexture: 1
+ correctGamma: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 0
+ cubemapConvolution: 0
+ cubemapConvolutionSteps: 7
+ cubemapConvolutionExponent: 1.5
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ rGBM: 0
+ compressionQuality: 50
+ allowsAlphaSplitting: 0
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ buildTargetSettings: []
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/PaddingMaterial.mat b/Assets/Obi/Editor/Resources/PaddingMaterial.mat
new file mode 100644
index 000000000..2756d3f1c
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/PaddingMaterial.mat
@@ -0,0 +1,81 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!21 &2100000
+Material:
+ serializedVersion: 8
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_Name: PaddingMaterial
+ m_Shader: {fileID: 4800000, guid: a915cd5b44e5b45509750bc8e231c325, type: 3}
+ m_Parent: {fileID: 0}
+ m_ModifiedSerializedProperties: 0
+ m_ValidKeywords: []
+ m_InvalidKeywords: []
+ m_LightmapFlags: 5
+ m_EnableInstancingVariants: 0
+ m_DoubleSidedGI: 0
+ m_CustomRenderQueue: -1
+ stringTagMap: {}
+ disabledShaderPasses: []
+ m_LockedProperties:
+ m_SavedProperties:
+ serializedVersion: 3
+ m_TexEnvs:
+ - _BumpMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _DetailAlbedoMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _DetailMask:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _DetailNormalMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _EmissionMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _MainTex:
+ m_Texture: {fileID: 2800000, guid: 7e271617753294f4aaf5d79862c5d182, type: 3}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _MetallicGlossMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _OcclusionMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _ParallaxMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ m_Ints: []
+ m_Floats:
+ - _BumpScale: 1
+ - _Cutoff: 0.5
+ - _DetailNormalMapScale: 1
+ - _DstBlend: 0
+ - _Glossiness: 0.5
+ - _Metallic: 0
+ - _Mode: 0
+ - _OcclusionStrength: 1
+ - _Padding: 64
+ - _Parallax: 0.02
+ - _SrcBlend: 1
+ - _UVSec: 0
+ - _ZWrite: 1
+ m_Colors:
+ - _Color: {r: 1, g: 1, b: 1, a: 1}
+ - _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
+ m_BuildTextureStacks: []
+ m_AllowLocking: 1
diff --git a/Assets/Obi/Editor/Resources/PaddingMaterial.mat.meta b/Assets/Obi/Editor/Resources/PaddingMaterial.mat.meta
new file mode 100644
index 000000000..b85cec38d
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/PaddingMaterial.mat.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 8c11f7c3415044fd9b6bc7896f38f9d8
+timeCreated: 1445287098
+licenseType: Store
+NativeFormatImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/PaddingShader.shader b/Assets/Obi/Editor/Resources/PaddingShader.shader
new file mode 100644
index 000000000..afab7e2fc
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/PaddingShader.shader
@@ -0,0 +1,81 @@
+Shader "Obi/PaddingShader"
+{
+ Properties
+ {
+ _MainTex ("Texture", 2D) = "white" {}
+ _Padding ("Paddding", Int) = 32
+ }
+ SubShader
+ {
+ // No culling or depth
+ Cull Off ZWrite Off ZTest Always
+
+ Pass
+ {
+ CGPROGRAM
+ #pragma vertex vert
+ #pragma fragment frag
+
+ #include "UnityCG.cginc"
+
+ struct appdata
+ {
+ float4 vertex : POSITION;
+ float2 uv : TEXCOORD0;
+ };
+
+ struct v2f
+ {
+ float2 uv : TEXCOORD0;
+ float4 vertex : SV_POSITION;
+ };
+
+ v2f vert (appdata v)
+ {
+ v2f o;
+ o.vertex = UnityObjectToClipPos(v.vertex);
+ o.uv = v.uv;
+ return o;
+ }
+
+ sampler2D _MainTex;
+ float4 _MainTex_TexelSize;
+ int _Padding;
+ static const float2 offsets[8] = {float2(-1,0), float2(1,0), float2(0,1), float2(0,-1), float2(-1,1), float2(1,1), float2(1,-1), float2(-1,-1)};
+
+ fixed4 frag (v2f i) : SV_Target
+ {
+
+ fixed4 sample = tex2D(_MainTex, i.uv);
+
+ if (sample.a > 0)
+ return sample;
+
+ fixed4 minSample = sample;
+ float minDist = 99999999;
+
+ for (int k = 1; k < _Padding; ++k)
+ {
+ for (int j = 0; j < 8; ++j)
+ {
+ float2 offsetUV = i.uv + offsets[j] * _MainTex_TexelSize.xy * k;
+ fixed4 offsetSample = tex2Dlod(_MainTex, float4(offsetUV.xy,0,0));
+
+ if (offsetSample.a > 0)
+ {
+ float dist = length(i.uv - offsetUV);
+ if (dist < minDist)
+ {
+ minDist = dist;
+ minSample = offsetSample;
+ }
+ }
+ }
+ }
+
+ return minSample;
+ }
+ ENDCG
+ }
+ }
+}
diff --git a/Assets/Obi/Editor/Resources/PaddingShader.shader.meta b/Assets/Obi/Editor/Resources/PaddingShader.shader.meta
new file mode 100644
index 000000000..88728fdec
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/PaddingShader.shader.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: a915cd5b44e5b45509750bc8e231c325
+ShaderImporter:
+ externalObjects: {}
+ defaultTextures: []
+ nonModifiableTextures: []
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/PauseButton.psd b/Assets/Obi/Editor/Resources/PauseButton.psd
new file mode 100644
index 000000000..c22cc9cd7
Binary files /dev/null and b/Assets/Obi/Editor/Resources/PauseButton.psd differ
diff --git a/Assets/Obi/Editor/Resources/PauseButton.psd.meta b/Assets/Obi/Editor/Resources/PauseButton.psd.meta
new file mode 100644
index 000000000..6e24ea628
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/PauseButton.psd.meta
@@ -0,0 +1,57 @@
+fileFormatVersion: 2
+guid: 280ec959fe3324151be804cf285fe931
+timeCreated: 1458681991
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 2
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ linearTexture: 1
+ correctGamma: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 0
+ cubemapConvolution: 0
+ cubemapConvolutionSteps: 8
+ cubemapConvolutionExponent: 1.5
+ seamlessCubemap: 0
+ textureFormat: -3
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ rGBM: 0
+ compressionQuality: 50
+ allowsAlphaSplitting: 0
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaIsTransparency: 1
+ textureType: 2
+ buildTargetSettings: []
+ spriteSheet:
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/PencilButton.psd b/Assets/Obi/Editor/Resources/PencilButton.psd
new file mode 100644
index 000000000..b6705e585
Binary files /dev/null and b/Assets/Obi/Editor/Resources/PencilButton.psd differ
diff --git a/Assets/Obi/Editor/Resources/PencilButton.psd.meta b/Assets/Obi/Editor/Resources/PencilButton.psd.meta
new file mode 100644
index 000000000..8e30edb8d
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/PencilButton.psd.meta
@@ -0,0 +1,55 @@
+fileFormatVersion: 2
+guid: d7e21f95a6c084fd5be0c6ab594e4b78
+timeCreated: 1442227197
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 2
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ linearTexture: 1
+ correctGamma: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: .25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 0
+ cubemapConvolution: 0
+ cubemapConvolutionSteps: 8
+ cubemapConvolutionExponent: 1.5
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ rGBM: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: .5, y: .5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaIsTransparency: 1
+ textureType: 2
+ buildTargetSettings: []
+ spriteSheet:
+ sprites: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/PinButton.psd b/Assets/Obi/Editor/Resources/PinButton.psd
new file mode 100644
index 000000000..619b34e70
Binary files /dev/null and b/Assets/Obi/Editor/Resources/PinButton.psd differ
diff --git a/Assets/Obi/Editor/Resources/PinButton.psd.meta b/Assets/Obi/Editor/Resources/PinButton.psd.meta
new file mode 100644
index 000000000..0c59cff6a
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/PinButton.psd.meta
@@ -0,0 +1,59 @@
+fileFormatVersion: 2
+guid: 0da1cb5104a8b4a60b761e4d1744d8ae
+timeCreated: 1478802054
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 2
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ linearTexture: 1
+ correctGamma: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 0
+ cubemapConvolution: 0
+ cubemapConvolutionSteps: 7
+ cubemapConvolutionExponent: 1.5
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ rGBM: 0
+ compressionQuality: 50
+ allowsAlphaSplitting: 0
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ buildTargetSettings: []
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/PinTranslation.psd b/Assets/Obi/Editor/Resources/PinTranslation.psd
new file mode 100644
index 000000000..44495627a
Binary files /dev/null and b/Assets/Obi/Editor/Resources/PinTranslation.psd differ
diff --git a/Assets/Obi/Editor/Resources/PinTranslation.psd.meta b/Assets/Obi/Editor/Resources/PinTranslation.psd.meta
new file mode 100644
index 000000000..db5c7f960
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/PinTranslation.psd.meta
@@ -0,0 +1,95 @@
+fileFormatVersion: 2
+guid: 89138aa3f21fa426aa57afb83ebc3df3
+TextureImporter:
+ fileIDToRecycleName: {}
+ externalObjects: {}
+ serializedVersion: 5
+ 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
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapU: 1
+ wrapV: 1
+ wrapW: -1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - serializedVersion: 2
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ - serializedVersion: 2
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/PlayButton.psd b/Assets/Obi/Editor/Resources/PlayButton.psd
new file mode 100644
index 000000000..296a318fa
Binary files /dev/null and b/Assets/Obi/Editor/Resources/PlayButton.psd differ
diff --git a/Assets/Obi/Editor/Resources/PlayButton.psd.meta b/Assets/Obi/Editor/Resources/PlayButton.psd.meta
new file mode 100644
index 000000000..ca8974d23
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/PlayButton.psd.meta
@@ -0,0 +1,55 @@
+fileFormatVersion: 2
+guid: 0368711c00a38431db570869752031a3
+timeCreated: 1435830837
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 2
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ linearTexture: 1
+ correctGamma: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: .25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 0
+ cubemapConvolution: 0
+ cubemapConvolutionSteps: 8
+ cubemapConvolutionExponent: 1.5
+ seamlessCubemap: 0
+ textureFormat: -3
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ rGBM: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: .5, y: .5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaIsTransparency: 1
+ textureType: 2
+ buildTargetSettings: []
+ spriteSheet:
+ sprites: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/PropertyGradientMaterial.mat b/Assets/Obi/Editor/Resources/PropertyGradientMaterial.mat
new file mode 100644
index 000000000..6212a848a
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/PropertyGradientMaterial.mat
@@ -0,0 +1,80 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!21 &2100000
+Material:
+ serializedVersion: 8
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_Name: PropertyGradientMaterial
+ m_Shader: {fileID: 4800000, guid: 41dfefbc390fc41cc8e1b421c43e52f5, type: 3}
+ m_Parent: {fileID: 0}
+ m_ModifiedSerializedProperties: 0
+ m_ValidKeywords: []
+ m_InvalidKeywords: []
+ m_LightmapFlags: 5
+ m_EnableInstancingVariants: 0
+ m_DoubleSidedGI: 0
+ m_CustomRenderQueue: -1
+ stringTagMap: {}
+ disabledShaderPasses: []
+ m_LockedProperties:
+ m_SavedProperties:
+ serializedVersion: 3
+ m_TexEnvs:
+ - _BumpMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _DetailAlbedoMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _DetailMask:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _DetailNormalMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _EmissionMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _MainTex:
+ m_Texture: {fileID: 2800000, guid: 7e271617753294f4aaf5d79862c5d182, type: 3}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _MetallicGlossMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _OcclusionMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _ParallaxMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ m_Ints: []
+ m_Floats:
+ - _BumpScale: 1
+ - _Cutoff: 0.5
+ - _DetailNormalMapScale: 1
+ - _DstBlend: 0
+ - _Glossiness: 0.5
+ - _Metallic: 0
+ - _Mode: 0
+ - _OcclusionStrength: 1
+ - _Parallax: 0.02
+ - _SrcBlend: 1
+ - _UVSec: 0
+ - _ZWrite: 1
+ m_Colors:
+ - _Color: {r: 1, g: 1, b: 1, a: 1}
+ - _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
+ m_BuildTextureStacks: []
+ m_AllowLocking: 1
diff --git a/Assets/Obi/Editor/Resources/PropertyGradientMaterial.mat.meta b/Assets/Obi/Editor/Resources/PropertyGradientMaterial.mat.meta
new file mode 100644
index 000000000..ee658f291
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/PropertyGradientMaterial.mat.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: cd3a36913cf194d75a271606ea32cde5
+timeCreated: 1445287098
+licenseType: Store
+NativeFormatImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/PropertyGradientMaterial.shader b/Assets/Obi/Editor/Resources/PropertyGradientMaterial.shader
new file mode 100644
index 000000000..73c3cebd5
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/PropertyGradientMaterial.shader
@@ -0,0 +1,95 @@
+Shader "Obi/PropertyGradientMaterial" {
+
+ Properties {
+ _MainTex ("Base (RGB)", 2D) = "white" {}
+ }
+
+ SubShader {
+
+ Pass {
+
+ Offset -0.5, -0.5
+ Cull Back
+ Fog { Mode Off }
+
+ CGPROGRAM
+ #pragma vertex vert
+ #pragma fragment frag
+
+ #include "UnityCG.cginc"
+
+ struct vin{
+ float4 vertex : POSITION;
+ fixed4 color : COLOR;
+ float2 texcoord : TEXCOORD0;
+ };
+
+ struct v2f {
+ float4 pos: POSITION;
+ fixed4 color : COLOR;
+ float2 texcoord : TEXCOORD0;
+ };
+
+ sampler2D _MainTex;
+
+ v2f vert(vin v) {
+ v2f o;
+ o.pos = UnityObjectToClipPos (v.vertex);
+ o.texcoord = v.texcoord;
+ o.color = v.color;
+ return o;
+ }
+
+ fixed4 frag(v2f i) : SV_Target {
+ return i.color;
+ }
+
+ ENDCG
+ }
+
+ Pass {
+
+ Offset -1, -1
+ Cull Back
+ ZWrite Off
+ Blend SrcAlpha OneMinusSrcAlpha
+ Fog { Mode Off }
+
+ CGPROGRAM
+ #pragma vertex vert
+ #pragma fragment frag
+
+ #include "UnityCG.cginc"
+
+ struct vin{
+ float4 vertex : POSITION;
+ fixed4 color : COLOR;
+ float2 texcoord : TEXCOORD0;
+ };
+
+ struct v2f {
+ float4 pos: POSITION;
+ fixed4 color : COLOR;
+ float2 texcoord : TEXCOORD0;
+ };
+
+ sampler2D _MainTex;
+
+ v2f vert(vin v) {
+ v2f o;
+ o.pos = UnityObjectToClipPos (v.vertex);
+ o.texcoord = v.texcoord;
+ o.color = v.color;
+ return o;
+ }
+
+ fixed4 frag(v2f i) : SV_Target {
+ return i.color;
+ }
+
+ ENDCG
+ }
+
+ }
+}
+
diff --git a/Assets/Obi/Editor/Resources/PropertyGradientMaterial.shader.meta b/Assets/Obi/Editor/Resources/PropertyGradientMaterial.shader.meta
new file mode 100644
index 000000000..2a3123aa1
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/PropertyGradientMaterial.shader.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 41dfefbc390fc41cc8e1b421c43e52f5
+timeCreated: 1445287084
+licenseType: Store
+ShaderImporter:
+ defaultTextures: []
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/RadiusIndicator.psd b/Assets/Obi/Editor/Resources/RadiusIndicator.psd
new file mode 100644
index 000000000..b51421581
Binary files /dev/null and b/Assets/Obi/Editor/Resources/RadiusIndicator.psd differ
diff --git a/Assets/Obi/Editor/Resources/RadiusIndicator.psd.meta b/Assets/Obi/Editor/Resources/RadiusIndicator.psd.meta
new file mode 100644
index 000000000..7f9e818b3
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/RadiusIndicator.psd.meta
@@ -0,0 +1,59 @@
+fileFormatVersion: 2
+guid: fe4fd4da6245f48c1bcd64c8422b7b4c
+timeCreated: 1471035768
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 2
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ linearTexture: 0
+ correctGamma: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 0
+ cubemapConvolution: 0
+ cubemapConvolutionSteps: 7
+ cubemapConvolutionExponent: 1.5
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: -1
+ mipBias: -1
+ wrapMode: -1
+ nPOTScale: 1
+ lightmap: 0
+ rGBM: 0
+ compressionQuality: 50
+ allowsAlphaSplitting: 0
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: -1
+ buildTargetSettings: []
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/RecButton.psd b/Assets/Obi/Editor/Resources/RecButton.psd
new file mode 100644
index 000000000..d9cefe3da
Binary files /dev/null and b/Assets/Obi/Editor/Resources/RecButton.psd differ
diff --git a/Assets/Obi/Editor/Resources/RecButton.psd.meta b/Assets/Obi/Editor/Resources/RecButton.psd.meta
new file mode 100644
index 000000000..bbb80a953
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/RecButton.psd.meta
@@ -0,0 +1,57 @@
+fileFormatVersion: 2
+guid: d5d19ff51922e4539a782a48d6adf4e1
+timeCreated: 1458681621
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 2
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ linearTexture: 1
+ correctGamma: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 0
+ cubemapConvolution: 0
+ cubemapConvolutionSteps: 8
+ cubemapConvolutionExponent: 1.5
+ seamlessCubemap: 0
+ textureFormat: -3
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ rGBM: 0
+ compressionQuality: 50
+ allowsAlphaSplitting: 0
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaIsTransparency: 1
+ textureType: 2
+ buildTargetSettings: []
+ spriteSheet:
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/RemoveButton.psd b/Assets/Obi/Editor/Resources/RemoveButton.psd
new file mode 100644
index 000000000..d422e962a
Binary files /dev/null and b/Assets/Obi/Editor/Resources/RemoveButton.psd differ
diff --git a/Assets/Obi/Editor/Resources/RemoveButton.psd.meta b/Assets/Obi/Editor/Resources/RemoveButton.psd.meta
new file mode 100644
index 000000000..d561f91f4
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/RemoveButton.psd.meta
@@ -0,0 +1,127 @@
+fileFormatVersion: 2
+guid: 8b56a65aecb4c42dea430c75690b8a4b
+TextureImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 10
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ sRGBTexture: 1
+ linearTexture: 1
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: -1
+ aniso: 1
+ mipBias: -100
+ wrapU: 1
+ wrapV: 1
+ wrapW: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - serializedVersion: 3
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: iPhone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Android
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ spritePackingTag:
+ pSDRemoveMatte: 0
+ pSDShowRemoveMatteOption: 1
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/RemoveControlPoint.psd b/Assets/Obi/Editor/Resources/RemoveControlPoint.psd
new file mode 100644
index 000000000..acf904406
Binary files /dev/null and b/Assets/Obi/Editor/Resources/RemoveControlPoint.psd differ
diff --git a/Assets/Obi/Editor/Resources/RemoveControlPoint.psd.meta b/Assets/Obi/Editor/Resources/RemoveControlPoint.psd.meta
new file mode 100644
index 000000000..da5349a3c
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/RemoveControlPoint.psd.meta
@@ -0,0 +1,59 @@
+fileFormatVersion: 2
+guid: 7d2ee37b895e649c186b4de7004bd444
+timeCreated: 1478799645
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 2
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ linearTexture: 1
+ correctGamma: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 0
+ cubemapConvolution: 0
+ cubemapConvolutionSteps: 7
+ cubemapConvolutionExponent: 1.5
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ rGBM: 0
+ compressionQuality: 50
+ allowsAlphaSplitting: 0
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ buildTargetSettings: []
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/RemoveIcon.psd b/Assets/Obi/Editor/Resources/RemoveIcon.psd
new file mode 100644
index 000000000..48f6bb12c
Binary files /dev/null and b/Assets/Obi/Editor/Resources/RemoveIcon.psd differ
diff --git a/Assets/Obi/Editor/Resources/RemoveIcon.psd.meta b/Assets/Obi/Editor/Resources/RemoveIcon.psd.meta
new file mode 100644
index 000000000..069fee787
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/RemoveIcon.psd.meta
@@ -0,0 +1,55 @@
+fileFormatVersion: 2
+guid: 79919ab1f90654f4f811134da7164129
+timeCreated: 1440144040
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 2
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ linearTexture: 1
+ correctGamma: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: .25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 0
+ cubemapConvolution: 0
+ cubemapConvolutionSteps: 8
+ cubemapConvolutionExponent: 1.5
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ rGBM: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: .5, y: .5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaIsTransparency: 1
+ textureType: 2
+ buildTargetSettings: []
+ spriteSheet:
+ sprites: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/RestoreButton.psd b/Assets/Obi/Editor/Resources/RestoreButton.psd
new file mode 100644
index 000000000..32674d37b
Binary files /dev/null and b/Assets/Obi/Editor/Resources/RestoreButton.psd differ
diff --git a/Assets/Obi/Editor/Resources/RestoreButton.psd.meta b/Assets/Obi/Editor/Resources/RestoreButton.psd.meta
new file mode 100644
index 000000000..6086b8367
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/RestoreButton.psd.meta
@@ -0,0 +1,127 @@
+fileFormatVersion: 2
+guid: 3b85a7a10acb94ba093952ee1cb68420
+TextureImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 10
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ sRGBTexture: 1
+ linearTexture: 1
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: -1
+ aniso: 1
+ mipBias: -100
+ wrapU: 1
+ wrapV: 1
+ wrapW: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - serializedVersion: 3
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: iPhone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Android
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ spritePackingTag:
+ pSDRemoveMatte: 0
+ pSDShowRemoveMatteOption: 1
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/RewindButton.psd b/Assets/Obi/Editor/Resources/RewindButton.psd
new file mode 100644
index 000000000..73b9694e2
Binary files /dev/null and b/Assets/Obi/Editor/Resources/RewindButton.psd differ
diff --git a/Assets/Obi/Editor/Resources/RewindButton.psd.meta b/Assets/Obi/Editor/Resources/RewindButton.psd.meta
new file mode 100644
index 000000000..5664ebb14
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/RewindButton.psd.meta
@@ -0,0 +1,55 @@
+fileFormatVersion: 2
+guid: 3276c82f639db4e1393d50621591b623
+timeCreated: 1435831272
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 2
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ linearTexture: 1
+ correctGamma: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: .25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 0
+ cubemapConvolution: 0
+ cubemapConvolutionSteps: 8
+ cubemapConvolutionExponent: 1.5
+ seamlessCubemap: 0
+ textureFormat: -3
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ rGBM: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: .5, y: .5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaIsTransparency: 1
+ textureType: 2
+ buildTargetSettings: []
+ spriteSheet:
+ sprites: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/RotateControlPoint.psd b/Assets/Obi/Editor/Resources/RotateControlPoint.psd
new file mode 100644
index 000000000..d21b4f3f6
Binary files /dev/null and b/Assets/Obi/Editor/Resources/RotateControlPoint.psd differ
diff --git a/Assets/Obi/Editor/Resources/RotateControlPoint.psd.meta b/Assets/Obi/Editor/Resources/RotateControlPoint.psd.meta
new file mode 100644
index 000000000..dc569cf07
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/RotateControlPoint.psd.meta
@@ -0,0 +1,59 @@
+fileFormatVersion: 2
+guid: f33b6dcf4f7f946909841f077b4f1aa3
+timeCreated: 1478799645
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 2
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ linearTexture: 1
+ correctGamma: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 0
+ cubemapConvolution: 0
+ cubemapConvolutionSteps: 7
+ cubemapConvolutionExponent: 1.5
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ rGBM: 0
+ compressionQuality: 50
+ allowsAlphaSplitting: 0
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ buildTargetSettings: []
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/ScaleControlPoint.psd b/Assets/Obi/Editor/Resources/ScaleControlPoint.psd
new file mode 100644
index 000000000..cb52d7268
Binary files /dev/null and b/Assets/Obi/Editor/Resources/ScaleControlPoint.psd differ
diff --git a/Assets/Obi/Editor/Resources/ScaleControlPoint.psd.meta b/Assets/Obi/Editor/Resources/ScaleControlPoint.psd.meta
new file mode 100644
index 000000000..2f4c39cc3
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/ScaleControlPoint.psd.meta
@@ -0,0 +1,55 @@
+fileFormatVersion: 2
+guid: d13fb15ff13b2475b8585a693545eb0c
+timeCreated: 1442227197
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 2
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ linearTexture: 1
+ correctGamma: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: .25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 0
+ cubemapConvolution: 0
+ cubemapConvolutionSteps: 8
+ cubemapConvolutionExponent: 1.5
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ rGBM: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: .5, y: .5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaIsTransparency: 1
+ textureType: 2
+ buildTargetSettings: []
+ spriteSheet:
+ sprites: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/SelectIcon.psd b/Assets/Obi/Editor/Resources/SelectIcon.psd
new file mode 100644
index 000000000..719afb5ce
Binary files /dev/null and b/Assets/Obi/Editor/Resources/SelectIcon.psd differ
diff --git a/Assets/Obi/Editor/Resources/SelectIcon.psd.meta b/Assets/Obi/Editor/Resources/SelectIcon.psd.meta
new file mode 100644
index 000000000..82a5cbeba
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/SelectIcon.psd.meta
@@ -0,0 +1,55 @@
+fileFormatVersion: 2
+guid: d10211a5e35be4a1f97e25a7f78b84fd
+timeCreated: 1442227627
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 2
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ linearTexture: 1
+ correctGamma: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: .25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 0
+ cubemapConvolution: 0
+ cubemapConvolutionSteps: 8
+ cubemapConvolutionExponent: 1.5
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ rGBM: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: .5, y: .5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaIsTransparency: 1
+ textureType: 2
+ buildTargetSettings: []
+ spriteSheet:
+ sprites: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/SelectedWorld_bck.psd b/Assets/Obi/Editor/Resources/SelectedWorld_bck.psd
new file mode 100644
index 000000000..4d590d62b
Binary files /dev/null and b/Assets/Obi/Editor/Resources/SelectedWorld_bck.psd differ
diff --git a/Assets/Obi/Editor/Resources/SelectedWorld_bck.psd.meta b/Assets/Obi/Editor/Resources/SelectedWorld_bck.psd.meta
new file mode 100644
index 000000000..716381932
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/SelectedWorld_bck.psd.meta
@@ -0,0 +1,55 @@
+fileFormatVersion: 2
+guid: 01844e929694344c79f595973dd49a4a
+timeCreated: 1440124004
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 2
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ linearTexture: 1
+ correctGamma: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: .25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 0
+ cubemapConvolution: 0
+ cubemapConvolutionSteps: 8
+ cubemapConvolutionExponent: 1.5
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ rGBM: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: .5, y: .5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaIsTransparency: 1
+ textureType: 2
+ buildTargetSettings: []
+ spriteSheet:
+ sprites: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/SeparatorLine.psd b/Assets/Obi/Editor/Resources/SeparatorLine.psd
new file mode 100644
index 000000000..b3234dc52
Binary files /dev/null and b/Assets/Obi/Editor/Resources/SeparatorLine.psd differ
diff --git a/Assets/Obi/Editor/Resources/SeparatorLine.psd.meta b/Assets/Obi/Editor/Resources/SeparatorLine.psd.meta
new file mode 100644
index 000000000..e939ca9ff
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/SeparatorLine.psd.meta
@@ -0,0 +1,59 @@
+fileFormatVersion: 2
+guid: ce2eac6e238e5450991af12bb7d594c1
+timeCreated: 1442217896
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 2
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ linearTexture: 1
+ correctGamma: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 0
+ cubemapConvolution: 0
+ cubemapConvolutionSteps: 8
+ cubemapConvolutionExponent: 1.5
+ seamlessCubemap: 0
+ textureFormat: -2
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ rGBM: 0
+ compressionQuality: 50
+ allowsAlphaSplitting: 0
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ buildTargetSettings: []
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/ShowTangentHandles.psd b/Assets/Obi/Editor/Resources/ShowTangentHandles.psd
new file mode 100644
index 000000000..80bc18574
Binary files /dev/null and b/Assets/Obi/Editor/Resources/ShowTangentHandles.psd differ
diff --git a/Assets/Obi/Editor/Resources/ShowTangentHandles.psd.meta b/Assets/Obi/Editor/Resources/ShowTangentHandles.psd.meta
new file mode 100644
index 000000000..91403965a
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/ShowTangentHandles.psd.meta
@@ -0,0 +1,59 @@
+fileFormatVersion: 2
+guid: 913a0a12dbef54c7ca939f3dc86dc19f
+timeCreated: 1478799645
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 2
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ linearTexture: 1
+ correctGamma: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 0
+ cubemapConvolution: 0
+ cubemapConvolutionSteps: 7
+ cubemapConvolutionExponent: 1.5
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ rGBM: 0
+ compressionQuality: 50
+ allowsAlphaSplitting: 0
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ buildTargetSettings: []
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/ShowThicknessHandles.psd b/Assets/Obi/Editor/Resources/ShowThicknessHandles.psd
new file mode 100644
index 000000000..717c329e3
Binary files /dev/null and b/Assets/Obi/Editor/Resources/ShowThicknessHandles.psd differ
diff --git a/Assets/Obi/Editor/Resources/ShowThicknessHandles.psd.meta b/Assets/Obi/Editor/Resources/ShowThicknessHandles.psd.meta
new file mode 100644
index 000000000..bb3842d3c
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/ShowThicknessHandles.psd.meta
@@ -0,0 +1,59 @@
+fileFormatVersion: 2
+guid: 71c2b8c0a1d5b4908a4764a8beed8da6
+timeCreated: 1478799645
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 2
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ linearTexture: 1
+ correctGamma: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 0
+ cubemapConvolution: 0
+ cubemapConvolutionSteps: 7
+ cubemapConvolutionExponent: 1.5
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ rGBM: 0
+ compressionQuality: 50
+ allowsAlphaSplitting: 0
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ buildTargetSettings: []
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/SmoothButton.psd b/Assets/Obi/Editor/Resources/SmoothButton.psd
new file mode 100644
index 000000000..bce383f62
Binary files /dev/null and b/Assets/Obi/Editor/Resources/SmoothButton.psd differ
diff --git a/Assets/Obi/Editor/Resources/SmoothButton.psd.meta b/Assets/Obi/Editor/Resources/SmoothButton.psd.meta
new file mode 100644
index 000000000..66ef2bacd
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/SmoothButton.psd.meta
@@ -0,0 +1,59 @@
+fileFormatVersion: 2
+guid: 51e011fff1bad43078a63a1c71b11965
+timeCreated: 1478802054
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 2
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ linearTexture: 1
+ correctGamma: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 0
+ cubemapConvolution: 0
+ cubemapConvolutionSteps: 7
+ cubemapConvolutionExponent: 1.5
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ rGBM: 0
+ compressionQuality: 50
+ allowsAlphaSplitting: 0
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ buildTargetSettings: []
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/StepButton.psd b/Assets/Obi/Editor/Resources/StepButton.psd
new file mode 100644
index 000000000..049bfe911
Binary files /dev/null and b/Assets/Obi/Editor/Resources/StepButton.psd differ
diff --git a/Assets/Obi/Editor/Resources/StepButton.psd.meta b/Assets/Obi/Editor/Resources/StepButton.psd.meta
new file mode 100644
index 000000000..b6b08a1a4
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/StepButton.psd.meta
@@ -0,0 +1,55 @@
+fileFormatVersion: 2
+guid: 3a4a9652d5a3546a494c48ad14e4b492
+timeCreated: 1435831067
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 2
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ linearTexture: 1
+ correctGamma: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: .25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 0
+ cubemapConvolution: 0
+ cubemapConvolutionSteps: 8
+ cubemapConvolutionExponent: 1.5
+ seamlessCubemap: 0
+ textureFormat: -3
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ rGBM: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: .5, y: .5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaIsTransparency: 1
+ textureType: 2
+ buildTargetSettings: []
+ spriteSheet:
+ sprites: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/StopButton.psd b/Assets/Obi/Editor/Resources/StopButton.psd
new file mode 100644
index 000000000..d601f8691
Binary files /dev/null and b/Assets/Obi/Editor/Resources/StopButton.psd differ
diff --git a/Assets/Obi/Editor/Resources/StopButton.psd.meta b/Assets/Obi/Editor/Resources/StopButton.psd.meta
new file mode 100644
index 000000000..e07230971
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/StopButton.psd.meta
@@ -0,0 +1,55 @@
+fileFormatVersion: 2
+guid: d7f73785945ac441d9d2c7e6aea7c600
+timeCreated: 1435831194
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 2
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ linearTexture: 1
+ correctGamma: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: .25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 0
+ cubemapConvolution: 0
+ cubemapConvolutionSteps: 8
+ cubemapConvolutionExponent: 1.5
+ seamlessCubemap: 0
+ textureFormat: -3
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ rGBM: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: .5, y: .5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaIsTransparency: 1
+ textureType: 2
+ buildTargetSettings: []
+ spriteSheet:
+ sprites: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/StopRecButton.psd b/Assets/Obi/Editor/Resources/StopRecButton.psd
new file mode 100644
index 000000000..2c3b63162
Binary files /dev/null and b/Assets/Obi/Editor/Resources/StopRecButton.psd differ
diff --git a/Assets/Obi/Editor/Resources/StopRecButton.psd.meta b/Assets/Obi/Editor/Resources/StopRecButton.psd.meta
new file mode 100644
index 000000000..defe78474
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/StopRecButton.psd.meta
@@ -0,0 +1,57 @@
+fileFormatVersion: 2
+guid: e4c64699292b6490aac7e91c52abdc2c
+timeCreated: 1458681626
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 2
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ linearTexture: 1
+ correctGamma: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 0
+ cubemapConvolution: 0
+ cubemapConvolutionSteps: 8
+ cubemapConvolutionExponent: 1.5
+ seamlessCubemap: 0
+ textureFormat: -3
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ rGBM: 0
+ compressionQuality: 50
+ allowsAlphaSplitting: 0
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaIsTransparency: 1
+ textureType: 2
+ buildTargetSettings: []
+ spriteSheet:
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/TextureIcon.psd b/Assets/Obi/Editor/Resources/TextureIcon.psd
new file mode 100644
index 000000000..e72917621
Binary files /dev/null and b/Assets/Obi/Editor/Resources/TextureIcon.psd differ
diff --git a/Assets/Obi/Editor/Resources/TextureIcon.psd.meta b/Assets/Obi/Editor/Resources/TextureIcon.psd.meta
new file mode 100644
index 000000000..0821ef678
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/TextureIcon.psd.meta
@@ -0,0 +1,98 @@
+fileFormatVersion: 2
+guid: 931c48569a82e4dae84d4702bf6da199
+TextureImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 11
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ sRGBTexture: 1
+ linearTexture: 1
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ vTOnly: 0
+ ignoreMasterTextureLimit: 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: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ singleChannelComponent: 0
+ flipbookRows: 1
+ flipbookColumns: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ ignorePngGamma: 0
+ applyGammaDecoding: 1
+ platformSettings:
+ - serializedVersion: 3
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ nameFileIdTable: {}
+ spritePackingTag:
+ pSDRemoveMatte: 1
+ pSDShowRemoveMatteOption: 1
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/ToggleableGroupBg.psd b/Assets/Obi/Editor/Resources/ToggleableGroupBg.psd
new file mode 100644
index 000000000..5a186ceba
Binary files /dev/null and b/Assets/Obi/Editor/Resources/ToggleableGroupBg.psd differ
diff --git a/Assets/Obi/Editor/Resources/ToggleableGroupBg.psd.meta b/Assets/Obi/Editor/Resources/ToggleableGroupBg.psd.meta
new file mode 100644
index 000000000..caa2025b8
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/ToggleableGroupBg.psd.meta
@@ -0,0 +1,59 @@
+fileFormatVersion: 2
+guid: f08eeaacb82744bf498511aef9a6c649
+timeCreated: 1442217896
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 2
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ linearTexture: 1
+ correctGamma: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 0
+ cubemapConvolution: 0
+ cubemapConvolutionSteps: 8
+ cubemapConvolutionExponent: 1.5
+ seamlessCubemap: 0
+ textureFormat: -2
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ rGBM: 0
+ compressionQuality: 50
+ allowsAlphaSplitting: 0
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ buildTargetSettings: []
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/TopologyBorders.shader b/Assets/Obi/Editor/Resources/TopologyBorders.shader
new file mode 100644
index 000000000..923f6aa42
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/TopologyBorders.shader
@@ -0,0 +1,54 @@
+// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
+
+
+Shader "Obi/TopologyBorders" {
+Properties {
+ _Color ("Main Color", Color) = (1,1,1,1)
+}
+
+SubShader {
+ Tags { "RenderType"="Opaque" }
+ LOD 100
+
+ Pass {
+
+ ZWrite Off
+ ZTest always
+ Cull Off
+ Fog { Mode Off }
+
+ CGPROGRAM
+ #pragma vertex vert
+ #pragma fragment frag
+ #pragma multi_compile_fog
+
+ #include "UnityCG.cginc"
+
+ struct appdata_t {
+ float4 vertex : POSITION;
+ };
+
+ struct v2f {
+ float4 vertex : SV_POSITION;
+ };
+
+ fixed4 _Color;
+
+ v2f vert (appdata_t v)
+ {
+ v2f o;
+ o.vertex = UnityObjectToClipPos(v.vertex);
+ return o;
+ }
+
+ fixed4 frag (v2f i) : COLOR
+ {
+ fixed4 col = _Color;
+ UNITY_OPAQUE_ALPHA(col.a);
+ return col;
+ }
+ ENDCG
+ }
+}
+
+}
diff --git a/Assets/Obi/Editor/Resources/TopologyBorders.shader.meta b/Assets/Obi/Editor/Resources/TopologyBorders.shader.meta
new file mode 100644
index 000000000..584e28856
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/TopologyBorders.shader.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 973221b91492243759c6f0871607f830
+timeCreated: 1459228603
+licenseType: Store
+ShaderImporter:
+ defaultTextures: []
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/TopologyPreview.mat b/Assets/Obi/Editor/Resources/TopologyPreview.mat
new file mode 100644
index 000000000..56d3d68c6
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/TopologyPreview.mat
@@ -0,0 +1,85 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!21 &2100000
+Material:
+ serializedVersion: 8
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_Name: TopologyPreview
+ m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0}
+ m_Parent: {fileID: 0}
+ m_ModifiedSerializedProperties: 0
+ m_ValidKeywords:
+ - _EMISSION
+ m_InvalidKeywords: []
+ m_LightmapFlags: 1
+ m_EnableInstancingVariants: 0
+ m_DoubleSidedGI: 0
+ m_CustomRenderQueue: -1
+ stringTagMap: {}
+ disabledShaderPasses: []
+ m_LockedProperties:
+ m_SavedProperties:
+ serializedVersion: 3
+ m_TexEnvs:
+ - _BumpMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _DetailAlbedoMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _DetailMask:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _DetailNormalMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _EmissionMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _MainTex:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _MetallicGlossMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _OcclusionMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _ParallaxMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ m_Ints: []
+ m_Floats:
+ - _BumpScale: 1
+ - _Cutoff: 0.5
+ - _DetailNormalMapScale: 1
+ - _DstBlend: 0
+ - _GlossMapScale: 1
+ - _Glossiness: 0.5
+ - _GlossyReflections: 1
+ - _Metallic: 0
+ - _Mode: 0
+ - _OcclusionStrength: 1
+ - _Parallax: 0.02
+ - _SmoothnessTextureChannel: 0
+ - _SpecularHighlights: 1
+ - _SrcBlend: 1
+ - _UVSec: 0
+ - _ZWrite: 1
+ m_Colors:
+ - _Color: {r: 0.49803922, g: 0.49803922, b: 0.49803922, a: 1}
+ - _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
+ m_BuildTextureStacks: []
+ m_AllowLocking: 1
diff --git a/Assets/Obi/Editor/Resources/TopologyPreview.mat.meta b/Assets/Obi/Editor/Resources/TopologyPreview.mat.meta
new file mode 100644
index 000000000..dfc815966
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/TopologyPreview.mat.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 62dd1825e029c4d6291eb024124c520a
+timeCreated: 1446008685
+licenseType: Store
+NativeFormatImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/TopologyPreviewBorder.mat b/Assets/Obi/Editor/Resources/TopologyPreviewBorder.mat
new file mode 100644
index 000000000..55b02f6e3
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/TopologyPreviewBorder.mat
@@ -0,0 +1,80 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!21 &2100000
+Material:
+ serializedVersion: 8
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_Name: TopologyPreviewBorder
+ m_Shader: {fileID: 10755, guid: 0000000000000000f000000000000000, type: 0}
+ m_Parent: {fileID: 0}
+ m_ModifiedSerializedProperties: 0
+ m_ValidKeywords: []
+ m_InvalidKeywords: []
+ m_LightmapFlags: 5
+ m_EnableInstancingVariants: 0
+ m_DoubleSidedGI: 0
+ m_CustomRenderQueue: -1
+ stringTagMap: {}
+ disabledShaderPasses: []
+ m_LockedProperties:
+ m_SavedProperties:
+ serializedVersion: 3
+ m_TexEnvs:
+ - _BumpMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _DetailAlbedoMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _DetailMask:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _DetailNormalMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _EmissionMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _MainTex:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _MetallicGlossMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _OcclusionMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _ParallaxMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ m_Ints: []
+ m_Floats:
+ - _BumpScale: 1
+ - _Cutoff: 0.5
+ - _DetailNormalMapScale: 1
+ - _DstBlend: 0
+ - _Glossiness: 0.5
+ - _Metallic: 0
+ - _Mode: 0
+ - _OcclusionStrength: 1
+ - _Parallax: 0.02
+ - _SrcBlend: 1
+ - _UVSec: 0
+ - _ZWrite: 1
+ m_Colors:
+ - _Color: {r: 1, g: 0, b: 0, a: 1}
+ - _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
+ m_BuildTextureStacks: []
+ m_AllowLocking: 1
diff --git a/Assets/Obi/Editor/Resources/TopologyPreviewBorder.mat.meta b/Assets/Obi/Editor/Resources/TopologyPreviewBorder.mat.meta
new file mode 100644
index 000000000..32b303a9f
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/TopologyPreviewBorder.mat.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 83b0018e22cec4650b2f51e7b1cae99f
+timeCreated: 1446016691
+licenseType: Store
+NativeFormatImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/TranslateControlPoint.psd b/Assets/Obi/Editor/Resources/TranslateControlPoint.psd
new file mode 100644
index 000000000..2c3ee0c71
Binary files /dev/null and b/Assets/Obi/Editor/Resources/TranslateControlPoint.psd differ
diff --git a/Assets/Obi/Editor/Resources/TranslateControlPoint.psd.meta b/Assets/Obi/Editor/Resources/TranslateControlPoint.psd.meta
new file mode 100644
index 000000000..d0e97e746
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/TranslateControlPoint.psd.meta
@@ -0,0 +1,116 @@
+fileFormatVersion: 2
+guid: b759d71b63d26412f9bdf4730efccd87
+TextureImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 11
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ sRGBTexture: 1
+ linearTexture: 1
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: 1
+ aniso: 1
+ mipBias: 0
+ wrapU: 1
+ wrapV: 1
+ wrapW: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ applyGammaDecoding: 1
+ platformSettings:
+ - serializedVersion: 3
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: iPhone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ spritePackingTag:
+ pSDRemoveMatte: 1
+ pSDShowRemoveMatteOption: 1
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/TrunkButton.png b/Assets/Obi/Editor/Resources/TrunkButton.png
new file mode 100644
index 000000000..6ed2d0f3e
Binary files /dev/null and b/Assets/Obi/Editor/Resources/TrunkButton.png differ
diff --git a/Assets/Obi/Editor/Resources/TrunkButton.png.meta b/Assets/Obi/Editor/Resources/TrunkButton.png.meta
new file mode 100644
index 000000000..abc62b327
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/TrunkButton.png.meta
@@ -0,0 +1,117 @@
+fileFormatVersion: 2
+guid: ca503dc9534e0488b98fc100f4fd1d5d
+TextureImporter:
+ fileIDToRecycleName: {}
+ externalObjects: {}
+ serializedVersion: 5
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapU: 1
+ wrapV: 1
+ wrapW: -1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - serializedVersion: 2
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ - serializedVersion: 2
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ - serializedVersion: 2
+ buildTarget: iPhone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ - serializedVersion: 2
+ buildTarget: Android
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/UVSpaceColor.shader b/Assets/Obi/Editor/Resources/UVSpaceColor.shader
new file mode 100644
index 000000000..c8b2ac3eb
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/UVSpaceColor.shader
@@ -0,0 +1,47 @@
+Shader "Obi/UVSpaceColor"
+{
+ SubShader
+ {
+ Tags { "RenderType"="Opaque" }
+ LOD 100
+
+ Pass
+ {
+ CGPROGRAM
+ #pragma vertex vert
+ #pragma fragment frag
+
+ #include "UnityCG.cginc"
+
+ struct appdata
+ {
+ float4 vertex : POSITION;
+ fixed4 color : COLOR;
+ float2 uv : TEXCOORD0;
+ };
+
+ struct v2f
+ {
+ float2 uv : TEXCOORD0;
+ fixed4 color : COLOR;
+ float4 vertex : SV_POSITION;
+ };
+
+ v2f vert (appdata v)
+ {
+ v2f o;
+ o.uv = v.uv;
+ o.vertex = float4(v.uv.xy,0,1);
+ o.vertex = UnityObjectToClipPos(float4(v.uv,0,1));
+ o.color = v.color;
+ return o;
+ }
+
+ fixed4 frag (v2f i) : SV_Target
+ {
+ return i.color;
+ }
+ ENDCG
+ }
+ }
+}
diff --git a/Assets/Obi/Editor/Resources/UVSpaceColor.shader.meta b/Assets/Obi/Editor/Resources/UVSpaceColor.shader.meta
new file mode 100644
index 000000000..367df23aa
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/UVSpaceColor.shader.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 459ae7c4c81724f20b6810647d2dbd3d
+ShaderImporter:
+ externalObjects: {}
+ defaultTextures: []
+ nonModifiableTextures: []
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/UVSpaceColorMaterial.mat b/Assets/Obi/Editor/Resources/UVSpaceColorMaterial.mat
new file mode 100644
index 000000000..5519f761d
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/UVSpaceColorMaterial.mat
@@ -0,0 +1,80 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!21 &2100000
+Material:
+ serializedVersion: 8
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_Name: UVSpaceColorMaterial
+ m_Shader: {fileID: 4800000, guid: 459ae7c4c81724f20b6810647d2dbd3d, type: 3}
+ m_Parent: {fileID: 0}
+ m_ModifiedSerializedProperties: 0
+ m_ValidKeywords: []
+ m_InvalidKeywords: []
+ m_LightmapFlags: 5
+ m_EnableInstancingVariants: 0
+ m_DoubleSidedGI: 0
+ m_CustomRenderQueue: -1
+ stringTagMap: {}
+ disabledShaderPasses: []
+ m_LockedProperties:
+ m_SavedProperties:
+ serializedVersion: 3
+ m_TexEnvs:
+ - _BumpMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _DetailAlbedoMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _DetailMask:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _DetailNormalMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _EmissionMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _MainTex:
+ m_Texture: {fileID: 2800000, guid: 7e271617753294f4aaf5d79862c5d182, type: 3}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _MetallicGlossMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _OcclusionMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _ParallaxMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ m_Ints: []
+ m_Floats:
+ - _BumpScale: 1
+ - _Cutoff: 0.5
+ - _DetailNormalMapScale: 1
+ - _DstBlend: 0
+ - _Glossiness: 0.5
+ - _Metallic: 0
+ - _Mode: 0
+ - _OcclusionStrength: 1
+ - _Parallax: 0.02
+ - _SrcBlend: 1
+ - _UVSec: 0
+ - _ZWrite: 1
+ m_Colors:
+ - _Color: {r: 1, g: 1, b: 1, a: 1}
+ - _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
+ m_BuildTextureStacks: []
+ m_AllowLocking: 1
diff --git a/Assets/Obi/Editor/Resources/UVSpaceColorMaterial.mat.meta b/Assets/Obi/Editor/Resources/UVSpaceColorMaterial.mat.meta
new file mode 100644
index 000000000..66a8487b8
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/UVSpaceColorMaterial.mat.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 8d64d32033a9145218d8c42c02e53b63
+timeCreated: 1445287098
+licenseType: Store
+NativeFormatImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/UnpinButton.psd b/Assets/Obi/Editor/Resources/UnpinButton.psd
new file mode 100644
index 000000000..46e280c5a
Binary files /dev/null and b/Assets/Obi/Editor/Resources/UnpinButton.psd differ
diff --git a/Assets/Obi/Editor/Resources/UnpinButton.psd.meta b/Assets/Obi/Editor/Resources/UnpinButton.psd.meta
new file mode 100644
index 000000000..a96c6e380
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/UnpinButton.psd.meta
@@ -0,0 +1,59 @@
+fileFormatVersion: 2
+guid: 546d0fbcbc7794babadce998d53cc471
+timeCreated: 1478802054
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 2
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ linearTexture: 1
+ correctGamma: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 0
+ cubemapConvolution: 0
+ cubemapConvolutionSteps: 7
+ cubemapConvolutionExponent: 1.5
+ seamlessCubemap: 0
+ textureFormat: -1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ rGBM: 0
+ compressionQuality: 50
+ allowsAlphaSplitting: 0
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ buildTargetSettings: []
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/VoxelMaterial.mat b/Assets/Obi/Editor/Resources/VoxelMaterial.mat
new file mode 100644
index 000000000..48145edff
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/VoxelMaterial.mat
@@ -0,0 +1,83 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!21 &2100000
+Material:
+ serializedVersion: 8
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_Name: VoxelMaterial
+ m_Shader: {fileID: 4800000, guid: a5455d2f5ab50497d8642726d64b9cd5, type: 3}
+ m_Parent: {fileID: 0}
+ m_ModifiedSerializedProperties: 0
+ m_ValidKeywords: []
+ m_InvalidKeywords: []
+ m_LightmapFlags: 5
+ m_EnableInstancingVariants: 0
+ m_DoubleSidedGI: 0
+ m_CustomRenderQueue: -1
+ stringTagMap: {}
+ disabledShaderPasses: []
+ m_LockedProperties:
+ m_SavedProperties:
+ serializedVersion: 3
+ m_TexEnvs:
+ - _BumpMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _DetailAlbedoMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _DetailMask:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _DetailNormalMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _EmissionMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _MainTex:
+ m_Texture: {fileID: 2800000, guid: 7e271617753294f4aaf5d79862c5d182, type: 3}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _MetallicGlossMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _OcclusionMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _ParallaxMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ m_Ints: []
+ m_Floats:
+ - _BumpScale: 1
+ - _Cutoff: 0.5
+ - _DetailNormalMapScale: 1
+ - _DstBlend: 0
+ - _Glossiness: 0.5
+ - _Metallic: 0
+ - _Mode: 0
+ - _OcclusionStrength: 1
+ - _Parallax: 0.02
+ - _Size: 0.95
+ - _SrcBlend: 1
+ - _UVSec: 0
+ - _ZWrite: 1
+ m_Colors:
+ - _Color: {r: 1, g: 1, b: 1, a: 1}
+ - _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
+ - _InsideColor: {r: 0.8627451, g: 0.8627451, b: 0.8627451, a: 1}
+ - _OutsideColor: {r: 0.3529412, g: 0.3529412, b: 0.3529412, a: 1}
+ m_BuildTextureStacks: []
+ m_AllowLocking: 1
diff --git a/Assets/Obi/Editor/Resources/VoxelMaterial.mat.meta b/Assets/Obi/Editor/Resources/VoxelMaterial.mat.meta
new file mode 100644
index 000000000..344e7c4d4
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/VoxelMaterial.mat.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 130b71128e55b4a3f9a4dceca6667bf9
+timeCreated: 1445287098
+licenseType: Store
+NativeFormatImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/VoxelMaterial.shader b/Assets/Obi/Editor/Resources/VoxelMaterial.shader
new file mode 100644
index 000000000..55d1a82b4
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/VoxelMaterial.shader
@@ -0,0 +1,63 @@
+Shader "Obi/VoxelMaterial" {
+
+ Properties {
+ _MainTex ("Base (RGB)", 2D) = "white" {}
+ _Size("Square size",Float) = 0.95
+ _InsideColor("Inside color",Color) = (1,1,1,1)
+ _OutsideColor("Outside color",Color) = (0,0,0,1)
+ }
+
+ SubShader {
+
+ Pass {
+
+ Cull Back
+ Fog { Mode Off }
+
+ CGPROGRAM
+ #pragma vertex vert
+ #pragma fragment frag
+
+ #include "UnityCG.cginc"
+
+ struct vin{
+ float4 vertex : POSITION;
+ fixed4 color : COLOR;
+ float2 texcoord : TEXCOORD0;
+ };
+
+ struct v2f {
+ float4 pos: POSITION;
+ fixed4 color : COLOR;
+ float2 texcoord : TEXCOORD0;
+ };
+
+ sampler2D _MainTex;
+ float _Size;
+ fixed4 _InsideColor;
+ fixed4 _OutsideColor;
+
+ v2f vert(vin v) {
+ v2f o;
+ o.pos = UnityObjectToClipPos (v.vertex);
+ o.texcoord = v.texcoord;
+ o.color = v.color;
+ return o;
+ }
+
+ fixed4 frag(v2f i) : SV_Target {
+
+ float2 centered = i.texcoord * 2 - 1;
+ float square = max(abs(centered.x), abs(centered.y)) - 0.05f/(2.0*1.4142);
+ float width = fwidth(square);
+ float alpha = smoothstep(_Size - width, _Size, square);
+
+ return lerp(_InsideColor,_OutsideColor,alpha);
+ }
+
+ ENDCG
+ }
+
+ }
+}
+
diff --git a/Assets/Obi/Editor/Resources/VoxelMaterial.shader.meta b/Assets/Obi/Editor/Resources/VoxelMaterial.shader.meta
new file mode 100644
index 000000000..d5800a63c
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/VoxelMaterial.shader.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: a5455d2f5ab50497d8642726d64b9cd5
+timeCreated: 1445287084
+licenseType: Store
+ShaderImporter:
+ defaultTextures: []
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/Resources/obi_editor_logo.png b/Assets/Obi/Editor/Resources/obi_editor_logo.png
new file mode 100644
index 000000000..51c3c88b6
Binary files /dev/null and b/Assets/Obi/Editor/Resources/obi_editor_logo.png differ
diff --git a/Assets/Obi/Editor/Resources/obi_editor_logo.png.meta b/Assets/Obi/Editor/Resources/obi_editor_logo.png.meta
new file mode 100644
index 000000000..464725b23
--- /dev/null
+++ b/Assets/Obi/Editor/Resources/obi_editor_logo.png.meta
@@ -0,0 +1,59 @@
+fileFormatVersion: 2
+guid: 8eeefc8d5c2ab4e0582a93f719bcd31a
+timeCreated: 1471538194
+licenseType: Store
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 2
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ linearTexture: 1
+ correctGamma: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 0
+ cubemapConvolution: 0
+ cubemapConvolutionSteps: 7
+ cubemapConvolutionExponent: 1.5
+ seamlessCubemap: 0
+ textureFormat: -3
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: -1
+ aniso: 1
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ rGBM: 0
+ compressionQuality: 50
+ allowsAlphaSplitting: 0
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ buildTargetSettings: []
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/RopeAndRod.meta b/Assets/Obi/Editor/RopeAndRod.meta
new file mode 100644
index 000000000..2f90f428d
--- /dev/null
+++ b/Assets/Obi/Editor/RopeAndRod.meta
@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: 00c9b99ffa90a4646b360dcad1ea0b84
+labels:
+- ObiRope
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/RopeAndRod/Blueprints.meta b/Assets/Obi/Editor/RopeAndRod/Blueprints.meta
new file mode 100644
index 000000000..2d99c2303
--- /dev/null
+++ b/Assets/Obi/Editor/RopeAndRod/Blueprints.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 16f13a837c41b437a87aa83162abd677
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/RopeAndRod/Blueprints/ObiRopeBaseBlueprintEditor.cs b/Assets/Obi/Editor/RopeAndRod/Blueprints/ObiRopeBaseBlueprintEditor.cs
new file mode 100644
index 000000000..ff5c98e18
--- /dev/null
+++ b/Assets/Obi/Editor/RopeAndRod/Blueprints/ObiRopeBaseBlueprintEditor.cs
@@ -0,0 +1,58 @@
+using UnityEngine;
+using UnityEditor;
+using System.Collections.Generic;
+using System.Collections;
+using System;
+
+namespace Obi
+{
+ [CustomEditor(typeof(ObiRopeBlueprintBase), true)]
+ public class ObiRopeBaseBlueprintEditor : ObiActorBlueprintEditor
+ {
+
+ public override void OnEnable()
+ {
+ base.OnEnable();
+ Undo.undoRedoPerformed += UndoRedoPerformed;
+ }
+
+ public override void OnDisable()
+ {
+ base.OnDisable();
+ Undo.undoRedoPerformed -= UndoRedoPerformed;
+ }
+
+ void UndoRedoPerformed()
+ {
+ // Re-generate the blueprint after undo/redo.
+ if (blueprint != null)
+ blueprint.GenerateImmediate();
+ }
+
+ public override void OnInspectorGUI()
+ {
+
+ serializedObject.UpdateIfRequiredOrScript();
+
+ EditorGUILayout.BeginVertical(EditorStyles.inspectorDefaultMargins);
+ Editor.DrawPropertiesExcluding(serializedObject, "m_Script");
+
+ EditorGUILayout.EndVertical();
+
+ if (GUI.changed)
+ {
+ serializedObject.ApplyModifiedProperties();
+
+ // Re-generate the blueprint if any element has been changed.
+ if (blueprint != null)
+ blueprint.GenerateImmediate();
+
+ // There might be blueprint editing operations that have no undo entry, so do this to
+ // ensure changes are serialized to disk by Unity.
+ EditorUtility.SetDirty(this);
+ }
+ }
+ }
+
+
+}
diff --git a/Assets/Obi/Editor/RopeAndRod/Blueprints/ObiRopeBaseBlueprintEditor.cs.meta b/Assets/Obi/Editor/RopeAndRod/Blueprints/ObiRopeBaseBlueprintEditor.cs.meta
new file mode 100644
index 000000000..c5925c274
--- /dev/null
+++ b/Assets/Obi/Editor/RopeAndRod/Blueprints/ObiRopeBaseBlueprintEditor.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 87efff4816bdd4fa4bda69ca33516658
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/RopeAndRod/BonePropertyCurveDrawer.cs b/Assets/Obi/Editor/RopeAndRod/BonePropertyCurveDrawer.cs
new file mode 100644
index 000000000..8d240cdec
--- /dev/null
+++ b/Assets/Obi/Editor/RopeAndRod/BonePropertyCurveDrawer.cs
@@ -0,0 +1,29 @@
+using UnityEngine;
+using UnityEditor;
+
+namespace Obi
+{
+ [CustomPropertyDrawer(typeof(ObiBone.BonePropertyCurve))]
+ public class BonePropertyCurveDrawer : PropertyDrawer
+ {
+ public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
+ {
+ EditorGUI.BeginProperty(position, label, property);
+
+ float curveFieldWidth = (position.width - EditorGUIUtility.labelWidth) * 0.5f;
+
+ var multRect = new Rect(position.x, position.y, position.width - curveFieldWidth, position.height);
+ EditorGUI.PropertyField(multRect, property.FindPropertyRelative("multiplier"), label);
+
+ var indent = EditorGUI.indentLevel;
+ EditorGUI.indentLevel = 0;
+
+ var curveRect = new Rect(position.x + position.width - curveFieldWidth + 3, position.y, curveFieldWidth - 3, position.height);
+ EditorGUI.CurveField(curveRect, property.FindPropertyRelative("curve"), Color.green, new Rect(0, 0, 1, 1), GUIContent.none);
+
+ EditorGUI.indentLevel = indent;
+
+ EditorGUI.EndProperty();
+ }
+ }
+}
diff --git a/Assets/Obi/Editor/RopeAndRod/BonePropertyCurveDrawer.cs.meta b/Assets/Obi/Editor/RopeAndRod/BonePropertyCurveDrawer.cs.meta
new file mode 100644
index 000000000..3fb84d07b
--- /dev/null
+++ b/Assets/Obi/Editor/RopeAndRod/BonePropertyCurveDrawer.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: b78a1342294ee4644a9a0d6a247d3604
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/RopeAndRod/IgnoredBoneDrawer.cs b/Assets/Obi/Editor/RopeAndRod/IgnoredBoneDrawer.cs
new file mode 100644
index 000000000..2ba8fccf2
--- /dev/null
+++ b/Assets/Obi/Editor/RopeAndRod/IgnoredBoneDrawer.cs
@@ -0,0 +1,30 @@
+using UnityEngine;
+using UnityEditor;
+
+namespace Obi
+{
+ [CustomPropertyDrawer(typeof(ObiBone.IgnoredBone))]
+ public class IgnoredBoneDrawer : PropertyDrawer
+ {
+ public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
+ {
+ EditorGUI.BeginProperty(position, label, property);
+
+ GUI.Box(EditorGUI.IndentedRect(position), GUIContent.none, ObiEditorUtils.GetToggleablePropertyGroupStyle());
+
+ var rect = new Rect(position.x + 4, position.y + EditorGUIUtility.standardVerticalSpacing, position.width - 8, EditorGUIUtility.singleLineHeight);
+ EditorGUI.PropertyField(rect, property.FindPropertyRelative("bone"), label);
+
+ rect.position = new Vector2(rect.position.x, rect.position.y + EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing);
+ EditorGUI.PropertyField(rect, property.FindPropertyRelative("ignoreChildren"));
+
+ EditorGUI.EndProperty();
+ }
+
+ public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
+ {
+ int lineCount = 2;
+ return EditorGUIUtility.singleLineHeight * lineCount + EditorGUIUtility.standardVerticalSpacing * (lineCount + 1);
+ }
+ }
+}
diff --git a/Assets/Obi/Editor/RopeAndRod/IgnoredBoneDrawer.cs.meta b/Assets/Obi/Editor/RopeAndRod/IgnoredBoneDrawer.cs.meta
new file mode 100644
index 000000000..f1da00749
--- /dev/null
+++ b/Assets/Obi/Editor/RopeAndRod/IgnoredBoneDrawer.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: f9e4bd0b2f9544e039fef4cd5d95232f
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/RopeAndRod/ObiBoneEditor.cs b/Assets/Obi/Editor/RopeAndRod/ObiBoneEditor.cs
new file mode 100644
index 000000000..0aedd61e2
--- /dev/null
+++ b/Assets/Obi/Editor/RopeAndRod/ObiBoneEditor.cs
@@ -0,0 +1,225 @@
+using UnityEditor;
+using UnityEngine;
+
+namespace Obi
+{
+
+ [CustomEditor(typeof(ObiBone))]
+ public class ObiBoneEditor : Editor
+ {
+ ObiBone bone;
+
+ SerializedProperty collisionMaterial;
+ SerializedProperty selfCollisions;
+ SerializedProperty surfaceCollisions;
+
+ SerializedProperty mass;
+ SerializedProperty rotationalMass;
+ SerializedProperty radius;
+
+ SerializedProperty skinConstraintsEnabled;
+ SerializedProperty skinCompliance;
+ SerializedProperty skinRadius;
+
+ SerializedProperty stretchShearConstraintsEnabled;
+ SerializedProperty stretchCompliance;
+ SerializedProperty shear1Compliance;
+ SerializedProperty shear2Compliance;
+
+ SerializedProperty bendTwistConstraintsEnabled;
+ SerializedProperty torsionCompliance;
+ SerializedProperty bend1Compliance;
+ SerializedProperty bend2Compliance;
+ SerializedProperty plasticYield;
+ SerializedProperty plasticCreep;
+
+ SerializedProperty aerodynamicsEnabled;
+ SerializedProperty drag;
+ SerializedProperty lift;
+
+ SerializedProperty fixRoot;
+ SerializedProperty stretchBones;
+ SerializedProperty ignored;
+
+ public void OnEnable()
+ {
+ bone = (ObiBone)target;
+
+ fixRoot = serializedObject.FindProperty("fixRoot");
+ stretchBones = serializedObject.FindProperty("stretchBones");
+ ignored = serializedObject.FindProperty("ignored");
+
+ collisionMaterial = serializedObject.FindProperty("m_CollisionMaterial");
+ selfCollisions = serializedObject.FindProperty("m_SelfCollisions");
+ surfaceCollisions = serializedObject.FindProperty("m_SurfaceCollisions");
+
+ mass = serializedObject.FindProperty("_mass");
+ rotationalMass = serializedObject.FindProperty("_rotationalMass");
+ radius = serializedObject.FindProperty("_radius");
+
+ skinConstraintsEnabled = serializedObject.FindProperty("_skinConstraintsEnabled");
+ skinRadius = serializedObject.FindProperty("_skinRadius");
+ skinCompliance = serializedObject.FindProperty("_skinCompliance");
+
+ stretchShearConstraintsEnabled = serializedObject.FindProperty("_stretchShearConstraintsEnabled");
+ stretchCompliance = serializedObject.FindProperty("_stretchCompliance");
+ shear1Compliance = serializedObject.FindProperty("_shear1Compliance");
+ shear2Compliance = serializedObject.FindProperty("_shear2Compliance");
+
+ bendTwistConstraintsEnabled = serializedObject.FindProperty("_bendTwistConstraintsEnabled");
+ torsionCompliance = serializedObject.FindProperty("_torsionCompliance");
+ bend1Compliance = serializedObject.FindProperty("_bend1Compliance");
+ bend2Compliance = serializedObject.FindProperty("_bend2Compliance");
+ plasticYield = serializedObject.FindProperty("_plasticYield");
+ plasticCreep = serializedObject.FindProperty("_plasticCreep");
+
+ aerodynamicsEnabled = serializedObject.FindProperty("_aerodynamicsEnabled");
+ drag = serializedObject.FindProperty("_drag");
+ lift = serializedObject.FindProperty("_lift");
+ }
+
+ public void OnDisable()
+ {
+ Tools.hidden = false;
+ }
+
+ public override void OnInspectorGUI()
+ {
+ serializedObject.UpdateIfRequiredOrScript();
+
+ EditorGUILayout.LabelField("Bones", EditorStyles.boldLabel);
+ EditorGUILayout.PropertyField(fixRoot);
+ EditorGUILayout.PropertyField(stretchBones);
+ EditorGUILayout.PropertyField(ignored);
+ EditorGUILayout.Space();
+
+ EditorGUILayout.LabelField("Collisions", EditorStyles.boldLabel);
+ EditorGUILayout.PropertyField(collisionMaterial, new GUIContent("Collision material"));
+ EditorGUI.BeginChangeCheck();
+ var newCategory = EditorGUILayout.Popup("Collision category", ObiUtils.GetCategoryFromFilter(bone.Filter), ObiUtils.categoryNames);
+ if (EditorGUI.EndChangeCheck())
+ {
+ foreach (ObiBone t in targets)
+ {
+ Undo.RecordObject(t, "Set collision category");
+ t.Filter = ObiUtils.MakeFilter(ObiUtils.GetMaskFromFilter(t.Filter), newCategory);
+ PrefabUtility.RecordPrefabInstancePropertyModifications(t);
+ }
+ }
+
+ EditorGUI.BeginChangeCheck();
+ var newMask = EditorGUILayout.MaskField("Collides with", ObiUtils.GetMaskFromFilter(bone.Filter), ObiUtils.categoryNames);
+ if (EditorGUI.EndChangeCheck())
+ {
+ foreach (ObiBone t in targets)
+ {
+ Undo.RecordObject(t, "Set collision mask");
+ t.Filter = ObiUtils.MakeFilter(newMask, ObiUtils.GetCategoryFromFilter(t.Filter));
+ PrefabUtility.RecordPrefabInstancePropertyModifications(t);
+ }
+ }
+ EditorGUILayout.PropertyField(selfCollisions, new GUIContent("Self collisions"));
+ EditorGUILayout.PropertyField(surfaceCollisions, new GUIContent("Surface-based collisions"));
+ EditorGUILayout.Space();
+
+ ObiEditorUtils.DoPropertyGroup(new GUIContent("Particles"),
+ () => {
+ EditorGUILayout.PropertyField(mass);
+ EditorGUILayout.PropertyField(rotationalMass);
+ EditorGUILayout.PropertyField(radius);
+ });
+
+ ObiEditorUtils.DoToggleablePropertyGroup(skinConstraintsEnabled, new GUIContent("Skin Constraints", Resources.Load("Icons/ObiSkinConstraints Icon")),
+ () => {
+ EditorGUILayout.PropertyField(skinRadius, new GUIContent("Skin radius"));
+ EditorGUILayout.PropertyField(skinCompliance, new GUIContent("Skin compliance"));
+ });
+
+ ObiEditorUtils.DoToggleablePropertyGroup(stretchShearConstraintsEnabled, new GUIContent("Stretch & Shear Constraints", Resources.Load("Icons/ObiStretchShearConstraints Icon")),
+ () => {
+ EditorGUILayout.PropertyField(stretchCompliance, new GUIContent("Stretch compliance"));
+ EditorGUILayout.PropertyField(shear1Compliance, new GUIContent("Shear compliance X"));
+ EditorGUILayout.PropertyField(shear2Compliance, new GUIContent("Shear compliance Y"));
+ });
+
+ ObiEditorUtils.DoToggleablePropertyGroup(bendTwistConstraintsEnabled, new GUIContent("Bend & Twist Constraints", Resources.Load("Icons/ObiBendTwistConstraints Icon")),
+ () => {
+ EditorGUILayout.PropertyField(torsionCompliance, new GUIContent("Torsion compliance"));
+ EditorGUILayout.PropertyField(bend1Compliance, new GUIContent("Bend compliance X"));
+ EditorGUILayout.PropertyField(bend2Compliance, new GUIContent("Bend compliance Y"));
+ EditorGUILayout.PropertyField(plasticYield, new GUIContent("Plastic yield"));
+ EditorGUILayout.PropertyField(plasticCreep, new GUIContent("Plastic creep"));
+ });
+
+ ObiEditorUtils.DoToggleablePropertyGroup(aerodynamicsEnabled, new GUIContent("Aerodynamics", Resources.Load("Icons/ObiAerodynamicConstraints Icon")),
+ () => {
+ EditorGUILayout.PropertyField(drag, new GUIContent("Drag"));
+ EditorGUILayout.PropertyField(lift, new GUIContent("Lift"));
+ });
+
+ if (GUI.changed)
+ serializedObject.ApplyModifiedProperties();
+
+ }
+
+
+ [DrawGizmo(GizmoType.Selected)]
+ private static void DrawGizmos(ObiBone actor, GizmoType gizmoType)
+ {
+ if (actor.boneBlueprint != null && actor.isLoaded)
+ {
+ var color = new Color(1, 1, 1, 0.5f);
+ var upColor = new Color(0, 1, 0, 1);
+
+ for (int i = 0; i < actor.boneBlueprint.parentIndices.Count; ++i)
+ {
+ int parent = actor.boneBlueprint.parentIndices[i];
+ if (parent >= 0)
+ {
+ var index = actor.solverIndices[parent];
+ var nextIndex = actor.solverIndices[i];
+
+ var pos = actor.GetParticlePosition(index);
+ var npos = actor.GetParticlePosition(nextIndex);
+ var or = actor.GetParticleOrientation(index);
+ var nor = actor.GetParticleOrientation(nextIndex);
+ var rad = actor.GetParticleMaxRadius(index);
+ var nrad = actor.GetParticleMaxRadius(nextIndex);
+
+ var up = pos + or * Vector3.up * rad;
+ var down = pos + or * Vector3.down * rad;
+ var left = pos + or * Vector3.left * rad;
+ var right = pos + or * Vector3.right * rad;
+
+ var nup = npos + nor * Vector3.up * nrad;
+ var ndown = npos + nor * Vector3.down * nrad;
+ var nleft = npos + nor * Vector3.left * nrad;
+ var nright = npos + nor * Vector3.right * nrad;
+
+ Handles.color = upColor;
+ Handles.DrawLine(up, nup);
+
+ Handles.color = color;
+ Handles.DrawLine(down, ndown);
+ Handles.DrawLine(left, nleft);
+ Handles.DrawLine(right, nright);
+ Handles.DrawWireDisc(npos, nor * Vector3.forward, nrad);
+ }
+ }
+ if (actor.particleCount > 0)
+ {
+ var index = actor.solverIndices[0];
+ var pos = actor.GetParticlePosition(index);
+ var or = actor.GetParticleOrientation(index);
+ var rad = actor.GetParticleMaxRadius(index);
+
+ Handles.DrawWireDisc(pos, or * Vector3.forward, rad);
+ }
+ }
+ }
+
+ }
+
+}
+
+
diff --git a/Assets/Obi/Editor/RopeAndRod/ObiBoneEditor.cs.meta b/Assets/Obi/Editor/RopeAndRod/ObiBoneEditor.cs.meta
new file mode 100644
index 000000000..2f33c8d3c
--- /dev/null
+++ b/Assets/Obi/Editor/RopeAndRod/ObiBoneEditor.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 1f25827f322514e1bb93fd309cd801bf
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/RopeAndRod/ObiDraggableIcon.cs b/Assets/Obi/Editor/RopeAndRod/ObiDraggableIcon.cs
new file mode 100644
index 000000000..1d41c3b92
--- /dev/null
+++ b/Assets/Obi/Editor/RopeAndRod/ObiDraggableIcon.cs
@@ -0,0 +1,73 @@
+using UnityEngine;
+using UnityEditor;
+using System.Collections;
+
+namespace Obi{
+public class ObiDraggableIcon {
+
+ public static bool Draw(bool selected, int id, ref Vector2 position, Color color){
+
+ Texture texture = Resources.Load("Dot");
+
+ int controlID = GUIUtility.GetControlID(id,FocusType.Passive);
+
+ // select vertex on mouse click:
+ switch (Event.current.GetTypeForControl(controlID)){
+
+ case EventType.MouseDown:
+
+ Rect area = new Rect (position.x-5, position.y-5, 10, 10);
+
+ if (area.Contains(Event.current.mousePosition))
+ {
+ selected = true;
+ GUIUtility.hotControl = controlID;
+ Event.current.Use();
+ }else if ((Event.current.modifiers & EventModifiers.Shift) == 0 && (Event.current.modifiers & EventModifiers.Command) == 0){
+
+ selected = false;
+
+ }
+
+ break;
+
+ case EventType.MouseDrag:
+
+ if (GUIUtility.hotControl == controlID){
+
+ position = Event.current.mousePosition;
+ GUI.changed = true;
+
+ Event.current.Use();
+
+ }
+
+ break;
+
+ case EventType.MouseUp:
+
+ if (GUIUtility.hotControl == controlID){
+
+ GUIUtility.hotControl = 0;
+ Event.current.Use();
+
+ }
+
+ break;
+
+ case EventType.Repaint:
+
+ Color oldColor = GUI.color;
+ GUI.color = selected ? ObiEditorSettings.GetOrCreateSettings().selectedParticleColor : ObiEditorSettings.GetOrCreateSettings().particleColor;
+ Rect rect = new Rect (position.x-2, position.y-2, 4, 4);
+ GUI.Box(rect,EditorGUIUtility.whiteTexture);
+ GUI.color = oldColor;
+
+ break;
+
+ }
+
+ return selected;
+ }
+}
+}
diff --git a/Assets/Obi/Editor/RopeAndRod/ObiDraggableIcon.cs.meta b/Assets/Obi/Editor/RopeAndRod/ObiDraggableIcon.cs.meta
new file mode 100644
index 000000000..d2449d026
--- /dev/null
+++ b/Assets/Obi/Editor/RopeAndRod/ObiDraggableIcon.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: c736a38cd50af4bccbd08b83993abbdb
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/RopeAndRod/ObiPathEditor.cs b/Assets/Obi/Editor/RopeAndRod/ObiPathEditor.cs
new file mode 100644
index 000000000..7056a44e6
--- /dev/null
+++ b/Assets/Obi/Editor/RopeAndRod/ObiPathEditor.cs
@@ -0,0 +1,1241 @@
+using UnityEngine;
+using UnityEditor;
+using UnityEditor.EditorTools;
+using System;
+using UnityEditor.Overlays;
+using UnityEngine.UIElements;
+
+namespace Obi
+{
+ [EditorTool("Obi Path Editor Tool",typeof(ObiRopeBase))]
+ public class ObiPathEditor : EditorTool
+ {
+
+ [Overlay(typeof(SceneView), "Obi Path Editor", "Obi Path Editor", "Obi Path Editor", true)]
+ [Icon("Assets/Obi/Editor/Resources/EditCurves.psd")]
+ class PathEditorOverlay : Overlay, ITransientOverlay
+ {
+ public static ObiPathEditor editor;
+
+ public override VisualElement CreatePanelContent()
+ {
+ var root = new VisualElement();
+ root.Add(new IMGUIContainer(editor.DrawToolPanel));
+ return root;
+ }
+
+ // Use the visible property to hide or show this instance from within the class.
+ public bool visible
+ {
+ get
+ {
+ return ToolManager.activeToolType == typeof(ObiPathEditor);
+ }
+ }
+ }
+
+ enum PathEditorTool
+ {
+ TranslatePoints,
+ RotatePoints,
+ ScalePoints,
+ OrientPoints,
+ InsertPoints,
+ RemovePoints
+ }
+
+ ObiPath path;
+
+ Quaternion prevRot = Quaternion.identity;
+ Vector3 prevScale = Vector3.one;
+
+ PathEditorTool currentTool = PathEditorTool.TranslatePoints;
+ bool showTangentHandles = true;
+ bool showThicknessHandles = true;
+
+ public bool needsRepaint = false;
+
+ protected bool[] selectedStatus;
+ protected int lastSelected = 0;
+ protected int selectedCount = 0;
+ protected Vector3 selectionAverage;
+ protected bool useOrientation = false;
+
+ protected static Color handleColor = new Color(1, 0.55f, 0.1f);
+ protected GUIContent m_IconContent;
+
+ public override GUIContent toolbarIcon
+ {
+ get
+ {
+ if (m_IconContent == null)
+ {
+ m_IconContent = new GUIContent()
+ {
+ image = Resources.Load("EditCurves"),
+ text = "Obi Path Editor Tool",
+ tooltip = "Obi Path Editor Tool"
+ };
+ }
+ return m_IconContent;
+ }
+ }
+
+ ObiRopeBlueprintBase blueprint
+ {
+ get { return (target as ObiRopeBase).sharedBlueprint as ObiRopeBlueprintBase; }
+ }
+
+ public void OnEnable()
+ {
+ this.useOrientation = target is ObiRod;
+ selectedStatus = new bool[0];
+ PathEditorOverlay.editor = this;
+ }
+
+ public void ResizeCPArrays()
+ {
+ Array.Resize(ref selectedStatus, path.ControlPointCount);
+ }
+
+ public override void OnToolGUI(EditorWindow window)
+ {
+ needsRepaint = false;
+
+ float thicknessScale = blueprint.thickness;
+ this.path = (target as ObiRopeBase).path;
+ var matrix = (target as ObiRopeBase).transform.localToWorldMatrix;
+
+ ResizeCPArrays();
+
+ HandleUtility.AddDefaultControl(GUIUtility.GetControlID("PathEditor".GetHashCode(), FocusType.Passive));
+
+ Matrix4x4 prevMatrix = Handles.matrix;
+ Handles.matrix = matrix;
+
+ // Draw control points:
+ Handles.color = handleColor;
+ for (int i = 0; i < path.ControlPointCount; ++i)
+ {
+ needsRepaint |= DrawControlPoint(i);
+ }
+
+ // Count selected and calculate average position:
+ selectionAverage = GetControlPointAverage(out lastSelected, out selectedCount);
+
+ // Draw cp tool handles:
+ needsRepaint |= SplineCPTools(matrix);
+
+ if (showThicknessHandles)
+ needsRepaint |= DoThicknessHandles(thicknessScale);
+
+ // Control point selection handle:
+ needsRepaint |= ObiPathHandles.SplineCPSelector(path, selectedStatus);
+
+ Handles.matrix = prevMatrix;
+
+ // During edit mode, allow to add/remove control points.
+ if (currentTool == PathEditorTool.InsertPoints)
+ AddControlPointsMode(matrix);
+
+ if (currentTool == PathEditorTool.RemovePoints)
+ RemoveControlPointsMode(matrix);
+
+ if (needsRepaint)
+ window.Repaint();
+
+ }
+
+ private void AddControlPointsMode(Matrix4x4 matrix)
+ {
+
+ float mu = ScreenPointToCurveMu(path, Event.current.mousePosition, matrix);
+
+ Vector3 pointOnSpline = matrix.MultiplyPoint3x4(path.points.GetPositionAtMu(path.Closed, mu));
+
+ float size = HandleUtility.GetHandleSize(pointOnSpline) * 0.12f;
+
+ Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);
+ Handles.color = Color.green;
+ Handles.DrawDottedLine(pointOnSpline, ray.origin, 4);
+ Handles.SphereHandleCap(0, pointOnSpline, Quaternion.identity, size, Event.current.type);
+
+
+ if (Event.current.type == EventType.MouseDown && Event.current.modifiers == EventModifiers.None)
+ {
+ Undo.RecordObject(blueprint, "Add");
+
+ int newIndex = path.InsertControlPoint(mu);
+ if (newIndex >= 0)
+ {
+ ResizeCPArrays();
+ for (int i = 0; i < selectedStatus.Length; ++i)
+ selectedStatus[i] = false;
+ selectedStatus[newIndex] = true;
+ }
+
+ path.FlushEvents();
+ Event.current.Use();
+ }
+
+ // Repaint the scene, so that the add control point helpers are updated every frame.
+ SceneView.RepaintAll();
+
+ }
+
+ private void RemoveControlPointsMode(Matrix4x4 matrix)
+ {
+
+ float mu = ScreenPointToCurveMu(path, Event.current.mousePosition, matrix);
+
+ Vector3 pointOnSpline = matrix.MultiplyPoint3x4(path.points.GetPositionAtMu(path.Closed, mu));
+
+ float size = HandleUtility.GetHandleSize(pointOnSpline) * 0.12f;
+
+ Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);
+
+ Handles.color = Color.red;
+ Handles.DrawDottedLine(pointOnSpline, ray.origin, 4);
+
+ int index = path.GetClosestControlPointIndex(mu);
+ Handles.SphereHandleCap(0, matrix.MultiplyPoint3x4(path.points[index].position), Quaternion.identity, size, Event.current.type);
+
+ if (Event.current.type == EventType.MouseDown && Event.current.modifiers == EventModifiers.None && index >= 0 && path.ControlPointCount > 2)
+ {
+ Undo.RecordObject(blueprint, "Remove");
+
+ path.RemoveControlPoint(index);
+ ResizeCPArrays();
+ for (int i = 0; i < selectedStatus.Length; ++i)
+ selectedStatus[i] = false;
+
+ path.FlushEvents();
+ Event.current.Use();
+ }
+
+ // Repaint the scene, so that the add control point helpers are updated every frame.
+ SceneView.RepaintAll();
+
+ }
+
+ protected bool DrawControlPoint(int i)
+ {
+ bool repaint = false;
+ var wp = path.points[i];
+ float size = HandleUtility.GetHandleSize(wp.position) * 0.04f;
+
+ if (selectedStatus[i] && showTangentHandles)
+ {
+
+ Handles.color = handleColor;
+
+ if (!(i == 0 && !path.Closed))
+ {
+ Vector3 tangentPosition = wp.inTangentEndpoint;
+
+ if (Event.current.type == EventType.Repaint)
+ Handles.DrawDottedLine(tangentPosition, wp.position, 2);
+
+ EditorGUI.BeginChangeCheck();
+ Handles.DotHandleCap(0, tangentPosition, Quaternion.identity, size, Event.current.type);
+ Vector3 newTangent = Handles.PositionHandle(tangentPosition, Quaternion.identity);
+ if (EditorGUI.EndChangeCheck())
+ {
+ Undo.RecordObject(blueprint, "Modify tangent");
+ wp.SetInTangentEndpoint(newTangent);
+ path.points[i] = wp;
+ path.FlushEvents();
+ repaint = true;
+ }
+ }
+
+ if (!(i == path.ControlPointCount - 1 && !path.Closed))
+ {
+ Vector3 tangentPosition = wp.outTangentEndpoint;
+
+ if (Event.current.type == EventType.Repaint)
+ Handles.DrawDottedLine(tangentPosition, wp.position, 2);
+
+ EditorGUI.BeginChangeCheck();
+ Handles.DotHandleCap(0, tangentPosition, Quaternion.identity, size, Event.current.type);
+ Vector3 newTangent = Handles.PositionHandle(tangentPosition, Quaternion.identity);
+ if (EditorGUI.EndChangeCheck())
+ {
+ Undo.RecordObject(blueprint, "Modify tangent");
+ wp.SetOutTangentEndpoint(newTangent);
+ path.points[i] = wp;
+ path.FlushEvents();
+ repaint = true;
+ }
+ }
+ }
+
+ if (Event.current.type == EventType.Repaint)
+ {
+
+ Handles.color = selectedStatus[i] ? handleColor : Color.white;
+ Vector3 pos = wp.position;
+
+ if (currentTool == PathEditorTool.OrientPoints)
+ {
+ Handles.ArrowHandleCap(0, pos, Quaternion.LookRotation(path.normals[i]), HandleUtility.GetHandleSize(pos), EventType.Repaint);
+ }
+
+ Handles.SphereHandleCap(0, pos, Quaternion.identity, size * 3, EventType.Repaint);
+
+ }
+ return repaint;
+ }
+
+ protected Vector3 GetControlPointAverage(out int lastSelected, out int selectedCount)
+ {
+
+ lastSelected = -1;
+ selectedCount = 0;
+ Vector3 averagePos = Vector3.zero;
+
+ // Find center of all selected control points:
+ for (int i = 0; i < path.ControlPointCount; ++i)
+ {
+ if (selectedStatus[i])
+ {
+
+ averagePos += path.points[i].position;
+ selectedCount++;
+ lastSelected = i;
+
+ }
+ }
+ if (selectedCount > 0)
+ averagePos /= selectedCount;
+ return averagePos;
+
+ }
+
+ protected bool SplineCPTools(Matrix4x4 matrix)
+ {
+ bool repaint = false;
+
+ // Calculate handle rotation, for local or world pivot modes.
+ Quaternion handleRotation = Tools.pivotRotation == PivotRotation.Local ? Quaternion.identity : Quaternion.Inverse(matrix.rotation);
+
+ // Reset initial handle rotation/orientation after using a tool:
+ if (GUIUtility.hotControl == 0)
+ {
+
+ prevRot = handleRotation;
+ prevScale = Vector3.one;
+
+ if (selectedCount == 1 && Tools.pivotRotation == PivotRotation.Local && currentTool == PathEditorTool.OrientPoints)
+ {
+ //prevRot = Quaternion.LookRotation(GetNormal(lastSelected));
+ }
+ }
+
+ // Transform handles:
+ if (selectedCount > 0)
+ {
+
+ if (useOrientation && currentTool == PathEditorTool.OrientPoints)
+ {
+ repaint |= OrientTool(selectionAverage, handleRotation);
+ }
+ else
+ {
+ switch (currentTool)
+ {
+ case PathEditorTool.TranslatePoints:
+ {
+ repaint |= MoveTool(selectionAverage, handleRotation);
+ }
+ break;
+
+ case PathEditorTool.ScalePoints:
+ {
+ repaint |= ScaleTool(selectionAverage, handleRotation);
+ }
+ break;
+
+ case PathEditorTool.RotatePoints:
+ {
+ repaint |= RotateTool(selectionAverage, handleRotation);
+ }
+ break;
+ }
+ }
+ }
+ return repaint;
+ }
+
+ protected bool MoveTool(Vector3 handlePosition, Quaternion handleRotation)
+ {
+
+ EditorGUI.BeginChangeCheck();
+ Vector3 newPos = Handles.PositionHandle(handlePosition, handleRotation);
+ if (EditorGUI.EndChangeCheck())
+ {
+
+ Undo.RecordObject(blueprint, "Move control point");
+
+ Vector3 delta = newPos - handlePosition;
+
+ for (int i = 0; i < path.ControlPointCount; ++i)
+ {
+ if (selectedStatus[i])
+ {
+ var wp = path.points[i];
+ wp.Transform(delta, Quaternion.identity, Vector3.one);
+ path.points[i] = wp;
+ }
+ }
+
+ path.FlushEvents();
+ return true;
+ }
+ return false;
+ }
+
+ protected bool ScaleTool(Vector3 handlePosition, Quaternion handleRotation)
+ {
+
+ EditorGUI.BeginChangeCheck();
+ Vector3 scale = Handles.ScaleHandle(prevScale, handlePosition, handleRotation, HandleUtility.GetHandleSize(handlePosition));
+
+ if (EditorGUI.EndChangeCheck())
+ {
+
+ Vector3 deltaScale = new Vector3(scale.x / prevScale.x, scale.y / prevScale.y, scale.z / prevScale.z);
+ prevScale = scale;
+
+ Undo.RecordObject(blueprint, "Scale control point");
+
+ if (Tools.pivotMode == PivotMode.Center && selectedCount > 1)
+ {
+ for (int i = 0; i < path.ControlPointCount; ++i)
+ {
+ if (selectedStatus[i])
+ {
+ var wp = path.points[i];
+ Vector3 newPos = handlePosition + Vector3.Scale(wp.position - handlePosition, deltaScale);
+ wp.Transform(newPos - wp.position, Quaternion.identity, Vector3.one);
+ path.points[i] = wp;
+ }
+ }
+ }
+ else
+ {
+ // Scale all handles of selected control points relative to their control point:
+ for (int i = 0; i < path.ControlPointCount; ++i)
+ {
+ if (selectedStatus[i])
+ {
+ var wp = path.points[i];
+ wp.Transform(Vector3.zero, Quaternion.identity, deltaScale);
+ path.points[i] = wp;
+ }
+ }
+ }
+
+ path.FlushEvents();
+ return true;
+ }
+ return false;
+ }
+
+ protected bool RotateTool(Vector3 handlePosition, Quaternion handleRotation)
+ {
+
+ EditorGUI.BeginChangeCheck();
+
+ // TODO: investigate weird rotation gizmo:
+ Quaternion newRotation = Handles.RotationHandle(prevRot, handlePosition);
+
+ if (EditorGUI.EndChangeCheck())
+ {
+
+ Quaternion delta = newRotation * Quaternion.Inverse(prevRot);
+ prevRot = newRotation;
+
+ Undo.RecordObject(blueprint, "Rotate control point");
+
+ if (Tools.pivotMode == PivotMode.Center && selectedCount > 1)
+ {
+
+ // Rotate all selected control points around their average:
+ for (int i = 0; i < path.ControlPointCount; ++i)
+ {
+ if (selectedStatus[i])
+ {
+ var wp = path.points[i];
+ Vector3 newPos = handlePosition + delta * (wp.position - handlePosition);
+ wp.Transform(newPos - wp.position, Quaternion.identity, Vector3.one);
+ path.points[i] = wp;
+ }
+ }
+
+ }
+ else
+ {
+
+ // Rotate all handles of selected control points around their control point:
+ for (int i = 0; i < path.ControlPointCount; ++i)
+ {
+ if (selectedStatus[i])
+ {
+ var wp = path.points[i];
+ wp.Transform(Vector3.zero, delta, Vector3.one);
+ path.points[i] = wp;
+ }
+ }
+ }
+
+ path.FlushEvents();
+ return true;
+ }
+ return false;
+ }
+
+ protected bool OrientTool(Vector3 averagePos, Quaternion pivotRotation)
+ {
+
+ EditorGUI.BeginChangeCheck();
+ Quaternion newRotation = Handles.RotationHandle(prevRot, averagePos);
+
+ if (EditorGUI.EndChangeCheck())
+ {
+
+ Quaternion delta = newRotation * Quaternion.Inverse(prevRot);
+ prevRot = newRotation;
+
+ Undo.RecordObject(blueprint, "Orient control point");
+
+ // Rotate all selected control points around their average:
+ for (int i = 0; i < path.ControlPointCount; ++i)
+ {
+ if (selectedStatus[i])
+ {
+ path.normals[i] = delta * path.normals[i];
+ }
+ }
+
+ path.FlushEvents();
+ return true;
+ }
+ return false;
+ }
+
+
+ protected bool DoThicknessHandles(float scale)
+ {
+ Color oldColor = Handles.color;
+ Handles.color = handleColor;
+
+ EditorGUI.BeginChangeCheck();
+ for (int i = 0; i < path.ControlPointCount; ++i)
+ {
+ if (selectedStatus[i])
+ {
+ Vector3 position = path.points[i].position;
+
+ var tangent = path.points.GetTangent(i);
+ if (!tangent.Equals(Vector3.zero))
+ {
+ Quaternion orientation = Quaternion.LookRotation(tangent);
+
+ float offset = 0.05f;
+ float thickness = (path.thicknesses[i] * scale) + offset;
+
+ EditorGUI.BeginChangeCheck();
+ thickness = DoRadiusHandle(orientation, position, thickness);
+ if (EditorGUI.EndChangeCheck())
+ {
+ Undo.RecordObject(blueprint, "Change control point thickness");
+ path.thicknesses[i] = Mathf.Max(0, (thickness - offset) / scale);
+ path.FlushEvents();
+ return true;
+ }
+ }
+ }
+ }
+ Handles.color = oldColor;
+
+ return false;
+ }
+
+ public void DrawToolPanel()
+ {
+
+ DrawToolButtons();
+
+ DrawControlPointInspector();
+
+ }
+
+ private void DrawToolButtons()
+ {
+ GUILayout.BeginHorizontal();
+
+ EditorGUI.BeginChangeCheck();
+ GUILayout.Toggle(currentTool == PathEditorTool.TranslatePoints, new GUIContent(Resources.Load("TranslateControlPoint"), "Translate CPs"), "Button", GUILayout.MaxHeight(24), GUILayout.Width(38));
+ if (EditorGUI.EndChangeCheck())
+ {
+ currentTool = PathEditorTool.TranslatePoints;
+ }
+
+ EditorGUI.BeginChangeCheck();
+ GUILayout.Toggle(currentTool == PathEditorTool.RotatePoints, new GUIContent(Resources.Load("RotateControlPoint"), "Rotate CPs"), "Button", GUILayout.MaxHeight(24), GUILayout.Width(38));
+ if (EditorGUI.EndChangeCheck())
+ {
+ currentTool = PathEditorTool.RotatePoints;
+ }
+
+ EditorGUI.BeginChangeCheck();
+ GUILayout.Toggle(currentTool == PathEditorTool.ScalePoints, new GUIContent(Resources.Load("ScaleControlPoint"), "Scale CPs"), "Button", GUILayout.MaxHeight(24), GUILayout.Width(38));
+ if (EditorGUI.EndChangeCheck())
+ {
+ currentTool = PathEditorTool.ScalePoints;
+ }
+
+ EditorGUI.BeginChangeCheck();
+ GUILayout.Toggle(currentTool == PathEditorTool.InsertPoints, new GUIContent(Resources.Load("AddControlPoint"), "Add CPs"), "Button", GUILayout.MaxHeight(24), GUILayout.Width(38));
+ if (EditorGUI.EndChangeCheck())
+ {
+ currentTool = PathEditorTool.InsertPoints;
+ }
+
+ EditorGUI.BeginChangeCheck();
+ GUILayout.Toggle(currentTool == PathEditorTool.RemovePoints, new GUIContent(Resources.Load("RemoveControlPoint"), "Remove CPs"), "Button", GUILayout.MaxHeight(24), GUILayout.Width(38));
+ if (EditorGUI.EndChangeCheck())
+ {
+ currentTool = PathEditorTool.RemovePoints;
+ }
+
+ EditorGUI.BeginChangeCheck();
+ bool closed = GUILayout.Toggle(path.Closed, new GUIContent(Resources.Load("OpenCloseCurve"), "Open/Close the path"), "Button", GUILayout.MaxHeight(24), GUILayout.Width(38));
+ if (EditorGUI.EndChangeCheck())
+ {
+ Undo.RecordObject(blueprint, "Open/close path");
+ path.Closed = closed;
+ path.FlushEvents();
+ needsRepaint = true;
+ }
+
+ if (useOrientation)
+ {
+ EditorGUI.BeginChangeCheck();
+ GUILayout.Toggle(currentTool == PathEditorTool.OrientPoints, new GUIContent(Resources.Load("OrientControlPoint"), "Orientation tool"), "Button", GUILayout.MaxHeight(24), GUILayout.Width(38));
+ if (EditorGUI.EndChangeCheck())
+ {
+ currentTool = PathEditorTool.OrientPoints;
+ }
+ }
+
+ showTangentHandles = GUILayout.Toggle(showTangentHandles, new GUIContent(Resources.Load("ShowTangentHandles"), "Show tangent handles"), "Button", GUILayout.MaxHeight(24), GUILayout.Width(38));
+ showThicknessHandles = GUILayout.Toggle(showThicknessHandles, new GUIContent(Resources.Load("ShowThicknessHandles"), "Show thickness handles"), "Button", GUILayout.MaxHeight(24), GUILayout.Width(38));
+
+ GUILayout.EndHorizontal();
+ }
+
+ private void DrawPositionField(Rect rect, string label, int index)
+ {
+ EditorGUI.showMixedValue = false;
+ float pos = 0;
+ bool firstSelected = true;
+ for (int i = 0; i < path.ControlPointCount; ++i)
+ {
+ if (selectedStatus[i])
+ {
+ if (firstSelected)
+ {
+ pos = path.points[i].position[index];
+ firstSelected = false;
+ }
+ else if (!Mathf.Approximately(pos,path.points[i].position[index]))
+ {
+ EditorGUI.showMixedValue = true;
+ break;
+ }
+ }
+ }
+
+ EditorGUI.BeginChangeCheck();
+ float oldLabelWidth = EditorGUIUtility.labelWidth;
+ EditorGUIUtility.labelWidth = 10;
+ pos = EditorGUI.FloatField(rect, label, pos);
+ EditorGUIUtility.labelWidth = oldLabelWidth;
+ EditorGUI.showMixedValue = false;
+ if (EditorGUI.EndChangeCheck())
+ {
+
+ Undo.RecordObject(blueprint, "Change control points position");
+
+ for (int i = 0; i < path.ControlPointCount; ++i)
+ {
+ if (selectedStatus[i])
+ {
+ var wp = path.points[i];
+ wp.position[index] = pos;
+ path.points[i] = wp;
+ }
+ }
+ path.FlushEvents();
+ needsRepaint = true;
+ }
+ }
+
+ private void DrawInTangentField(Rect rect, string label, int index)
+ {
+ EditorGUI.showMixedValue = false;
+ float pos = 0;
+ bool firstSelected = true;
+ for (int i = 0; i < path.ControlPointCount; ++i)
+ {
+ if (selectedStatus[i])
+ {
+ if (firstSelected)
+ {
+ pos = path.points[i].inTangent[index];
+ firstSelected = false;
+ }
+ else if (!Mathf.Approximately(pos, path.points[i].inTangent[index]))
+ {
+ EditorGUI.showMixedValue = true;
+ break;
+ }
+ }
+ }
+
+ EditorGUI.BeginChangeCheck();
+ float oldLabelWidth = EditorGUIUtility.labelWidth;
+ EditorGUIUtility.labelWidth = 10;
+ pos = EditorGUI.FloatField(rect, label, pos);
+ EditorGUIUtility.labelWidth = oldLabelWidth;
+ EditorGUI.showMixedValue = false;
+ if (EditorGUI.EndChangeCheck())
+ {
+
+ Undo.RecordObject(blueprint, "Change control points tangent");
+
+ for (int i = 0; i < path.ControlPointCount; ++i)
+ {
+ if (selectedStatus[i])
+ {
+ var wp = path.points[i];
+ var newInTangent = wp.inTangent;
+ newInTangent[index] = pos;
+ wp.SetInTangent(newInTangent);
+ path.points[i] = wp;
+ }
+ }
+ path.FlushEvents();
+ needsRepaint = true;
+ }
+ }
+
+ private void DrawOutTangentField(Rect rect, string label, int index)
+ {
+ EditorGUI.showMixedValue = false;
+ float pos = 0;
+ bool firstSelected = true;
+ for (int i = 0; i < path.ControlPointCount; ++i)
+ {
+ if (selectedStatus[i])
+ {
+ if (firstSelected)
+ {
+ pos = path.points[i].outTangent[index];
+ firstSelected = false;
+ }
+ else if (!Mathf.Approximately(pos, path.points[i].outTangent[index]))
+ {
+ EditorGUI.showMixedValue = true;
+ break;
+ }
+ }
+ }
+
+ EditorGUI.BeginChangeCheck();
+ float oldLabelWidth = EditorGUIUtility.labelWidth;
+ EditorGUIUtility.labelWidth = 10;
+ pos = EditorGUI.FloatField(rect, label, pos);
+ EditorGUIUtility.labelWidth = oldLabelWidth;
+ EditorGUI.showMixedValue = false;
+ if (EditorGUI.EndChangeCheck())
+ {
+
+ Undo.RecordObject(blueprint, "Change control points tangent");
+
+ for (int i = 0; i < path.ControlPointCount; ++i)
+ {
+ if (selectedStatus[i])
+ {
+ var wp = path.points[i];
+ var newOutTangent = wp.outTangent;
+ newOutTangent[index] = pos;
+ wp.SetOutTangent(newOutTangent);
+ path.points[i] = wp;
+ }
+ }
+ path.FlushEvents();
+ needsRepaint = true;
+ }
+ }
+
+ private void DrawControlPointInspector()
+ {
+
+ GUI.enabled = selectedCount > 0;
+
+ bool wideMode = EditorGUIUtility.wideMode;
+ EditorGUIUtility.wideMode = true;
+ EditorGUIUtility.labelWidth = 100;
+
+ EditorGUILayout.BeginVertical();
+
+ GUILayout.Box("", ObiEditorUtils.GetSeparatorLineStyle());
+
+ // position:
+ var rect = EditorGUILayout.GetControlRect();
+ rect = EditorGUI.PrefixLabel(rect, GUIUtility.GetControlID(FocusType.Passive), new GUIContent("Position"));
+ rect.width /= 3.0f;
+ DrawPositionField(rect,"X",0); rect.x += rect.width;
+ DrawPositionField(rect,"Y",1); rect.x += rect.width;
+ DrawPositionField(rect,"Z",2); rect.x += rect.width;
+
+ // in tangent:
+ rect = EditorGUILayout.GetControlRect();
+ rect = EditorGUI.PrefixLabel(rect, GUIUtility.GetControlID(FocusType.Passive), new GUIContent("In Tangent"));
+ rect.width /= 3.0f;
+ DrawInTangentField(rect, "X", 0); rect.x += rect.width;
+ DrawInTangentField(rect, "Y", 1); rect.x += rect.width;
+ DrawInTangentField(rect, "Z", 2); rect.x += rect.width;
+
+ // out tangent:
+ rect = EditorGUILayout.GetControlRect();
+ rect = EditorGUI.PrefixLabel(rect, GUIUtility.GetControlID(FocusType.Passive), new GUIContent("Out Tangent"));
+ rect.width /= 3.0f;
+ DrawOutTangentField(rect, "X", 0); rect.x += rect.width;
+ DrawOutTangentField(rect, "Y", 1); rect.x += rect.width;
+ DrawOutTangentField(rect, "Z", 2); rect.x += rect.width;
+
+ // tangent mode:
+ EditorGUI.showMixedValue = false;
+ var mode = ObiWingedPoint.TangentMode.Free;
+ bool firstSelected = true;
+ for (int i = 0; i < path.ControlPointCount; ++i)
+ {
+ if (selectedStatus[i])
+ {
+ if (firstSelected)
+ {
+ mode = path.points[i].tangentMode;
+ firstSelected = false;
+ }
+ else if (mode != path.points[i].tangentMode)
+ {
+ EditorGUI.showMixedValue = true;
+ break;
+ }
+ }
+ }
+
+ EditorGUI.BeginChangeCheck();
+ var newMode = (ObiWingedPoint.TangentMode)EditorGUILayout.EnumPopup("Tangent mode", mode, GUILayout.MinWidth(94));
+ EditorGUI.showMixedValue = false;
+ if (EditorGUI.EndChangeCheck())
+ {
+
+ Undo.RecordObject(blueprint, "Change control points mode");
+
+ for (int i = 0; i < path.ControlPointCount; ++i)
+ {
+ if (selectedStatus[i])
+ {
+ var wp = path.points[i];
+ wp.tangentMode = newMode;
+ path.points[i] = wp;
+ }
+ }
+ path.FlushEvents();
+ needsRepaint = true;
+ }
+
+ // thickness:
+ EditorGUI.showMixedValue = false;
+ float thickness = 0;
+ firstSelected = true;
+ for (int i = 0; i < path.ControlPointCount; ++i)
+ {
+ if (selectedStatus[i])
+ {
+ if (firstSelected)
+ {
+ thickness = path.thicknesses[i];
+ firstSelected = false;
+ }
+ else if (!Mathf.Approximately(thickness, path.thicknesses[i]))
+ {
+ EditorGUI.showMixedValue = true;
+ break;
+ }
+ }
+ }
+
+ EditorGUI.BeginChangeCheck();
+ thickness = EditorGUILayout.FloatField("Thickness", thickness, GUILayout.MinWidth(94));
+ EditorGUI.showMixedValue = false;
+ if (EditorGUI.EndChangeCheck())
+ {
+
+ Undo.RecordObject(blueprint, "Change control point thickness");
+
+ for (int i = 0; i < path.ControlPointCount; ++i)
+ {
+ if (selectedStatus[i])
+ path.thicknesses[i] = Mathf.Max(0, thickness);
+ }
+ path.FlushEvents();
+ needsRepaint = true;
+ }
+
+ // mass:
+ EditorGUI.showMixedValue = false;
+ float mass = 0;
+ firstSelected = true;
+ for (int i = 0; i < path.ControlPointCount; ++i)
+ {
+ if (selectedStatus[i])
+ {
+ if (firstSelected)
+ {
+ mass = path.masses[i];
+ firstSelected = false;
+ }
+ else if (!Mathf.Approximately(mass, path.masses[i]))
+ {
+ EditorGUI.showMixedValue = true;
+ break;
+ }
+ }
+ }
+
+ EditorGUI.BeginChangeCheck();
+ mass = EditorGUILayout.FloatField("Mass", mass, GUILayout.MinWidth(94));
+ EditorGUI.showMixedValue = false;
+ if (EditorGUI.EndChangeCheck())
+ {
+
+ Undo.RecordObject(blueprint, "Change control point mass");
+
+ for (int i = 0; i < path.ControlPointCount; ++i)
+ {
+ if (selectedStatus[i])
+ path.masses[i] = mass;
+ }
+ path.FlushEvents();
+ needsRepaint = true;
+ }
+
+ if (useOrientation)
+ {
+ // rotational mass:
+ EditorGUI.showMixedValue = false;
+ float rotationalMass = 0;
+ firstSelected = true;
+ for (int i = 0; i < path.ControlPointCount; ++i)
+ {
+ if (selectedStatus[i])
+ {
+ if (firstSelected)
+ {
+ rotationalMass = path.rotationalMasses[i];
+ firstSelected = false;
+ }
+ else if (!Mathf.Approximately(rotationalMass, path.rotationalMasses[i]))
+ {
+ EditorGUI.showMixedValue = true;
+ break;
+ }
+ }
+ }
+
+ EditorGUI.BeginChangeCheck();
+ rotationalMass = EditorGUILayout.FloatField("Rotational mass", rotationalMass, GUILayout.MinWidth(94));
+ EditorGUI.showMixedValue = false;
+ if (EditorGUI.EndChangeCheck())
+ {
+
+ Undo.RecordObject(blueprint, "Change control point rotational mass");
+
+ for (int i = 0; i < path.ControlPointCount; ++i)
+ {
+ if (selectedStatus[i])
+ path.rotationalMasses[i] = rotationalMass;
+ }
+ path.FlushEvents();
+ needsRepaint = true;
+ }
+ }
+
+ // category:
+ EditorGUI.showMixedValue = false;
+ int category = 0;
+ firstSelected = true;
+ for (int i = 0; i < path.ControlPointCount; ++i)
+ {
+ if (selectedStatus[i])
+ {
+ if (firstSelected)
+ {
+ category = ObiUtils.GetCategoryFromFilter(path.filters[i]);
+ firstSelected = false;
+ }
+ else if (!Mathf.Approximately(category, ObiUtils.GetCategoryFromFilter(path.filters[i])))
+ {
+ EditorGUI.showMixedValue = true;
+ break;
+ }
+ }
+ }
+
+ EditorGUI.BeginChangeCheck();
+ category = EditorGUILayout.Popup("Category", category, ObiUtils.categoryNames, GUILayout.MinWidth(94));
+ EditorGUI.showMixedValue = false;
+ if (EditorGUI.EndChangeCheck())
+ {
+ Undo.RecordObject(blueprint, "Change control point category");
+
+ for (int i = 0; i < path.ControlPointCount; ++i)
+ {
+ if (selectedStatus[i])
+ path.filters[i] = ObiUtils.MakeFilter(ObiUtils.GetMaskFromFilter(path.filters[i]),category);
+ }
+ path.FlushEvents();
+ needsRepaint = true;
+ }
+
+ // mask:
+ EditorGUI.showMixedValue = false;
+ int mask = 0;
+ firstSelected = true;
+ for (int i = 0; i < path.ControlPointCount; ++i)
+ {
+ if (selectedStatus[i])
+ {
+ if (firstSelected)
+ {
+ mask = ObiUtils.GetMaskFromFilter(path.filters[i]);
+ firstSelected = false;
+ }
+ else if (!Mathf.Approximately(mask, ObiUtils.GetMaskFromFilter(path.filters[i])))
+ {
+ EditorGUI.showMixedValue = true;
+ break;
+ }
+ }
+ }
+
+ EditorGUI.BeginChangeCheck();
+ mask = EditorGUILayout.MaskField("Collides with", mask, ObiUtils.categoryNames, GUILayout.MinWidth(94));
+ EditorGUI.showMixedValue = false;
+ if (EditorGUI.EndChangeCheck())
+ {
+ Undo.RecordObject(blueprint, "Change control point mask");
+
+ for (int i = 0; i < path.ControlPointCount; ++i)
+ {
+ if (selectedStatus[i])
+ path.filters[i] = ObiUtils.MakeFilter(mask,ObiUtils.GetCategoryFromFilter(path.filters[i]));
+ }
+ path.FlushEvents();
+ needsRepaint = true;
+ }
+
+ // color:
+ EditorGUI.showMixedValue = false;
+ Color color = Color.white;
+ firstSelected = true;
+ for (int i = 0; i < path.ControlPointCount; ++i)
+ {
+ if (selectedStatus[i])
+ {
+ if (firstSelected)
+ {
+ color = path.colors[i];
+ firstSelected = false;
+ }
+ else if (color != path.colors[i])
+ {
+ EditorGUI.showMixedValue = true;
+ break;
+ }
+ }
+ }
+
+ EditorGUI.BeginChangeCheck();
+ color = EditorGUILayout.ColorField(new GUIContent("Color"), color, true, true, true, GUILayout.MinWidth(94));
+ EditorGUI.showMixedValue = false;
+ if (EditorGUI.EndChangeCheck())
+ {
+
+ Undo.RecordObject(blueprint, "Change control point color");
+
+ for (int i = 0; i < path.ControlPointCount; ++i)
+ {
+ if (selectedStatus[i])
+ path.colors[i] = color;
+ }
+ path.FlushEvents();
+ needsRepaint = true;
+ }
+
+ // name:
+ EditorGUI.showMixedValue = false;
+ string cpname = "";
+ firstSelected = true;
+ for (int i = 0; i < path.ControlPointCount; ++i)
+ {
+ if (selectedStatus[i])
+ {
+ if (firstSelected)
+ {
+ cpname = path.GetName(i);
+ firstSelected = false;
+ }
+ else if (cpname != path.GetName(i))
+ {
+ EditorGUI.showMixedValue = true;
+ break;
+ }
+ }
+ }
+
+ EditorGUI.BeginChangeCheck();
+ cpname = EditorGUILayout.DelayedTextField("Name", cpname, GUILayout.MinWidth(94));
+ EditorGUI.showMixedValue = false;
+ if (EditorGUI.EndChangeCheck())
+ {
+
+ Undo.RecordObject(blueprint, "Change control point name");
+
+ for (int i = 0; i < path.ControlPointCount; ++i)
+ {
+ if (selectedStatus[i])
+ path.SetName(i, cpname);
+ }
+ path.FlushEvents();
+ needsRepaint = true;
+ }
+
+
+ EditorGUILayout.EndVertical();
+
+ EditorGUIUtility.wideMode = wideMode;
+
+ GUI.enabled = true;
+ }
+
+ internal static float DoRadiusHandle(Quaternion rotation, Vector3 position, float radius)
+ {
+ Vector3[] vector3Array;
+
+ Vector3 camToPosition;
+ if (Camera.current.orthographic)
+ {
+ camToPosition = Camera.current.transform.forward;
+ Handles.DrawWireDisc(position, camToPosition, radius);
+
+ vector3Array = new Vector3[4]
+ {
+ Camera.current.transform.right,
+ Camera.current.transform.up,
+ -Camera.current.transform.right,
+ -Camera.current.transform.up,
+ };
+
+ }
+ else
+ {
+ camToPosition = position - Camera.current.transform.position;
+ Handles.DrawWireDisc(position, rotation * Vector3.forward, radius);
+
+ vector3Array = new Vector3[4]
+ {
+ rotation * Vector3.right,
+ rotation * Vector3.up,
+ rotation * -Vector3.right,
+ rotation * -Vector3.up,
+ };
+ }
+
+ for (int index = 0; index < 4; ++index)
+ {
+ int controlId = GUIUtility.GetControlID("ObiPathThicknessHandle".GetHashCode(), FocusType.Passive);
+ Vector3 position1 = position + radius * vector3Array[index];
+ bool changed = GUI.changed;
+ GUI.changed = false;
+ Vector3 a = Handles.Slider(controlId, position1, vector3Array[index], HandleUtility.GetHandleSize(position1) * 0.03f, Handles.DotHandleCap, 0.0f);
+ if (GUI.changed)
+ radius = Vector3.Distance(a, position);
+ GUI.changed |= changed;
+ }
+
+ return radius;
+ }
+
+ public static float ScreenPointToCurveMu(ObiPath path, Vector2 screenPoint, Matrix4x4 referenceFrame, int samples = 30)
+ {
+
+ if (path.ControlPointCount >= 2)
+ {
+
+ samples = Mathf.Max(1, samples);
+ float step = 1 / (float)samples;
+
+ float closestMu = 0;
+ float minDistance = float.MaxValue;
+
+ for (int k = 0; k < path.GetSpanCount(); ++k)
+ {
+ int nextCP = (k + 1) % path.ControlPointCount;
+
+ var wp1 = path.points[k];
+ var wp2 = path.points[nextCP];
+
+ Vector3 _p = referenceFrame.MultiplyPoint3x4(wp1.position);
+ Vector3 p = referenceFrame.MultiplyPoint3x4(wp1.outTangentEndpoint);
+ Vector3 p_ = referenceFrame.MultiplyPoint3x4(wp2.inTangentEndpoint);
+ Vector3 p__ = referenceFrame.MultiplyPoint3x4(wp2.position);
+
+ Vector2 lastPoint = HandleUtility.WorldToGUIPoint(path.m_Points.Evaluate(_p, p, p_, p__, 0));
+ for (int i = 1; i <= samples; ++i)
+ {
+
+ Vector2 currentPoint = HandleUtility.WorldToGUIPoint(path.m_Points.Evaluate(_p, p, p_, p__, i * step));
+
+ float mu;
+ float distance = Vector2.SqrMagnitude((Vector2)ObiUtils.ProjectPointLine(lastPoint, currentPoint, screenPoint, out mu) - screenPoint);
+
+ if (distance < minDistance)
+ {
+ minDistance = distance;
+ closestMu = (k + (i - 1) * step + mu / samples) / (float)path.GetSpanCount();
+ }
+ lastPoint = currentPoint;
+ }
+
+ }
+
+ return closestMu;
+
+ }
+ else
+ {
+ Debug.LogWarning("Curve needs at least 2 control points to be defined.");
+ }
+ return 0;
+
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/Assets/Obi/Editor/RopeAndRod/ObiPathEditor.cs.meta b/Assets/Obi/Editor/RopeAndRod/ObiPathEditor.cs.meta
new file mode 100644
index 000000000..32c490bc1
--- /dev/null
+++ b/Assets/Obi/Editor/RopeAndRod/ObiPathEditor.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 0cb694bcadb6a4909b593111507e1eb3
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/RopeAndRod/ObiPathHandles.cs b/Assets/Obi/Editor/RopeAndRod/ObiPathHandles.cs
new file mode 100644
index 000000000..2a0bc1b67
--- /dev/null
+++ b/Assets/Obi/Editor/RopeAndRod/ObiPathHandles.cs
@@ -0,0 +1,271 @@
+using UnityEngine;
+using UnityEditor;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace Obi
+{
+
+ public class ObiPathHandles
+ {
+
+ static int splineSelectorHash = "ObiPathSelectorHash".GetHashCode();
+ const int minSelectionDistance = 5;
+
+ static Vector2 startPos;
+ static Vector2 currentPos;
+ static bool dragging = false;
+ static Rect marquee;
+
+ public static bool SplineCPSelector(ObiPath path, bool[] selectionStatus)
+ {
+
+ int controlID = GUIUtility.GetControlID(splineSelectorHash, FocusType.Passive);
+ int selectedCPIndex = -1;
+ bool selectionStatusChanged = false;
+
+ // select vertex on mouse click:
+ switch (Event.current.GetTypeForControl(controlID))
+ {
+ case EventType.Layout:
+ case EventType.MouseMove:
+
+ float minSqrDistance = System.Single.MaxValue;
+ float sqrMinSelectionDistance = minSelectionDistance * minSelectionDistance;
+
+ for (int i = 0; i < path.ControlPointCount; i++)
+ {
+
+ // get particle position in gui space:
+ Vector2 pos = HandleUtility.WorldToGUIPoint(path.points[i].position);
+
+ // get distance from mouse position to particle position:
+ float sqrDistance = Vector2.SqrMagnitude(Event.current.mousePosition - pos);
+
+ // check if this control point is closer to the cursor that any previously considered point.
+ if (sqrDistance < sqrMinSelectionDistance && sqrDistance < minSqrDistance)
+ {
+ minSqrDistance = sqrDistance;
+ }
+
+ }
+ HandleUtility.AddControl(controlID, Mathf.Sqrt(minSqrDistance));
+
+ break;
+
+ case EventType.MouseDown:
+
+ marquee.Set(0, 0, 0, 0);
+ startPos = Event.current.mousePosition;
+
+ if (Event.current.button == 0)
+ {
+
+ if (HandleUtility.nearestControl == controlID)
+ {
+ GUIUtility.hotControl = controlID;
+
+ // If the user is pressing shift or ctrl, accumulate selection.
+ if ((Event.current.modifiers & (EventModifiers.Shift | EventModifiers.Control)) == 0 && (Event.current.modifiers & EventModifiers.Alt) == 0)
+ {
+ for (int i = 0; i < selectionStatus.Length; i++)
+ selectionStatus[i] = false;
+
+ selectionStatusChanged = true;
+ }
+
+ minSqrDistance = System.Single.MaxValue;
+ sqrMinSelectionDistance = minSelectionDistance * minSelectionDistance;
+
+ for (int i = 0; i < path.ControlPointCount; i++)
+ {
+
+ // get particle position in gui space:
+ Vector2 pos = HandleUtility.WorldToGUIPoint(path.points[i].position);
+
+ // get distance from mouse position to particle position:
+ float sqrDistance = Vector2.SqrMagnitude(startPos - pos);
+
+ // check if this control point is closer to the cursor that any previously considered point.
+ if (sqrDistance < sqrMinSelectionDistance && sqrDistance < minSqrDistance)
+ {
+ minSqrDistance = sqrDistance;
+ selectedCPIndex = i;
+ }
+
+ }
+
+ if (selectedCPIndex >= 0)
+ { // toggle particle selection status.
+
+ selectionStatus[selectedCPIndex] = !selectionStatus[selectedCPIndex];
+ selectionStatusChanged = true;
+
+ // Prevent spline deselection if we have selected a particle:
+ Event.current.Use();
+
+ }
+ }
+ else if ((Event.current.modifiers & (EventModifiers.Shift | EventModifiers.Control)) == 0 && (Event.current.modifiers & EventModifiers.Alt) == 0)
+ {
+ for (int i = 0; i < selectionStatus.Length; i++)
+ selectionStatus[i] = false;
+
+ selectionStatusChanged = true;
+ }
+ }
+
+ break;
+
+ case EventType.MouseDrag:
+
+ if (Event.current.button == 0 && (Event.current.modifiers & EventModifiers.Alt) == 0)
+ {
+ currentPos = Event.current.mousePosition;
+ if (!dragging && Vector2.Distance(startPos, currentPos) > 5)
+ {
+ dragging = true;
+ }
+
+ if (dragging)
+ {
+ GUIUtility.hotControl = controlID;
+ Event.current.Use();
+ }
+
+ //update marquee rect:
+ float left = Mathf.Min(startPos.x, currentPos.x);
+ float right = Mathf.Max(startPos.x, currentPos.x);
+ float bottom = Mathf.Min(startPos.y, currentPos.y);
+ float top = Mathf.Max(startPos.y, currentPos.y);
+
+ marquee = new Rect(left, bottom, right - left, top - bottom);
+
+ }
+
+ break;
+
+ case EventType.MouseUp:
+
+ if (GUIUtility.hotControl == controlID)
+ {
+
+ dragging = false;
+
+ for (int i = 0; i < path.ControlPointCount; i++)
+ {
+
+ // get particle position in gui space:
+ Vector2 pos = HandleUtility.WorldToGUIPoint(path.points[i].position);
+
+ if (pos.x > marquee.xMin && pos.x < marquee.xMax && pos.y > marquee.yMin && pos.y < marquee.yMax)
+ {
+ selectionStatus[i] = true;
+ selectionStatusChanged = true;
+ }
+
+ }
+
+ GUIUtility.hotControl = 0;
+ Event.current.Use();
+ }
+
+ break;
+
+ case EventType.Repaint:
+
+ if (dragging)
+ {
+ GUISkin oldSkin = GUI.skin;
+ GUI.skin = EditorGUIUtility.GetBuiltinSkin(EditorSkin.Scene);
+ Handles.BeginGUI();
+ GUI.Box(new Rect(marquee.xMin, marquee.yMin, marquee.width, marquee.height), "");
+ Handles.EndGUI();
+ GUI.skin = oldSkin;
+ }
+
+ break;
+
+ }
+
+ return selectionStatusChanged;
+ }
+
+ private static void DrawControlPointArcs(ObiPath path, float thicknessScale)
+ {
+ for (int i = 0; i < path.ControlPointCount; ++i)
+ {
+ Vector3 position = path.points[i].position;
+ Vector3 tangent = path.points.GetTangent(i);
+ Vector3 right = Vector3.Cross(tangent, path.normals[i]).normalized;
+ float thickness = path.thicknesses[i] * thicknessScale + 0.05f;
+
+ Handles.DrawWireArc(position, tangent, right, -180, thickness);
+ }
+ }
+
+ private static void DrawPathPolylines(Vector3[] samples, Vector3[] leftSamples, Vector3[] rightSamples, Vector3[] upSamples, bool drawOrientation)
+ {
+ Handles.DrawPolyLine(samples);
+ if (drawOrientation)
+ {
+ Handles.DrawPolyLine(leftSamples);
+ Handles.DrawPolyLine(upSamples);
+ Handles.DrawPolyLine(rightSamples);
+ }
+ }
+
+ public static void DrawPathHandle(ObiPath path, Matrix4x4 referenceFrame, float thicknessScale, int resolution, bool drawOrientation = true)
+ {
+
+ if (path == null || path.GetSpanCount() == 0) return;
+
+ Matrix4x4 prevMatrix = Handles.matrix;
+ Handles.matrix = referenceFrame;
+
+ // Draw the curve:
+ int curveSegments = path.GetSpanCount() * resolution;
+ Vector3[] samples = new Vector3[curveSegments + 1];
+ Vector3[] leftSamples = new Vector3[curveSegments + 1];
+ Vector3[] rightSamples = new Vector3[curveSegments + 1];
+ Vector3[] upSamples = new Vector3[curveSegments + 1];
+
+ for (int i = 0; i <= curveSegments; ++i)
+ {
+
+ float mu = i / (float)curveSegments;
+ samples[i] = path.points.GetPositionAtMu(path.Closed,mu);
+
+ if (drawOrientation)
+ {
+ Vector3 tangent = path.points.GetTangentAtMu(path.Closed,mu);
+ Vector3 right = Vector3.Cross(tangent, path.normals.GetAtMu(path.Closed,mu)).normalized;
+ Vector3 up = Vector3.Cross(right, tangent).normalized;
+ float thickness = path.thicknesses.GetAtMu(path.Closed,mu) * thicknessScale + 0.05f;
+
+ leftSamples[i] = samples[i] - right * thickness;
+ rightSamples[i] = samples[i] + right * thickness;
+ upSamples[i] = samples[i] + up * thickness;
+
+ if (i % 5 == 0)
+ {
+ Handles.DrawLine(leftSamples[i], rightSamples[i]);
+ Handles.DrawLine(samples[i], samples[i] + up * thickness);
+ }
+ }
+ }
+
+ if (drawOrientation)
+ DrawControlPointArcs(path, thicknessScale);
+
+ DrawPathPolylines(samples, leftSamples, rightSamples, upSamples, drawOrientation);
+ DrawPathPolylines(samples, leftSamples, rightSamples, upSamples, drawOrientation);
+
+ Handles.matrix = prevMatrix;
+ }
+
+
+ }
+}
+
diff --git a/Assets/Obi/Editor/RopeAndRod/ObiPathHandles.cs.meta b/Assets/Obi/Editor/RopeAndRod/ObiPathHandles.cs.meta
new file mode 100644
index 000000000..8df16e491
--- /dev/null
+++ b/Assets/Obi/Editor/RopeAndRod/ObiPathHandles.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: f3c12ceb831344c47af02f0d6bf73de7
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/RopeAndRod/ObiPathSmootherEditor.cs b/Assets/Obi/Editor/RopeAndRod/ObiPathSmootherEditor.cs
new file mode 100644
index 000000000..068bc64ab
--- /dev/null
+++ b/Assets/Obi/Editor/RopeAndRod/ObiPathSmootherEditor.cs
@@ -0,0 +1,37 @@
+using UnityEditor;
+using UnityEngine;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace Obi
+{
+
+ [CustomEditor(typeof(ObiPathSmoother), true), CanEditMultipleObjects]
+ public class ObiPathSmootherEditor : Editor
+ {
+
+ ObiPathSmoother shape;
+
+ public void OnEnable()
+ {
+ shape = (ObiPathSmoother)target;
+ }
+
+ public override void OnInspectorGUI()
+ {
+
+ serializedObject.UpdateIfRequiredOrScript();
+
+ Editor.DrawPropertiesExcluding(serializedObject, "m_Script");
+
+ // Apply changes to the serializedProperty
+ if (GUI.changed)
+ serializedObject.ApplyModifiedProperties();
+
+ }
+
+ }
+
+}
+
diff --git a/Assets/Obi/Editor/RopeAndRod/ObiPathSmootherEditor.cs.meta b/Assets/Obi/Editor/RopeAndRod/ObiPathSmootherEditor.cs.meta
new file mode 100644
index 000000000..4b3fca50d
--- /dev/null
+++ b/Assets/Obi/Editor/RopeAndRod/ObiPathSmootherEditor.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: a01b6dc95e7284e2583513863858d670
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/RopeAndRod/ObiRodEditor.cs b/Assets/Obi/Editor/RopeAndRod/ObiRodEditor.cs
new file mode 100644
index 000000000..cb807468f
--- /dev/null
+++ b/Assets/Obi/Editor/RopeAndRod/ObiRodEditor.cs
@@ -0,0 +1,220 @@
+using UnityEditor;
+using UnityEditor.EditorTools;
+using UnityEditorInternal;
+using UnityEngine;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+
+namespace Obi
+{
+
+ [CustomEditor(typeof(ObiRod))]
+ public class ObiRodEditor : Editor
+ {
+ [MenuItem("GameObject/3D Object/Obi/Obi Rod", false, 301)]
+ static void CreateObiRod(MenuCommand menuCommand)
+ {
+ GameObject go = new GameObject("Obi Rod", typeof(ObiRod), typeof(ObiRopeExtrudedRenderer));
+ var renderer = go.GetComponent();
+ renderer.material = ObiEditorUtils.GetDefaultMaterial();
+ ObiEditorUtils.PlaceActorRoot(go, menuCommand);
+ }
+
+ ObiRod actor;
+
+ SerializedProperty rodBlueprint;
+
+ SerializedProperty collisionMaterial;
+ SerializedProperty selfCollisions;
+ SerializedProperty surfaceCollisions;
+ SerializedProperty massScale;
+
+ SerializedProperty stretchShearConstraintsEnabled;
+ SerializedProperty stretchCompliance;
+ SerializedProperty shear1Compliance;
+ SerializedProperty shear2Compliance;
+
+ SerializedProperty bendTwistConstraintsEnabled;
+ SerializedProperty torsionCompliance;
+ SerializedProperty bend1Compliance;
+ SerializedProperty bend2Compliance;
+ SerializedProperty plasticYield;
+ SerializedProperty plasticCreep;
+
+ SerializedProperty aerodynamicsEnabled;
+ SerializedProperty drag;
+ SerializedProperty lift;
+
+ SerializedProperty chainConstraintsEnabled;
+ SerializedProperty tightness;
+
+ GUIStyle editLabelStyle;
+
+ public void OnEnable()
+ {
+ actor = (ObiRod)target;
+
+ rodBlueprint = serializedObject.FindProperty("m_RodBlueprint");
+
+ collisionMaterial = serializedObject.FindProperty("m_CollisionMaterial");
+ selfCollisions = serializedObject.FindProperty("m_SelfCollisions");
+ surfaceCollisions = serializedObject.FindProperty("m_SurfaceCollisions");
+ massScale = serializedObject.FindProperty("m_MassScale");
+
+ stretchShearConstraintsEnabled = serializedObject.FindProperty("_stretchShearConstraintsEnabled");
+ stretchCompliance = serializedObject.FindProperty("_stretchCompliance");
+ shear1Compliance = serializedObject.FindProperty("_shear1Compliance");
+ shear2Compliance = serializedObject.FindProperty("_shear2Compliance");
+
+ bendTwistConstraintsEnabled = serializedObject.FindProperty("_bendTwistConstraintsEnabled");
+ torsionCompliance = serializedObject.FindProperty("_torsionCompliance");
+ bend1Compliance = serializedObject.FindProperty("_bend1Compliance");
+ bend2Compliance = serializedObject.FindProperty("_bend2Compliance");
+ plasticYield = serializedObject.FindProperty("_plasticYield");
+ plasticCreep = serializedObject.FindProperty("_plasticCreep");
+
+ aerodynamicsEnabled = serializedObject.FindProperty("_aerodynamicsEnabled");
+ drag = serializedObject.FindProperty("_drag");
+ lift = serializedObject.FindProperty("_lift");
+
+ chainConstraintsEnabled = serializedObject.FindProperty("_chainConstraintsEnabled");
+ tightness = serializedObject.FindProperty("_tightness");
+ }
+
+ private void DoEditButton()
+ {
+ using (new EditorGUI.DisabledScope(actor.rodBlueprint == null))
+ {
+ EditorGUILayout.BeginHorizontal();
+ GUILayout.Space(EditorGUIUtility.labelWidth);
+ EditorGUI.BeginChangeCheck();
+ bool edit = GUILayout.Toggle(ToolManager.activeToolType == typeof(ObiPathEditor), new GUIContent(Resources.Load("EditCurves")), "Button", GUILayout.MaxWidth(36), GUILayout.MaxHeight(24));
+ EditorGUILayout.LabelField("Edit path", editLabelStyle, GUILayout.ExpandHeight(true), GUILayout.MaxHeight(24));
+ if (EditorGUI.EndChangeCheck())
+ {
+ if (edit)
+ ToolManager.SetActiveTool();
+ else
+ ToolManager.RestorePreviousPersistentTool();
+
+ SceneView.RepaintAll();
+ }
+ EditorGUILayout.EndHorizontal();
+ }
+ }
+
+ public override void OnInspectorGUI()
+ {
+ if (editLabelStyle == null)
+ {
+ editLabelStyle = new GUIStyle(GUI.skin.label);
+ editLabelStyle.alignment = TextAnchor.MiddleLeft;
+ }
+
+ serializedObject.UpdateIfRequiredOrScript();
+
+ if (actor.rodBlueprint != null && actor.rodBlueprint.path.ControlPointCount < 2)
+ {
+ actor.rodBlueprint.GenerateImmediate();
+ }
+
+ using (new EditorGUI.DisabledScope(ToolManager.activeToolType == typeof(ObiPathEditor)))
+ {
+ GUILayout.BeginHorizontal();
+
+ EditorGUI.BeginChangeCheck();
+
+ EditorGUILayout.PropertyField(rodBlueprint, new GUIContent("Blueprint"));
+
+ if (actor.rodBlueprint == null)
+ {
+ if (GUILayout.Button("Create", EditorStyles.miniButton, GUILayout.MaxWidth(80)))
+ {
+ string path = EditorUtility.SaveFilePanel("Save blueprint", "Assets/", "RodBlueprint", "asset");
+ if (!string.IsNullOrEmpty(path))
+ {
+ path = FileUtil.GetProjectRelativePath(path);
+ ObiRodBlueprint asset = ScriptableObject.CreateInstance();
+
+ AssetDatabase.CreateAsset(asset, path);
+ AssetDatabase.SaveAssets();
+
+ actor.rodBlueprint = asset;
+ }
+ }
+ }
+
+ if (EditorGUI.EndChangeCheck())
+ {
+ foreach (var t in targets)
+ {
+ (t as ObiRod).RemoveFromSolver();
+ (t as ObiRod).ClearState();
+ }
+ serializedObject.ApplyModifiedProperties();
+ foreach (var t in targets)
+ (t as ObiRod).AddToSolver();
+ }
+
+ GUILayout.EndHorizontal();
+ }
+
+ EditorGUILayout.PropertyField(massScale, new GUIContent("m_MassScale"));
+
+ DoEditButton();
+
+ EditorGUILayout.Space();
+ EditorGUILayout.LabelField("Collisions", EditorStyles.boldLabel);
+ EditorGUILayout.PropertyField(collisionMaterial, new GUIContent("Collision material"));
+ EditorGUILayout.PropertyField(selfCollisions, new GUIContent("Self collisions"));
+ EditorGUILayout.PropertyField(surfaceCollisions, new GUIContent("Surface-based collisions"));
+
+ EditorGUILayout.Space();
+ ObiEditorUtils.DoToggleablePropertyGroup(stretchShearConstraintsEnabled, new GUIContent("Stretch & Shear Constraints", Resources.Load("Icons/ObiStretchShearConstraints Icon")),
+ () => {
+ EditorGUILayout.PropertyField(stretchCompliance, new GUIContent("Stretch compliance"));
+ EditorGUILayout.PropertyField(shear1Compliance, new GUIContent("Shear compliance X"));
+ EditorGUILayout.PropertyField(shear2Compliance, new GUIContent("Shear compliance Y"));
+ });
+
+ ObiEditorUtils.DoToggleablePropertyGroup(bendTwistConstraintsEnabled, new GUIContent("Bend & Twist Constraints", Resources.Load("Icons/ObiBendTwistConstraints Icon")),
+ () => {
+ EditorGUILayout.PropertyField(torsionCompliance, new GUIContent("Torsion compliance"));
+ EditorGUILayout.PropertyField(bend1Compliance, new GUIContent("Bend compliance X"));
+ EditorGUILayout.PropertyField(bend2Compliance, new GUIContent("Bend compliance Y"));
+ EditorGUILayout.PropertyField(plasticYield, new GUIContent("Plastic yield"));
+ EditorGUILayout.PropertyField(plasticCreep, new GUIContent("Plastic creep"));
+ });
+
+ ObiEditorUtils.DoToggleablePropertyGroup(aerodynamicsEnabled, new GUIContent("Aerodynamics", Resources.Load("Icons/ObiAerodynamicConstraints Icon")),
+ () => {
+ EditorGUILayout.PropertyField(drag, new GUIContent("Drag"));
+ EditorGUILayout.PropertyField(lift, new GUIContent("Lift"));
+ });
+
+ ObiEditorUtils.DoToggleablePropertyGroup(chainConstraintsEnabled, new GUIContent("Chain Constraints", Resources.Load("Icons/ObiChainConstraints Icon")),
+ () => {
+ EditorGUILayout.PropertyField(tightness, new GUIContent("Tightness"));
+ });
+
+
+ if (GUI.changed)
+ serializedObject.ApplyModifiedProperties();
+
+ }
+
+ [DrawGizmo(GizmoType.Selected)]
+ private static void DrawGizmos(ObiRod actor, GizmoType gizmoType)
+ {
+ Handles.color = Color.white;
+ if (actor.rodBlueprint != null)
+ ObiPathHandles.DrawPathHandle(actor.rodBlueprint.path, actor.transform.localToWorldMatrix, actor.rodBlueprint.thickness ,20);
+ }
+
+ }
+
+}
+
+
diff --git a/Assets/Obi/Editor/RopeAndRod/ObiRodEditor.cs.meta b/Assets/Obi/Editor/RopeAndRod/ObiRodEditor.cs.meta
new file mode 100644
index 000000000..43404e2f0
--- /dev/null
+++ b/Assets/Obi/Editor/RopeAndRod/ObiRodEditor.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: d55c0f03ad50c414cacd39520aef2087
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/RopeAndRod/ObiRopeChainRendererEditor.cs b/Assets/Obi/Editor/RopeAndRod/ObiRopeChainRendererEditor.cs
new file mode 100644
index 000000000..76570ef57
--- /dev/null
+++ b/Assets/Obi/Editor/RopeAndRod/ObiRopeChainRendererEditor.cs
@@ -0,0 +1,54 @@
+using UnityEditor;
+using UnityEngine;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace Obi{
+
+ [CustomEditor(typeof(ObiRopeChainRenderer)), CanEditMultipleObjects]
+ public class ObiRopeChainRendererEditor : Editor
+ {
+
+ ObiRopeChainRenderer renderer;
+
+ public void OnEnable(){
+ renderer = (ObiRopeChainRenderer)target;
+ }
+
+ [MenuItem("CONTEXT/ObiRopeChainRenderer/Bake mesh")]
+ static void Bake(MenuCommand command)
+ {
+ ObiRopeChainRenderer renderer = (ObiRopeChainRenderer)command.context;
+
+ if (renderer.actor.isLoaded)
+ {
+ var system = renderer.actor.solver.GetRenderSystem() as ObiChainRopeRenderSystem;
+
+ if (system != null)
+ {
+ var mesh = new Mesh();
+ system.BakeMesh(renderer, ref mesh, true);
+ ObiEditorUtils.SaveMesh(mesh, "Save chain mesh", "chain mesh");
+ GameObject.DestroyImmediate(mesh);
+ }
+ }
+ }
+
+ public override void OnInspectorGUI() {
+
+ serializedObject.UpdateIfRequiredOrScript();
+
+ Editor.DrawPropertiesExcluding(serializedObject,"m_Script");
+
+ // Apply changes to the serializedProperty
+ if (GUI.changed){
+
+ serializedObject.ApplyModifiedProperties();
+ }
+
+ }
+
+ }
+}
+
diff --git a/Assets/Obi/Editor/RopeAndRod/ObiRopeChainRendererEditor.cs.meta b/Assets/Obi/Editor/RopeAndRod/ObiRopeChainRendererEditor.cs.meta
new file mode 100644
index 000000000..f99530421
--- /dev/null
+++ b/Assets/Obi/Editor/RopeAndRod/ObiRopeChainRendererEditor.cs.meta
@@ -0,0 +1,13 @@
+fileFormatVersion: 2
+guid: 0efaf4d397fcc4b87842866f9a69f07b
+labels:
+- ObiRope
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/RopeAndRod/ObiRopeCursorEditor.cs b/Assets/Obi/Editor/RopeAndRod/ObiRopeCursorEditor.cs
new file mode 100644
index 000000000..f902539de
--- /dev/null
+++ b/Assets/Obi/Editor/RopeAndRod/ObiRopeCursorEditor.cs
@@ -0,0 +1,99 @@
+using UnityEditor;
+using UnityEngine;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace Obi
+{
+
+ [CustomEditor(typeof(ObiRopeCursor)), CanEditMultipleObjects]
+ public class ObiRopeCursorEditor : Editor
+ {
+ SerializedProperty cursorMu;
+ SerializedProperty sourceMu;
+ SerializedProperty direction;
+
+ public void OnEnable()
+ {
+ cursorMu = serializedObject.FindProperty("m_CursorMu");
+ sourceMu = serializedObject.FindProperty("m_SourceMu");
+ direction = serializedObject.FindProperty("direction");
+ }
+
+ public override void OnInspectorGUI()
+ {
+ serializedObject.UpdateIfRequiredOrScript();
+
+ EditorGUI.BeginChangeCheck();
+ EditorGUILayout.PropertyField(cursorMu);
+ if (EditorGUI.EndChangeCheck())
+ {
+ foreach (var t in targets)
+ (t as ObiRopeCursor).UpdateCursor();
+ }
+
+ EditorGUI.BeginChangeCheck();
+ EditorGUILayout.PropertyField(sourceMu);
+ if (EditorGUI.EndChangeCheck())
+ {
+ foreach (var t in targets)
+ (t as ObiRopeCursor).UpdateSource();
+ }
+
+ EditorGUILayout.PropertyField(direction);
+
+ // Apply changes to the serializedProperty
+ if (GUI.changed)
+ serializedObject.ApplyModifiedProperties();
+
+ }
+
+ private static void DrawArrow()
+ {
+ Gizmos.DrawLine(Vector3.left, Vector3.up);
+ Gizmos.DrawLine(Vector3.right, Vector3.up);
+ Gizmos.DrawLine(Vector3.left, Vector3.down);
+ Gizmos.DrawLine(Vector3.right, Vector3.down);
+ Gizmos.DrawLine(Vector3.left, Vector3.forward);
+ Gizmos.DrawLine(Vector3.right, Vector3.forward);
+ Gizmos.DrawLine(Vector3.up, Vector3.forward);
+ Gizmos.DrawLine(Vector3.down, Vector3.forward);
+ }
+
+ [DrawGizmo(GizmoType.Selected)]
+ private static void DrawGizmos(ObiRopeCursor cursor, GizmoType gizmoType)
+ {
+ var rope = cursor.GetComponent();
+ if (rope.isLoaded)
+ {
+ Handles.matrix = rope.solver.transform.localToWorldMatrix;
+ Handles.color = new Color(1, 0.5f, 0.2f, 1);
+
+ // draw source particle:
+ int sourceIndex = cursor.sourceParticleIndex;
+
+ if (sourceIndex >= 0 && rope.IsParticleActive(rope.solver.particleToActor[sourceIndex].indexInActor))
+ {
+ Vector3 pos = rope.solver.positions[sourceIndex];
+ float size = HandleUtility.GetHandleSize(pos) * 0.15f;
+ Handles.SphereHandleCap(0, pos, Quaternion.identity, size, EventType.Repaint);
+ }
+
+ // draw cursor:
+ var element = cursor.cursorElement;
+
+ if (element != null && element.particle1 != element.particle2)
+ {
+ Vector3 pos = rope.solver.positions[cursor.direction ? element.particle1 : element.particle2];
+ Vector3 pos2 = rope.solver.positions[cursor.direction ? element.particle2 : element.particle1];
+ Vector3 direction = pos2 - pos;
+
+ float size = HandleUtility.GetHandleSize(pos) * 0.25f;
+ Handles.ConeHandleCap(0, pos + Vector3.Normalize(direction)*size*0.5f, Quaternion.LookRotation(direction), size, EventType.Repaint);
+ }
+ }
+ }
+ }
+}
+
diff --git a/Assets/Obi/Editor/RopeAndRod/ObiRopeCursorEditor.cs.meta b/Assets/Obi/Editor/RopeAndRod/ObiRopeCursorEditor.cs.meta
new file mode 100644
index 000000000..f740a0b2a
--- /dev/null
+++ b/Assets/Obi/Editor/RopeAndRod/ObiRopeCursorEditor.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: e3ec1bf77ba7a47b596abdc62069c72b
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/RopeAndRod/ObiRopeEditor.cs b/Assets/Obi/Editor/RopeAndRod/ObiRopeEditor.cs
new file mode 100644
index 000000000..9d18998bb
--- /dev/null
+++ b/Assets/Obi/Editor/RopeAndRod/ObiRopeEditor.cs
@@ -0,0 +1,219 @@
+using UnityEditor;
+using UnityEditor.EditorTools;
+using UnityEngine;
+
+namespace Obi
+{
+
+ [CustomEditor(typeof(ObiRope))]
+ public class ObiRopeEditor : Editor
+ {
+
+ [MenuItem("GameObject/3D Object/Obi/Obi Rope", false, 300)]
+ static void CreateObiRope(MenuCommand menuCommand)
+ {
+ GameObject go = new GameObject("Obi Rope", typeof(ObiRope), typeof(ObiRopeExtrudedRenderer));
+ var renderer = go.GetComponent();
+ renderer.material = ObiEditorUtils.GetDefaultMaterial();
+ ObiEditorUtils.PlaceActorRoot(go, menuCommand);
+ }
+
+ ObiRope actor;
+
+ SerializedProperty ropeBlueprint;
+
+ SerializedProperty collisionMaterial;
+ SerializedProperty selfCollisions;
+ SerializedProperty surfaceCollisions;
+ SerializedProperty massScale;
+
+ SerializedProperty distanceConstraintsEnabled;
+ SerializedProperty stretchingScale;
+ SerializedProperty stretchCompliance;
+ SerializedProperty maxCompression;
+
+ SerializedProperty bendConstraintsEnabled;
+ SerializedProperty bendCompliance;
+ SerializedProperty maxBending;
+ SerializedProperty plasticYield;
+ SerializedProperty plasticCreep;
+
+ SerializedProperty aerodynamicsEnabled;
+ SerializedProperty drag;
+ SerializedProperty lift;
+
+ SerializedProperty tearingEnabled;
+ SerializedProperty tearResistanceMultiplier;
+ SerializedProperty tearRate;
+
+ GUIStyle editLabelStyle;
+
+ public void OnEnable()
+ {
+ actor = (ObiRope)target;
+
+ ropeBlueprint = serializedObject.FindProperty("m_RopeBlueprint");
+
+ collisionMaterial = serializedObject.FindProperty("m_CollisionMaterial");
+ selfCollisions = serializedObject.FindProperty("m_SelfCollisions");
+ surfaceCollisions = serializedObject.FindProperty("m_SurfaceCollisions");
+ massScale = serializedObject.FindProperty("m_MassScale");
+
+ distanceConstraintsEnabled = serializedObject.FindProperty("_distanceConstraintsEnabled");
+ stretchingScale = serializedObject.FindProperty("_stretchingScale");
+ stretchCompliance = serializedObject.FindProperty("_stretchCompliance");
+ maxCompression = serializedObject.FindProperty("_maxCompression");
+
+ bendConstraintsEnabled = serializedObject.FindProperty("_bendConstraintsEnabled");
+ bendCompliance = serializedObject.FindProperty("_bendCompliance");
+ maxBending = serializedObject.FindProperty("_maxBending");
+ plasticYield = serializedObject.FindProperty("_plasticYield");
+ plasticCreep = serializedObject.FindProperty("_plasticCreep");
+
+ aerodynamicsEnabled = serializedObject.FindProperty("_aerodynamicsEnabled");
+ drag = serializedObject.FindProperty("_drag");
+ lift = serializedObject.FindProperty("_lift");
+
+ tearingEnabled = serializedObject.FindProperty("tearingEnabled");
+ tearResistanceMultiplier = serializedObject.FindProperty("tearResistanceMultiplier");
+ tearRate = serializedObject.FindProperty("tearRate");
+
+ }
+
+ private void DoEditButton()
+ {
+ using (new EditorGUI.DisabledScope(actor.ropeBlueprint == null))
+ {
+ EditorGUILayout.BeginHorizontal();
+ GUILayout.Space(EditorGUIUtility.labelWidth);
+ EditorGUI.BeginChangeCheck();
+ bool edit = GUILayout.Toggle(ToolManager.activeToolType == typeof(ObiPathEditor), new GUIContent(Resources.Load("EditCurves")), "Button", GUILayout.MaxWidth(36), GUILayout.MaxHeight(24));
+ EditorGUILayout.LabelField("Edit path", editLabelStyle, GUILayout.ExpandHeight(true), GUILayout.MaxHeight(24));
+ if (EditorGUI.EndChangeCheck())
+ {
+ if (edit)
+ ToolManager.SetActiveTool();
+ else
+ ToolManager.RestorePreviousPersistentTool();
+
+ SceneView.RepaintAll();
+ }
+ EditorGUILayout.EndHorizontal();
+ }
+ }
+
+ public override void OnInspectorGUI()
+ {
+ if (editLabelStyle == null)
+ {
+ editLabelStyle = new GUIStyle(GUI.skin.label);
+ editLabelStyle.alignment = TextAnchor.MiddleLeft;
+ }
+
+ serializedObject.UpdateIfRequiredOrScript();
+
+ if (actor.sourceBlueprint != null && actor.ropeBlueprint.path.ControlPointCount < 2)
+ {
+ actor.ropeBlueprint.GenerateImmediate();
+ }
+
+ using (new EditorGUI.DisabledScope(ToolManager.activeToolType == typeof(ObiPathEditor)))
+ {
+ GUILayout.BeginHorizontal();
+ EditorGUI.BeginChangeCheck();
+
+ EditorGUILayout.PropertyField(ropeBlueprint, new GUIContent("Blueprint"));
+
+ if (actor.ropeBlueprint == null)
+ {
+ if (GUILayout.Button("Create", EditorStyles.miniButton, GUILayout.MaxWidth(80)))
+ {
+ string path = EditorUtility.SaveFilePanel("Save blueprint", "Assets/", "RopeBlueprint", "asset");
+ if (!string.IsNullOrEmpty(path))
+ {
+ path = FileUtil.GetProjectRelativePath(path);
+ ObiRopeBlueprint asset = ScriptableObject.CreateInstance();
+
+ AssetDatabase.CreateAsset(asset, path);
+ AssetDatabase.SaveAssets();
+
+ actor.ropeBlueprint = asset;
+ }
+ }
+ }
+
+ if (EditorGUI.EndChangeCheck())
+ {
+ foreach (var t in targets)
+ {
+ (t as ObiRope).RemoveFromSolver();
+ (t as ObiRope).ClearState();
+ }
+ serializedObject.ApplyModifiedProperties();
+ foreach (var t in targets)
+ (t as ObiRope).AddToSolver();
+ }
+
+ GUILayout.EndHorizontal();
+ }
+
+ GUI.enabled = !Application.isPlaying;
+ EditorGUILayout.PropertyField(massScale, new GUIContent("Mass scale"));
+ GUI.enabled = true;
+
+ DoEditButton();
+
+ EditorGUILayout.Space();
+ EditorGUILayout.LabelField("Collisions", EditorStyles.boldLabel);
+ EditorGUILayout.PropertyField(collisionMaterial, new GUIContent("Collision material"));
+ EditorGUILayout.PropertyField(selfCollisions, new GUIContent("Self collisions"));
+ EditorGUILayout.PropertyField(surfaceCollisions, new GUIContent("Surface-based collisions"));
+
+ EditorGUILayout.Space();
+ ObiEditorUtils.DoToggleablePropertyGroup(tearingEnabled, new GUIContent("Tearing"),
+ () =>
+ {
+ EditorGUILayout.PropertyField(tearResistanceMultiplier, new GUIContent("Tear resistance"));
+ EditorGUILayout.PropertyField(tearRate, new GUIContent("Tear rate"));
+ });
+ ObiEditorUtils.DoToggleablePropertyGroup(distanceConstraintsEnabled, new GUIContent("Distance Constraints", Resources.Load("Icons/ObiDistanceConstraints Icon")),
+ () =>
+ {
+ EditorGUILayout.PropertyField(stretchingScale, new GUIContent("Stretching scale"));
+ EditorGUILayout.PropertyField(stretchCompliance, new GUIContent("Stretch compliance"));
+ EditorGUILayout.PropertyField(maxCompression, new GUIContent("Max compression"));
+ });
+
+ ObiEditorUtils.DoToggleablePropertyGroup(bendConstraintsEnabled, new GUIContent("Bend Constraints", Resources.Load("Icons/ObiBendConstraints Icon")),
+ () =>
+ {
+ EditorGUILayout.PropertyField(bendCompliance, new GUIContent("Bend compliance"));
+ EditorGUILayout.PropertyField(maxBending, new GUIContent("Max bending"));
+ EditorGUILayout.PropertyField(plasticYield, new GUIContent("Plastic yield"));
+ EditorGUILayout.PropertyField(plasticCreep, new GUIContent("Plastic creep"));
+ });
+
+ ObiEditorUtils.DoToggleablePropertyGroup(aerodynamicsEnabled, new GUIContent("Aerodynamics", Resources.Load("Icons/ObiAerodynamicConstraints Icon")),
+ () => {
+ EditorGUILayout.PropertyField(drag, new GUIContent("Drag"));
+ EditorGUILayout.PropertyField(lift, new GUIContent("Lift"));
+ });
+
+ if (GUI.changed)
+ serializedObject.ApplyModifiedProperties();
+
+ }
+
+ [DrawGizmo(GizmoType.Selected)]
+ private static void DrawGizmos(ObiRope actor, GizmoType gizmoType)
+ {
+ Handles.color = Color.white;
+ if (actor.ropeBlueprint != null)
+ ObiPathHandles.DrawPathHandle(actor.ropeBlueprint.path, actor.transform.localToWorldMatrix, actor.ropeBlueprint.thickness, 20, false);
+ }
+
+ }
+
+}
+
+
diff --git a/Assets/Obi/Editor/RopeAndRod/ObiRopeEditor.cs.meta b/Assets/Obi/Editor/RopeAndRod/ObiRopeEditor.cs.meta
new file mode 100644
index 000000000..78df88c8d
--- /dev/null
+++ b/Assets/Obi/Editor/RopeAndRod/ObiRopeEditor.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: b7e5f7e0daf504c86885734478e9c965
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/RopeAndRod/ObiRopeExtrudedRendererEditor.cs b/Assets/Obi/Editor/RopeAndRod/ObiRopeExtrudedRendererEditor.cs
new file mode 100644
index 000000000..02a4983f0
--- /dev/null
+++ b/Assets/Obi/Editor/RopeAndRod/ObiRopeExtrudedRendererEditor.cs
@@ -0,0 +1,55 @@
+using UnityEditor;
+using UnityEngine;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace Obi{
+
+ [CustomEditor(typeof(ObiRopeExtrudedRenderer)), CanEditMultipleObjects]
+ public class ObiRopeExtrudedRendererEditor : Editor
+ {
+
+ ObiRopeExtrudedRenderer renderer;
+
+ public void OnEnable(){
+ renderer = (ObiRopeExtrudedRenderer)target;
+ }
+
+ [MenuItem("CONTEXT/ObiRopeExtrudedRenderer/Bake mesh")]
+ static void Bake(MenuCommand command)
+ {
+ ObiRopeExtrudedRenderer renderer = (ObiRopeExtrudedRenderer)command.context;
+
+ if (renderer.actor.isLoaded)
+ {
+ var system = renderer.actor.solver.GetRenderSystem() as ObiExtrudedRopeRenderSystem;
+
+ if (system != null)
+ {
+ var mesh = new Mesh();
+ system.BakeMesh(renderer, ref mesh, true);
+ ObiEditorUtils.SaveMesh(mesh, "Save rope mesh", "rope mesh");
+ GameObject.DestroyImmediate(mesh);
+ }
+ }
+ }
+
+ public override void OnInspectorGUI() {
+
+ serializedObject.UpdateIfRequiredOrScript();
+
+ Editor.DrawPropertiesExcluding(serializedObject,"m_Script");
+
+ // Apply changes to the serializedProperty
+ if (GUI.changed){
+
+ serializedObject.ApplyModifiedProperties();
+
+ }
+
+ }
+
+ }
+}
+
diff --git a/Assets/Obi/Editor/RopeAndRod/ObiRopeExtrudedRendererEditor.cs.meta b/Assets/Obi/Editor/RopeAndRod/ObiRopeExtrudedRendererEditor.cs.meta
new file mode 100644
index 000000000..50deeab9a
--- /dev/null
+++ b/Assets/Obi/Editor/RopeAndRod/ObiRopeExtrudedRendererEditor.cs.meta
@@ -0,0 +1,13 @@
+fileFormatVersion: 2
+guid: 0d0e145ce66cd47e798bf4b926eddfc2
+labels:
+- ObiRope
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/RopeAndRod/ObiRopeLineRendererEditor.cs b/Assets/Obi/Editor/RopeAndRod/ObiRopeLineRendererEditor.cs
new file mode 100644
index 000000000..586d69b18
--- /dev/null
+++ b/Assets/Obi/Editor/RopeAndRod/ObiRopeLineRendererEditor.cs
@@ -0,0 +1,38 @@
+using UnityEditor;
+using UnityEngine;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace Obi{
+
+ [CustomEditor(typeof(ObiRopeLineRenderer)), CanEditMultipleObjects]
+ public class ObiRopeLineRendererEditor : Editor
+ {
+
+ ObiRopeLineRenderer renderer;
+
+ public void OnEnable(){
+ renderer = (ObiRopeLineRenderer)target;
+ }
+
+ public override void OnInspectorGUI() {
+
+ serializedObject.UpdateIfRequiredOrScript();
+
+ Editor.DrawPropertiesExcluding(serializedObject,"m_Script");
+
+ // Apply changes to the serializedProperty
+ if (GUI.changed){
+
+ serializedObject.ApplyModifiedProperties();
+
+ //renderer.UpdateRenderer(null);
+
+ }
+
+ }
+
+ }
+}
+
diff --git a/Assets/Obi/Editor/RopeAndRod/ObiRopeLineRendererEditor.cs.meta b/Assets/Obi/Editor/RopeAndRod/ObiRopeLineRendererEditor.cs.meta
new file mode 100644
index 000000000..5accc43c8
--- /dev/null
+++ b/Assets/Obi/Editor/RopeAndRod/ObiRopeLineRendererEditor.cs.meta
@@ -0,0 +1,13 @@
+fileFormatVersion: 2
+guid: c0a72c38772bb454dabc7efc5b8f03be
+labels:
+- ObiRope
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/RopeAndRod/ObiRopeMeshRendererEditor.cs b/Assets/Obi/Editor/RopeAndRod/ObiRopeMeshRendererEditor.cs
new file mode 100644
index 000000000..2d110592d
--- /dev/null
+++ b/Assets/Obi/Editor/RopeAndRod/ObiRopeMeshRendererEditor.cs
@@ -0,0 +1,52 @@
+using UnityEditor;
+using UnityEngine;
+
+namespace Obi{
+
+ [CustomEditor(typeof(ObiRopeMeshRenderer)), CanEditMultipleObjects]
+ public class ObiRopeMeshRendererEditor : Editor
+ {
+
+ ObiRopeMeshRenderer renderer;
+
+ [MenuItem("CONTEXT/ObiRopeMeshRenderer/Bake mesh")]
+ static void Bake(MenuCommand command)
+ {
+ ObiRopeMeshRenderer renderer = (ObiRopeMeshRenderer)command.context;
+
+ if (renderer.actor.isLoaded)
+ {
+ var system = renderer.actor.solver.GetRenderSystem() as ObiMeshRopeRenderSystem;
+
+ if (system != null)
+ {
+ var mesh = new Mesh();
+ system.BakeMesh(renderer, ref mesh, true);
+ ObiEditorUtils.SaveMesh(mesh, "Save rope mesh", "rope mesh");
+ GameObject.DestroyImmediate(mesh);
+ }
+ }
+ }
+
+ public void OnEnable(){
+ renderer = (ObiRopeMeshRenderer)target;
+ }
+
+ public override void OnInspectorGUI() {
+
+ serializedObject.UpdateIfRequiredOrScript();
+
+ Editor.DrawPropertiesExcluding(serializedObject,"m_Script");
+
+ // Apply changes to the serializedProperty
+ if (GUI.changed){
+
+ serializedObject.ApplyModifiedProperties();
+
+ }
+
+ }
+
+ }
+}
+
diff --git a/Assets/Obi/Editor/RopeAndRod/ObiRopeMeshRendererEditor.cs.meta b/Assets/Obi/Editor/RopeAndRod/ObiRopeMeshRendererEditor.cs.meta
new file mode 100644
index 000000000..6a6c6a27a
--- /dev/null
+++ b/Assets/Obi/Editor/RopeAndRod/ObiRopeMeshRendererEditor.cs.meta
@@ -0,0 +1,13 @@
+fileFormatVersion: 2
+guid: 297abfc8979aa46329f3a7e914866adc
+labels:
+- ObiRope
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/RopeAndRod/ObiRopeSectionEditor.cs b/Assets/Obi/Editor/RopeAndRod/ObiRopeSectionEditor.cs
new file mode 100644
index 000000000..b5c6fe481
--- /dev/null
+++ b/Assets/Obi/Editor/RopeAndRod/ObiRopeSectionEditor.cs
@@ -0,0 +1,213 @@
+using UnityEditor;
+using UnityEngine;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace Obi{
+
+ /**
+ * Custom inspector for ObiParticleRenderer component.
+ */
+
+ [CustomEditor(typeof(ObiRopeSection))]
+ public class ObiRopeSectionEditor : Editor
+ {
+
+ ObiRopeSection section;
+ bool[] selected = new bool[0];
+
+ Color previewBck = new Color(0.2f,0.2f,0.2f,1);
+ Color previewLines = new Color(0.15f,0.15f,0.15f,1);
+
+ public void OnEnable(){
+ section = (ObiRopeSection)target;
+ }
+
+ public override bool HasPreviewGUI(){
+ return true;
+ }
+
+ private void ResetSelection(){
+ selected = new bool[section.Segments];
+ }
+
+ public override void OnInspectorGUI() {
+
+ serializedObject.UpdateIfRequiredOrScript();
+
+ Editor.DrawPropertiesExcluding(serializedObject,"m_Script");
+
+ GUI.enabled = !EditorApplication.isPlaying;
+ GUILayout.Label("Presets");
+
+ GUILayout.BeginHorizontal();
+ if (GUILayout.Button("4-segment circle")){
+ Undo.RecordObject(section, "Set rope section preset");
+ section.CirclePreset(4);
+ ResetSelection();
+ }
+
+ if (GUILayout.Button("8-segment circle")){
+ Undo.RecordObject(section, "Set rope section preset");
+ section.CirclePreset(8);
+ ResetSelection();
+ }
+ GUILayout.EndHorizontal();
+
+ GUILayout.BeginHorizontal();
+ if (GUILayout.Button("12-segment circle")){
+ Undo.RecordObject(section, "Set rope section preset");
+ section.CirclePreset(12);
+ ResetSelection();
+ }
+
+ if (GUILayout.Button("16-segment circle")){
+ Undo.RecordObject(section, "Set rope section preset");
+ section.CirclePreset(16);
+ ResetSelection();
+ }
+ GUILayout.EndHorizontal();
+
+ GUILayout.Label("Tools");
+ if (GUILayout.Button("Add vertex")){
+ Undo.RecordObject(section, "Add rope vertex");
+ section.vertices.Add(Vector2.zero);
+ }
+
+ if (GUILayout.Button("Remove selected vertices")){
+ Undo.RecordObject(section, "Remove rope vertices");
+ for (int i = selected.Length-1; i > 0; --i){
+ if (selected[i] && section.vertices.Count > 3)
+ section.vertices.RemoveAt(i);
+ }
+ // special cases: first vertex:
+ if (selected[0] && section.vertices.Count > 3){
+ section.vertices.RemoveAt(0);
+ section.vertices[section.vertices.Count-1] = section.vertices[0];
+ }
+
+ ResetSelection();
+ }
+ GUI.enabled = true;
+
+ // Apply changes to the serializedProperty
+ if (GUI.changed){
+ serializedObject.ApplyModifiedProperties();
+ EditorUtility.SetDirty(target);
+ }
+
+ }
+
+ private void DrawSectionOutline(Rect region, Color color){
+ // Draw segment lines:
+ Handles.BeginGUI( );
+ Color oldColor = Handles.color;
+ Handles.color = color;
+ Vector3[] points = new Vector3[section.vertices.Count];
+ for (int i = 0; i < section.vertices.Count; i++){
+ points[i] = new Vector3(region.center.x + section.vertices[i].x * region.width * 0.5f,
+ region.center.y + section.vertices[i].y * region.height * 0.5f,0);
+ }
+ Handles.DrawAAPolyLine(points);
+ Handles.EndGUI();
+ Handles.color = oldColor;
+ }
+
+ private void DrawDrawingArea(Rect region){
+ // Draw drawing area grid:
+ Handles.BeginGUI();
+ Handles.DrawSolidRectangleWithOutline(region,previewBck,previewLines);
+
+ Color oldColor = Handles.color;
+ Handles.color = previewLines;
+
+ if (section.snapX > 5){
+ float x = region.center.x;
+ while (x < region.xMax){
+ Handles.DrawLine(new Vector3(x,region.yMin,0),new Vector3(x,region.yMax,0));
+ x += section.snapX;
+ }
+ x = region.center.x - section.snapX;
+ while (x > region.xMin){
+ Handles.DrawLine(new Vector3(x,region.yMin,0),new Vector3(x,region.yMax,0));
+ x -= section.snapX;
+ }
+ }
+
+ if (section.snapY > 5){
+ float y = region.center.y;
+ while (y < region.yMax){
+ Handles.DrawLine(new Vector3(region.xMin,y,0),new Vector3(region.xMax,y,0));
+ y += section.snapY;
+ }
+ y = region.center.y - section.snapY;
+ while (y > region.yMin){
+ Handles.DrawLine(new Vector3(region.xMin,y,0),new Vector3(region.xMax,y,0));
+ y -= section.snapY;
+ }
+ }
+
+ Handles.color = oldColor;
+ Handles.EndGUI();
+ }
+
+ public override void OnPreviewGUI(Rect region, GUIStyle background)
+ {
+ DrawSectionOutline(region, Color.red);
+ }
+
+ public override void OnInteractivePreviewGUI(Rect region, GUIStyle background)
+ {
+ Array.Resize(ref selected,section.Segments);
+
+ // Calculate drawing area rect:
+ Vector2 oldCenter = region.center;
+ if (region.width > region.height)
+ region.width = region.height;
+ if (region.height > region.width)
+ region.height = region.width;
+
+ region.width -= 10;
+ region.height -= 15;
+
+ region.center = oldCenter;
+
+ // Draw background and lines:
+ DrawDrawingArea(region);
+
+ // Draw the section outline:
+ DrawSectionOutline(region, Color.white);
+
+ // Draw all draggable vertices:
+ for (int i = 0; i < section.Segments; i++){
+
+ float x = region.center.x + section.vertices[i].x * region.width * 0.5f;
+ float y = region.center.y + section.vertices[i].y * region.height * 0.5f;
+ Vector2 pos = new Vector2(x,y);
+
+ bool oldSelection = selected[i];
+ Vector2 olsPos = pos;
+ selected[i] = ObiDraggableIcon.Draw(selected[i],i,ref pos,Color.red);
+
+ if (selected[i] != oldSelection)
+ this.Repaint();
+
+ if (pos != olsPos){
+
+ pos.x = Mathf.Clamp(ObiRopeSection.SnapTo(pos.x - region.center.x,section.snapX,5) / (region.width * 0.5f),-1,1);
+ pos.y = Mathf.Clamp(ObiRopeSection.SnapTo(pos.y - region.center.y,section.snapY,5) / (region.height * 0.5f),-1,1);
+ section.vertices[i] = pos;
+ if (i == 0)
+ section.vertices[section.Segments] = pos;
+
+ EditorUtility.SetDirty(target);
+ }
+ }
+
+ }
+
+ }
+
+}
+
diff --git a/Assets/Obi/Editor/RopeAndRod/ObiRopeSectionEditor.cs.meta b/Assets/Obi/Editor/RopeAndRod/ObiRopeSectionEditor.cs.meta
new file mode 100644
index 000000000..c12c5c628
--- /dev/null
+++ b/Assets/Obi/Editor/RopeAndRod/ObiRopeSectionEditor.cs.meta
@@ -0,0 +1,13 @@
+fileFormatVersion: 2
+guid: 1539d8c58261942e28859228dfa310fb
+labels:
+- ObiRope
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/RopeAndRod/Utils.meta b/Assets/Obi/Editor/RopeAndRod/Utils.meta
new file mode 100644
index 000000000..9115ebae6
--- /dev/null
+++ b/Assets/Obi/Editor/RopeAndRod/Utils.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 72e3dd3ad91bf485099095b5e59ff81b
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Editor/RopeAndRod/Utils/ObiPinholeEditor.cs b/Assets/Obi/Editor/RopeAndRod/Utils/ObiPinholeEditor.cs
new file mode 100644
index 000000000..f2380581a
--- /dev/null
+++ b/Assets/Obi/Editor/RopeAndRod/Utils/ObiPinholeEditor.cs
@@ -0,0 +1,169 @@
+using UnityEditor;
+using UnityEditorInternal;
+using UnityEngine;
+using System.Collections.Generic;
+using System.Linq;
+
+
+namespace Obi
+{
+
+ [CustomEditor(typeof(ObiPinhole))]
+ public class ObiPinholeEditor : Editor
+ {
+
+ SerializedProperty targetTransform;
+ SerializedProperty position;
+ SerializedProperty limitRange;
+ SerializedProperty range;
+ SerializedProperty compliance;
+ SerializedProperty friction;
+ SerializedProperty motorSpeed;
+ SerializedProperty motorForce;
+ SerializedProperty clamp;
+ SerializedProperty breakThreshold;
+
+ ObiPinhole pinhole;
+
+ public void OnEnable()
+ {
+
+ pinhole = target as ObiPinhole;
+ targetTransform = serializedObject.FindProperty("m_Target");
+ position = serializedObject.FindProperty("m_Position");
+ limitRange = serializedObject.FindProperty("m_LimitRange");
+ range = serializedObject.FindProperty("m_Range");
+ friction = serializedObject.FindProperty("m_Friction");
+ motorSpeed = serializedObject.FindProperty("m_MotorSpeed");
+ motorForce = serializedObject.FindProperty("m_MotorForce");
+ compliance = serializedObject.FindProperty("m_Compliance");
+ clamp = serializedObject.FindProperty("m_ClampAtEnds");
+ breakThreshold = serializedObject.FindProperty("breakThreshold");
+ }
+
+ public override void OnInspectorGUI()
+ {
+
+ serializedObject.UpdateIfRequiredOrScript();
+
+ // warn about incorrect setups:
+ if (!targetTransform.hasMultipleDifferentValues)
+ {
+ var targetValue = targetTransform.objectReferenceValue as UnityEngine.Component;
+ if (targetValue != null)
+ {
+ var collider = targetValue.GetComponent();
+ if (collider == null)
+ {
+ EditorGUILayout.HelpBox("Pinholes require the target object to have a ObiCollider component. Please add one.", MessageType.Warning);
+ }
+ }
+ }
+
+ EditorGUI.BeginChangeCheck();
+ Transform trget = EditorGUILayout.ObjectField("Target", pinhole.target, typeof(Transform), true) as Transform;
+ if (EditorGUI.EndChangeCheck())
+ {
+ Undo.RecordObject(pinhole, "Set target");
+ pinhole.target = trget;
+ PrefabUtility.RecordPrefabInstancePropertyModifications(pinhole);
+ }
+
+ EditorGUI.BeginChangeCheck();
+ EditorGUILayout.PropertyField(position, new GUIContent("Position"));
+ if (EditorGUI.EndChangeCheck())
+ {
+ serializedObject.ApplyModifiedProperties();
+ pinhole.CalculateMu();
+ }
+
+ EditorGUI.BeginChangeCheck();
+ EditorGUILayout.PropertyField(limitRange, new GUIContent("Limit Range"));
+ if (EditorGUI.EndChangeCheck())
+ {
+ serializedObject.ApplyModifiedProperties();
+ pinhole.CalculateRange();
+ }
+
+ if (limitRange.boolValue)
+ {
+ EditorGUI.indentLevel++;
+ EditorGUI.BeginChangeCheck();
+ EditorGUILayout.PropertyField(range, new GUIContent("Range"));
+ if (EditorGUI.EndChangeCheck())
+ {
+ serializedObject.ApplyModifiedProperties();
+ pinhole.CalculateRange();
+ }
+ EditorGUI.indentLevel--;
+ }
+ EditorGUILayout.PropertyField(clamp, new GUIContent("Clamp at ends"));
+ EditorGUILayout.PropertyField(friction, new GUIContent("Friction"));
+ EditorGUILayout.PropertyField(motorSpeed, new GUIContent("Motor Target Speed"));
+ EditorGUILayout.PropertyField(motorForce, new GUIContent("Motor Max Force"));
+ EditorGUILayout.PropertyField(compliance, new GUIContent("Compliance"));
+ EditorGUILayout.PropertyField(breakThreshold, new GUIContent("Break threshold"));
+
+ if (GUI.changed)
+ serializedObject.ApplyModifiedProperties();
+
+ }
+
+ [DrawGizmo(GizmoType.Selected)]
+ private static void DrawGizmos(ObiPinhole pinhole, GizmoType gizmoType)
+ {
+ var rope = pinhole.GetComponent();
+
+ var ropeBlueprint = rope.sharedBlueprint as ObiRopeBlueprintBase;
+ if (rope.isLoaded && ropeBlueprint != null && ropeBlueprint.deformableEdges != null)
+ {
+ Handles.color = new Color(1, 0.5f, 0.2f, 1);
+ Handles.matrix = rope.solver.transform.localToWorldMatrix;
+
+ // draw limits:
+ if (pinhole.limitRange)
+ {
+ for (int i = pinhole.firstEdge.edgeIndex; i <= pinhole.lastEdge.edgeIndex; ++i)
+ {
+ if (i >= 0 && i < ropeBlueprint.deformableEdges.Length)
+ {
+ int p1 = ropeBlueprint.deformableEdges[i * 2];
+ int p2 = ropeBlueprint.deformableEdges[i * 2 + 1];
+ var pos1 = rope.solver.positions[rope.solverIndices[p1]];
+ var pos2 = rope.solver.positions[rope.solverIndices[p2]];
+
+ if (i == pinhole.firstEdge.edgeIndex)
+ {
+ pos1 = Vector4.Lerp(pos1, pos2, pinhole.firstEdge.coordinate);
+ Handles.DrawSolidDisc(pos1, pos2 - pos1, HandleUtility.GetHandleSize(pos1) * 0.05f);
+ }
+ if (i == pinhole.lastEdge.edgeIndex)
+ {
+ pos2 = Vector4.Lerp(pos1, pos2, pinhole.lastEdge.coordinate);
+ Handles.DrawSolidDisc(pos2, pos1 - pos2, HandleUtility.GetHandleSize(pos2) * 0.05f);
+ }
+
+ Handles.DrawLine(pos1, pos2, 2);
+ }
+ }
+ }
+
+ // draw source particle:
+ int edgeIndex = pinhole.edgeIndex;
+
+ if (edgeIndex >= 0 && edgeIndex < ropeBlueprint.deformableEdges.Length)
+ {
+ int p1 = ropeBlueprint.deformableEdges[edgeIndex * 2];
+ int p2 = ropeBlueprint.deformableEdges[edgeIndex * 2 + 1];
+ var pos1 = rope.solver.positions[rope.solverIndices[p1]];
+ var pos2 = rope.solver.positions[rope.solverIndices[p2]];
+ Vector4 pos = Vector4.Lerp(pos1, pos2, pinhole.edgeCoordinate);
+ Handles.DrawWireDisc(pos, pos1 - pos2, HandleUtility.GetHandleSize(pos) * 0.1f, 2);
+ }
+ }
+ }
+ }
+
+}
+
+
diff --git a/Assets/Obi/Editor/RopeAndRod/Utils/ObiPinholeEditor.cs.meta b/Assets/Obi/Editor/RopeAndRod/Utils/ObiPinholeEditor.cs.meta
new file mode 100644
index 000000000..97fc35243
--- /dev/null
+++ b/Assets/Obi/Editor/RopeAndRod/Utils/ObiPinholeEditor.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: f58defb5faddb428ea91cd06eecd8729
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/QuickstartGuide_rope.pdf b/Assets/Obi/QuickstartGuide_rope.pdf
new file mode 100644
index 000000000..d2071e966
Binary files /dev/null and b/Assets/Obi/QuickstartGuide_rope.pdf differ
diff --git a/Assets/Obi/QuickstartGuide_rope.pdf.meta b/Assets/Obi/QuickstartGuide_rope.pdf.meta
new file mode 100644
index 000000000..0218f7a96
--- /dev/null
+++ b/Assets/Obi/QuickstartGuide_rope.pdf.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: dd3977598aee74c5eaa2111f3d999165
+labels:
+- ObiRope
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/README.rtf b/Assets/Obi/README.rtf
new file mode 100644
index 000000000..d6d71741c
--- /dev/null
+++ b/Assets/Obi/README.rtf
@@ -0,0 +1,38 @@
+{\rtf1\ansi\ansicpg1252\cocoartf2512
+\cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fmodern\fcharset0 Courier-Bold;\f1\fmodern\fcharset0 Courier;}
+{\colortbl;\red255\green255\blue255;}
+{\*\expandedcolortbl;;}
+\paperw11900\paperh16840\margl1440\margr1440\vieww23180\viewh10900\viewkind0
+\deftab720
+\pard\pardeftab720\partightenfactor0
+
+\f0\b\fs26 \cf0 \expnd0\expndtw0\kerning0
+OFFICIAL OBI WEBPAGE:\
+{\field{\*\fldinst{HYPERLINK "http://obi.virtualmethodstudio.com"}}{\fldrslt
+\f1\b0 http://obi.virtualmethodstudio.com}}\
+\
+OFFICIAL FORUM:\
+{\field{\*\fldinst{HYPERLINK "http://obi.virtualmethodstudio.com/forum"}}{\fldrslt
+\f1\b0 http://obi.virtualmethodstudio.com/forum}}\
+\
+CREDITS:
+\f1\b0 \
+\
+\ul Programming, design:\ulnone \
+Jos\'e9 Mar\'eda \'93ArK\'94 M\'e9ndez Gonz\'e1lez\
+\
+\ul Support, Community management and Web/Forum maintenance:\ulnone \
+Lidia Mart\'ednez Prado \
+\
+\ul Special thanks to:\ulnone \
+VargaPD (testing and debugging)\
+theANMATOR2b (testing)\
+Hanging Cui (testing, help with vectorization issues)\
+Janne Ramstedt (debugging and suggestions)\
+Tigrero Tiger (debugging)\
+Hatchling (feedback regarding collision filtering and spatial query API)\
+\
+all the folks at the Unity forums and of course, all Obi users.\
+\
+\
+}
\ No newline at end of file
diff --git a/Assets/Obi/README.rtf.meta b/Assets/Obi/README.rtf.meta
new file mode 100644
index 000000000..de9ed91b3
--- /dev/null
+++ b/Assets/Obi/README.rtf.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 133c58a050c6b404cb14cc72f0a1676c
+timeCreated: 1443155832
+licenseType: Store
+DefaultImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Resources.meta b/Assets/Obi/Resources.meta
new file mode 100644
index 000000000..0cc732a65
--- /dev/null
+++ b/Assets/Obi/Resources.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 6217e7f6fe8104bbca06fe7ac150a57d
+folderAsset: yes
+timeCreated: 1435572248
+licenseType: Store
+DefaultImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Resources/Compute.meta b/Assets/Obi/Resources/Compute.meta
new file mode 100644
index 000000000..054ac1346
--- /dev/null
+++ b/Assets/Obi/Resources/Compute.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 55c2294f77a2c4783b788be18cc01798
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Obi/Resources/Compute/AerodynamicConstraints.compute b/Assets/Obi/Resources/Compute/AerodynamicConstraints.compute
new file mode 100644
index 000000000..d51c3c4b9
--- /dev/null
+++ b/Assets/Obi/Resources/Compute/AerodynamicConstraints.compute
@@ -0,0 +1,61 @@
+#pragma kernel Project
+
+#include "MathUtils.cginc"
+#include "AtomicDeltas.cginc"
+
+StructuredBuffer particleIndices;
+StructuredBuffer aerodynamicCoeffs;
+
+StructuredBuffer