Initial commit
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c238225edea024c2b8df349394939c3f
|
||||
folderAsset: yes
|
||||
timeCreated: 1512691582
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 31d8d23c21c2346f489ea4b8ea895323
|
||||
folderAsset: yes
|
||||
timeCreated: 1438098821
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f21d9411463fe4c518583dc787a70979
|
||||
folderAsset: yes
|
||||
timeCreated: 1438293695
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 62249380d6a53419c8af2248825f2225
|
||||
folderAsset: yes
|
||||
timeCreated: 1463713534
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Двоичные данные
Assets/AssetStorePackage/Editor/Heatmaps/Resources/unity_analytics_heatmaps_failed.png
Executable file
После Ширина: | Высота: | Размер: 1.2 KiB |
|
@ -0,0 +1,77 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d821bcec251614db69b44f63017fb25d
|
||||
timeCreated: 1513116735
|
||||
licenseType: Pro
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
externalObjects: {}
|
||||
serializedVersion: 4
|
||||
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: 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: 0
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 0
|
||||
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
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Двоичные данные
Assets/AssetStorePackage/Editor/Heatmaps/Resources/unity_analytics_heatmaps_heatmapper.png
Normal file
После Ширина: | Высота: | Размер: 2.9 KiB |
|
@ -0,0 +1,77 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 970254eaca62b48c19ba2b8a37e4be59
|
||||
timeCreated: 1513116735
|
||||
licenseType: Pro
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
externalObjects: {}
|
||||
serializedVersion: 4
|
||||
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: 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: 0
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 0
|
||||
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
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Двоичные данные
Assets/AssetStorePackage/Editor/Heatmaps/Resources/unity_analytics_heatmaps_none_dark.png
Executable file
После Ширина: | Высота: | Размер: 1.1 KiB |
|
@ -0,0 +1,77 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7906aa478f2864ef797fea65323bdb02
|
||||
timeCreated: 1513116735
|
||||
licenseType: Pro
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
externalObjects: {}
|
||||
serializedVersion: 4
|
||||
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: 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: 0
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 0
|
||||
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
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Двоичные данные
Assets/AssetStorePackage/Editor/Heatmaps/Resources/unity_analytics_heatmaps_none_light.png
Executable file
После Ширина: | Высота: | Размер: 1.2 KiB |
|
@ -0,0 +1,77 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c043bd35ad4e247d8b78af8af7b7b540
|
||||
timeCreated: 1513116735
|
||||
licenseType: Pro
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
externalObjects: {}
|
||||
serializedVersion: 4
|
||||
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: 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: 0
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 0
|
||||
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
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Двоичные данные
Assets/AssetStorePackage/Editor/Heatmaps/Resources/unity_analytics_heatmaps_number_dark.png
Executable file
После Ширина: | Высота: | Размер: 1.0 KiB |
|
@ -0,0 +1,77 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2a10c22a4b3ba47eba457543b2797ccb
|
||||
timeCreated: 1513116735
|
||||
licenseType: Pro
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
externalObjects: {}
|
||||
serializedVersion: 4
|
||||
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: 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: 0
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 0
|
||||
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
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Двоичные данные
Assets/AssetStorePackage/Editor/Heatmaps/Resources/unity_analytics_heatmaps_number_light.png
Executable file
После Ширина: | Высота: | Размер: 1.1 KiB |
|
@ -0,0 +1,77 @@
|
|||
fileFormatVersion: 2
|
||||
guid: dbdd0a3bb4a5d49a883f6dac743718f7
|
||||
timeCreated: 1513116735
|
||||
licenseType: Pro
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
externalObjects: {}
|
||||
serializedVersion: 4
|
||||
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: 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: 0
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 0
|
||||
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
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Двоичные данные
Assets/AssetStorePackage/Editor/Heatmaps/Resources/unity_analytics_heatmaps_pause_dark.png
Executable file
После Ширина: | Высота: | Размер: 955 B |
|
@ -0,0 +1,77 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c813ef568cfc54e89975e3cba1865aee
|
||||
timeCreated: 1513116735
|
||||
licenseType: Pro
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
externalObjects: {}
|
||||
serializedVersion: 4
|
||||
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: 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: 0
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 0
|
||||
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
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Двоичные данные
Assets/AssetStorePackage/Editor/Heatmaps/Resources/unity_analytics_heatmaps_pause_light.png
Executable file
После Ширина: | Высота: | Размер: 966 B |
|
@ -0,0 +1,77 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 32974842b7e2246a39105589ec930963
|
||||
timeCreated: 1513116735
|
||||
licenseType: Pro
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
externalObjects: {}
|
||||
serializedVersion: 4
|
||||
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: 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: 0
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 0
|
||||
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
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Двоичные данные
Assets/AssetStorePackage/Editor/Heatmaps/Resources/unity_analytics_heatmaps_play_dark.png
Executable file
После Ширина: | Высота: | Размер: 1.0 KiB |
|
@ -0,0 +1,77 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 999e7e026af4f4b5a8a3c6d5880bbabc
|
||||
timeCreated: 1513116735
|
||||
licenseType: Pro
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
externalObjects: {}
|
||||
serializedVersion: 4
|
||||
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: 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: 0
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 0
|
||||
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
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Двоичные данные
Assets/AssetStorePackage/Editor/Heatmaps/Resources/unity_analytics_heatmaps_play_light.png
Executable file
После Ширина: | Высота: | Размер: 1.1 KiB |
|
@ -0,0 +1,77 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8820cc7d4dcda4e05aabae34844b5d04
|
||||
timeCreated: 1513116735
|
||||
licenseType: Pro
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
externalObjects: {}
|
||||
serializedVersion: 4
|
||||
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: 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: 0
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 0
|
||||
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
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Двоичные данные
Assets/AssetStorePackage/Editor/Heatmaps/Resources/unity_analytics_heatmaps_running.png
Executable file
После Ширина: | Высота: | Размер: 1.2 KiB |
|
@ -0,0 +1,77 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a50bbedf15844489ba5279bc4405f663
|
||||
timeCreated: 1513116735
|
||||
licenseType: Pro
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
externalObjects: {}
|
||||
serializedVersion: 4
|
||||
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: 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: 0
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 0
|
||||
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
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Двоичные данные
Assets/AssetStorePackage/Editor/Heatmaps/Resources/unity_analytics_heatmaps_rwd_dark.png
Executable file
После Ширина: | Высота: | Размер: 1.1 KiB |
|
@ -0,0 +1,77 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5101704bcea19466ea3d7aa5e596f026
|
||||
timeCreated: 1513116735
|
||||
licenseType: Pro
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
externalObjects: {}
|
||||
serializedVersion: 4
|
||||
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: 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: 0
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 0
|
||||
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
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Двоичные данные
Assets/AssetStorePackage/Editor/Heatmaps/Resources/unity_analytics_heatmaps_rwd_light.png
Executable file
После Ширина: | Высота: | Размер: 1.1 KiB |
|
@ -0,0 +1,77 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 929eceb046d7843acbd78dfd41913446
|
||||
timeCreated: 1513116735
|
||||
licenseType: Pro
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
externalObjects: {}
|
||||
serializedVersion: 4
|
||||
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: 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: 0
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 0
|
||||
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
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Двоичные данные
Assets/AssetStorePackage/Editor/Heatmaps/Resources/unity_analytics_heatmaps_success.png
Executable file
После Ширина: | Высота: | Размер: 1.2 KiB |
|
@ -0,0 +1,77 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 35f6382bad4c94fe98f3bae4c615f790
|
||||
timeCreated: 1513116735
|
||||
licenseType: Pro
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
externalObjects: {}
|
||||
serializedVersion: 4
|
||||
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: 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: 0
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 0
|
||||
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
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Двоичные данные
Assets/AssetStorePackage/Editor/Heatmaps/Resources/unity_analytics_heatmaps_union_dark.png
Executable file
|
@ -0,0 +1,77 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c19831b708ada4c39b5e9a118c3e72be
|
||||
timeCreated: 1513116735
|
||||
licenseType: Pro
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
externalObjects: {}
|
||||
serializedVersion: 4
|
||||
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: 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: 0
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 0
|
||||
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
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Двоичные данные
Assets/AssetStorePackage/Editor/Heatmaps/Resources/unity_analytics_heatmaps_union_light.png
Executable file
После Ширина: | Высота: | Размер: 15 KiB |
|
@ -0,0 +1,77 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 39ed6f06956bf4774809defcff5e0898
|
||||
timeCreated: 1513116735
|
||||
licenseType: Pro
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
externalObjects: {}
|
||||
serializedVersion: 4
|
||||
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: 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: 0
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 0
|
||||
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
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fc1aae7c6c4fe4030b056a8d2df57df3
|
||||
folderAsset: yes
|
||||
timeCreated: 1444707777
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,150 @@
|
|||
/// <summary>
|
||||
/// Inspector for the Aggregation portion of the Heatmapper.
|
||||
/// </summary>
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityAnalytics;
|
||||
using System.Linq;
|
||||
|
||||
namespace UnityAnalytics360VideoHeatmap
|
||||
{
|
||||
public class AggregationInspector
|
||||
{
|
||||
const string k_UseCustomDataPathKey = "UnityAnalyticsHeatmapUsePersistentDataPathKey";
|
||||
|
||||
string m_DataPath = "./";
|
||||
|
||||
HeatmapDataProcessor m_Processor;
|
||||
private GUIContent m_DataPathContent = new GUIContent("Input Path", "Where to retrieve data (defaults to Application.persistentDataPath");
|
||||
private GUIContent m_DatesContent = new GUIContent("Dates", "ISO-8601 datetimes (YYYY-MM-DD)");
|
||||
|
||||
string m_StartDate = "";
|
||||
string m_EndDate = "";
|
||||
bool m_ValidDates = true;
|
||||
|
||||
GUIStyle m_ValidDateStyle;
|
||||
GUIStyle m_InvalidDateStyle;
|
||||
|
||||
const int k_FetchInitValue = 30;
|
||||
|
||||
public AggregationInspector(HeatmapDataProcessor processor)
|
||||
{
|
||||
m_Processor = processor;
|
||||
}
|
||||
|
||||
public static AggregationInspector Init(HeatmapDataProcessor processor)
|
||||
{
|
||||
return new AggregationInspector(processor);
|
||||
}
|
||||
|
||||
public void OnEnable()
|
||||
{
|
||||
// Restore cached paths
|
||||
m_DataPath = m_Processor.m_RawDataPath;
|
||||
m_EndDate = m_Processor.m_EndDate;
|
||||
m_StartDate = m_Processor.m_StartDate;
|
||||
}
|
||||
|
||||
public void OnGUI()
|
||||
{
|
||||
if (m_ValidDateStyle == null)
|
||||
{
|
||||
m_ValidDateStyle = new GUIStyle("button");
|
||||
m_InvalidDateStyle = new GUIStyle("button");
|
||||
m_InvalidDateStyle.normal.textColor = Color.red;
|
||||
}
|
||||
|
||||
using (new GUILayout.VerticalScope())
|
||||
{
|
||||
EditorGUILayout.LabelField("Data", EditorStyles.boldLabel, GUILayout.Width(EditorGUIUtility.labelWidth - 4));
|
||||
|
||||
using (new GUILayout.HorizontalScope())
|
||||
{
|
||||
EditorGUILayout.LabelField(m_DataPathContent, GUILayout.Width(EditorGUIUtility.labelWidth - 4));
|
||||
m_DataPath = Application.dataPath;
|
||||
UseCustomDataPathChange(true);
|
||||
EditorGUILayout.SelectableLabel(m_DataPath + "/RawDataFolder", EditorStyles.textField, GUILayout.Height(EditorGUIUtility.singleLineHeight));
|
||||
}
|
||||
|
||||
using (new GUILayout.HorizontalScope())
|
||||
{
|
||||
EditorGUILayout.LabelField(m_DatesContent, GUILayout.Width(EditorGUIUtility.labelWidth - 4));
|
||||
|
||||
GUIStyle dateFieldStyle = m_ValidDates ? m_ValidDateStyle : m_InvalidDateStyle;
|
||||
dateFieldStyle.padding = new RectOffset(0, 0, ((int)EditorGUIUtility.singleLineHeight / 3), 0);
|
||||
m_StartDate = AnalyticsDatePicker.DatePicker(m_StartDate, dateFieldStyle, StartDateChange, DateFailure, DateValidationStart);
|
||||
m_EndDate = AnalyticsDatePicker.DatePicker(m_EndDate, dateFieldStyle, EndDateChange, DateFailure, DateValidationEnd);
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
}
|
||||
}
|
||||
|
||||
void UseCustomDataPathChange(bool value)
|
||||
{
|
||||
EditorPrefs.SetBool(k_UseCustomDataPathKey, value);
|
||||
DataPathChange(m_DataPath);
|
||||
}
|
||||
|
||||
void DataPathChange(string value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(value))
|
||||
{
|
||||
m_DataPath = Application.persistentDataPath;
|
||||
}
|
||||
m_Processor.m_RawDataPath = value;
|
||||
}
|
||||
|
||||
void StartDateChange(string value)
|
||||
{
|
||||
m_ValidDates = true;
|
||||
m_Processor.m_StartDate = value;
|
||||
HeatmapViewModel.startDate = value;
|
||||
}
|
||||
|
||||
void EndDateChange(string value)
|
||||
{
|
||||
m_ValidDates = true;
|
||||
m_Processor.m_EndDate = value;
|
||||
HeatmapViewModel.endDate = value;
|
||||
}
|
||||
|
||||
void DateFailure()
|
||||
{
|
||||
m_ValidDates = false;
|
||||
}
|
||||
|
||||
bool DateValidationStart(string value)
|
||||
{
|
||||
return DateValidation(value, m_EndDate);
|
||||
}
|
||||
|
||||
bool DateValidationEnd(string value)
|
||||
{
|
||||
return DateValidation(m_StartDate, value);
|
||||
}
|
||||
|
||||
bool DateValidation(string start, string end)
|
||||
{
|
||||
DateTime startDate;
|
||||
DateTime endDate;
|
||||
try
|
||||
{
|
||||
startDate = DateTime.Parse(start);
|
||||
endDate = DateTime.Parse(end);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// Midnight tonight
|
||||
var today = DateTime.Today.AddDays(1).ToUniversalTime();
|
||||
return startDate < endDate && endDate <= today;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8d34ee6154c4743b1b5f0749c2c3eba4
|
||||
timeCreated: 1512690865
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6238eb5270fde46bfb6f852753b8cbc0
|
||||
folderAsset: yes
|
||||
timeCreated: 1471146040
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,359 @@
|
|||
using System;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityAnalytics360VideoHeatmap
|
||||
{
|
||||
public static class AnalyticsDatePicker {
|
||||
|
||||
//private static GUIStyle fieldStyle;
|
||||
private static Vector2 fieldOffset = new Vector2(0, -2f);
|
||||
private static Vector2 winSize = new Vector2(300f, 175f);
|
||||
|
||||
public static string s_CachedValue;
|
||||
private static int s_CachedControlId;
|
||||
private static bool s_DoDropDown = false;
|
||||
|
||||
public static string DatePicker(string value,
|
||||
GUIStyle fieldStyle,
|
||||
EditorGUIBinding.TextFieldChangeHandler change,
|
||||
EditorGUIBinding.TextFieldFailureHandler failure = null,
|
||||
EditorGUIBinding.TextFieldValidationHandler validate = null)
|
||||
{
|
||||
int controlID = GUIUtility.GetControlID (FocusType.Keyboard);
|
||||
Rect controlRect = EditorGUILayout.GetControlRect(false);
|
||||
|
||||
fieldStyle.contentOffset = fieldOffset;
|
||||
fieldStyle.clipping = TextClipping.Overflow;
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
EditorGUI.LabelField(controlRect, value, fieldStyle);
|
||||
DatePickerWindow window = null;
|
||||
|
||||
switch (Event.current.GetTypeForControl(controlID))
|
||||
{
|
||||
case EventType.MouseDown:
|
||||
if (controlRect.Contains(Event.current.mousePosition) && Event.current.button == 0)
|
||||
{
|
||||
GUIUtility.hotControl = controlID;
|
||||
Event.current.Use();
|
||||
}
|
||||
break;
|
||||
case EventType.MouseUp:
|
||||
if (GUIUtility.hotControl == controlID && Event.current.button == 0
|
||||
&& controlRect.Contains(Event.current.mousePosition))
|
||||
{
|
||||
s_DoDropDown = true;
|
||||
Event.current.Use();
|
||||
}
|
||||
break;
|
||||
case EventType.Repaint:
|
||||
if (GUIUtility.hotControl == controlID && s_DoDropDown)
|
||||
{
|
||||
s_DoDropDown = false;
|
||||
s_CachedControlId = controlID;
|
||||
GUIUtility.hotControl = 0;
|
||||
Vector2 position = EditorGUIUtility.GUIToScreenPoint(new Vector2(controlRect.x, controlRect.y+controlRect.height));
|
||||
window = ScriptableObject.CreateInstance<DatePickerWindow>();
|
||||
window.ShowAsDropDown(new Rect(position.x, position.y-winSize.y, winSize.x, winSize.y), winSize, value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (s_CachedControlId == controlID && s_CachedValue != null)
|
||||
{
|
||||
value = s_CachedValue;
|
||||
s_CachedControlId = 0;
|
||||
s_CachedValue = null;
|
||||
GUI.changed = true;
|
||||
}
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
DatePickerApplyChangeHandlers(value, change, failure, validate);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
private static void DatePickerApplyChangeHandlers(string text,
|
||||
EditorGUIBinding.TextFieldChangeHandler change,
|
||||
EditorGUIBinding.TextFieldFailureHandler failure,
|
||||
EditorGUIBinding.TextFieldValidationHandler validate)
|
||||
{
|
||||
bool validated = (validate == null) ? true : validate(text);
|
||||
if (validated)
|
||||
{
|
||||
change(text);
|
||||
}
|
||||
else if (!validated && failure != null)
|
||||
{
|
||||
failure();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class DatePickerWindow : EditorWindow
|
||||
{
|
||||
public string value;
|
||||
private DatePickerModel model;
|
||||
private bool doCommit = false;
|
||||
private GUILayoutOption itemWidth;
|
||||
|
||||
private static GUIStyle fieldStyle;
|
||||
private static GUIStyle dateStyle;
|
||||
private static RectOffset dateFieldRectOffset;
|
||||
|
||||
private static string[] m_MonthsOfTheYear = new string[12]
|
||||
{"January", "February", "March", "April",
|
||||
"May", "June", "July", "August",
|
||||
"September", "October", "November", "December"};
|
||||
|
||||
public void ShowAsDropDown(Rect buttonRect, Vector2 windowSize, string dateValue)
|
||||
{
|
||||
base.ShowAsDropDown(buttonRect, windowSize);
|
||||
value = dateValue;
|
||||
itemWidth = GUILayout.Width(35f);
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
model = new DatePickerModel();
|
||||
dateFieldRectOffset = new RectOffset(0, 0, 2, 0);
|
||||
|
||||
if (fieldStyle == null)
|
||||
{
|
||||
fieldStyle = new GUIStyle();
|
||||
fieldStyle.alignment = TextAnchor.MiddleCenter;
|
||||
|
||||
dateStyle = new GUIStyle();
|
||||
dateStyle.alignment = TextAnchor.MiddleCenter;
|
||||
dateStyle.margin = dateFieldRectOffset;
|
||||
dateStyle.stretchWidth = true;
|
||||
dateStyle.clipping = TextClipping.Overflow;
|
||||
}
|
||||
}
|
||||
|
||||
void OnGUI()
|
||||
{
|
||||
value = EditorGUILayout.TextField(value);
|
||||
if (string.IsNullOrEmpty(value))
|
||||
return;
|
||||
|
||||
model.Update(value);
|
||||
using(new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
if (GUILayout.Button("<"))
|
||||
{
|
||||
model.decrementMonth();
|
||||
model.Calculate();
|
||||
}
|
||||
|
||||
int monthIndex = Mathf.Clamp(model.m_Month - 1, 0, 11);
|
||||
EditorGUILayout.LabelField(model.m_Year + " " + m_MonthsOfTheYear[monthIndex], dateStyle);
|
||||
if (GUILayout.Button(">"))
|
||||
{
|
||||
model.incrementMonth();
|
||||
model.Calculate();
|
||||
}
|
||||
}
|
||||
|
||||
using (new EditorGUILayout.VerticalScope("box"))
|
||||
{
|
||||
for (int a = 0; a < 6; a++)
|
||||
{
|
||||
using(new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
for (int b = a*7; b < (a*7)+7; b++)
|
||||
{
|
||||
var dt = model.m_MonthDays[b];
|
||||
if (dt == 0)
|
||||
{
|
||||
EditorGUILayout.LabelField(" ", itemWidth);
|
||||
}
|
||||
else if (dt == model.m_Date)
|
||||
{
|
||||
EditorGUILayout.LabelField(dt.ToString(), fieldStyle, itemWidth);
|
||||
}
|
||||
else if (GUILayout.Button(dt.ToString(), itemWidth))
|
||||
{
|
||||
//TODO: Commit the new date
|
||||
model.m_Date = dt;
|
||||
doCommit = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
value = model.dateString;
|
||||
if (doCommit || Event.current.type == EventType.KeyDown && Event.current.keyCode == KeyCode.Return)
|
||||
{
|
||||
Commit();
|
||||
}
|
||||
}
|
||||
|
||||
void OnInspectorUpdate()
|
||||
{
|
||||
if (AnalyticsDatePicker.s_CachedValue != null)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
||||
void Commit()
|
||||
{
|
||||
AnalyticsDatePicker.s_CachedValue = value;
|
||||
doCommit = false;
|
||||
}
|
||||
}
|
||||
|
||||
public class DatePickerModel
|
||||
{
|
||||
private int _year;
|
||||
public int m_Year
|
||||
{
|
||||
get
|
||||
{
|
||||
return _year;
|
||||
}
|
||||
set
|
||||
{
|
||||
_year = value;
|
||||
dateString = _year + "-" + MinFormat(m_Month) + "-" + MinFormat(m_Date);
|
||||
}
|
||||
}
|
||||
private int _month;
|
||||
public int m_Month
|
||||
{
|
||||
get
|
||||
{
|
||||
return _month;
|
||||
}
|
||||
set
|
||||
{
|
||||
_month = value;
|
||||
dateString = m_Year + "-" + MinFormat(_month) + "-" + MinFormat(m_Date);
|
||||
}
|
||||
}
|
||||
private int _date;
|
||||
public int m_Date
|
||||
{
|
||||
get
|
||||
{
|
||||
return _date;
|
||||
}
|
||||
set
|
||||
{
|
||||
_date = value;
|
||||
dateString = m_Year + "-" + MinFormat(m_Month) + "-" + MinFormat(_date);
|
||||
}
|
||||
}
|
||||
|
||||
private string _dateString;
|
||||
public string dateString
|
||||
{
|
||||
get
|
||||
{
|
||||
return _dateString;
|
||||
}
|
||||
private set
|
||||
{
|
||||
_dateString = value;
|
||||
}
|
||||
}
|
||||
|
||||
public void decrementMonth()
|
||||
{
|
||||
if (m_Month - 1 < 1)
|
||||
{
|
||||
m_Year --;
|
||||
m_Month = 12;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Month --;
|
||||
}
|
||||
}
|
||||
|
||||
public void incrementMonth()
|
||||
{
|
||||
if (m_Month + 1 > 12)
|
||||
{
|
||||
m_Year ++;
|
||||
m_Month = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Month ++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int[] m_DaysInMonths = new int[12]{31, 28, 31, 30, 31, 30, 31, 30, 30, 31, 30, 31};
|
||||
public int[] m_MonthDays;
|
||||
|
||||
public void Update(string date)
|
||||
{
|
||||
dateString = date;
|
||||
string[] elements = date.Split('-');
|
||||
try {
|
||||
m_Year = int.Parse(elements[0]);
|
||||
m_Month = int.Parse(elements[1]);
|
||||
m_Date = int.Parse(elements[2]);
|
||||
} catch {
|
||||
//No-op
|
||||
}
|
||||
Calculate();
|
||||
}
|
||||
|
||||
public void Calculate()
|
||||
{
|
||||
if (!CheckDateValidity())
|
||||
{
|
||||
return;
|
||||
}
|
||||
var date = new DateTime(m_Year, m_Month, 1);
|
||||
int firstDay = (int)date.DayOfWeek;
|
||||
int daysInMonth = GetDaysInMonth();
|
||||
|
||||
m_MonthDays = new int[42];
|
||||
for(int a = 0; a < 42; a++)
|
||||
{
|
||||
if (a >= firstDay && a < daysInMonth+firstDay)
|
||||
{
|
||||
m_MonthDays[a] = a + 1 - firstDay;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int GetDaysInMonth()
|
||||
{
|
||||
int days = m_DaysInMonths[m_Month-1];
|
||||
// leap year calculation
|
||||
if (m_Month == 2 && m_Year % 4 == 0 && (m_Year % 100 != 0 || m_Year % 400 == 0))
|
||||
{
|
||||
days ++;
|
||||
}
|
||||
return days;
|
||||
}
|
||||
|
||||
bool CheckDateValidity()
|
||||
{
|
||||
try
|
||||
{
|
||||
new DateTime(m_Year, m_Month, m_Date);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
string MinFormat(int number)
|
||||
{
|
||||
return number < 10 ? "0" + number : number.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5b5aa70313e0c4f88928766412f1bdbe
|
||||
timeCreated: 1470758172
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,442 @@
|
|||
/// <summary>
|
||||
/// EditorGUI Components decorated with change, fail and validation handlers
|
||||
/// </summary>
|
||||
///
|
||||
/// Decorates EditorGUILayout controls, adding three callback handlers
|
||||
/// * change - Required. Calls back whenever the value changes. If a validation handler is included and validation fails,
|
||||
/// change is not called.
|
||||
/// * failure - Optional. Called if validation fails.
|
||||
/// * validation - Optional. If provided, will prevent calls to change when validation fails. If failure is provided, will call
|
||||
/// that handler instead.
|
||||
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
namespace UnityAnalytics360VideoHeatmap
|
||||
{
|
||||
public class EditorGUIBinding
|
||||
{
|
||||
#region FloatField
|
||||
public delegate void FloatChangeHandler(float value);
|
||||
public delegate void FloatFailureHandler();
|
||||
public delegate bool FloatValidationHandler(float value);
|
||||
|
||||
private static void FloatApplyChangeHandlers(float value, FloatChangeHandler change, FloatFailureHandler failure, FloatValidationHandler validate)
|
||||
{
|
||||
bool validated = (validate == null) ? true : validate(value);
|
||||
if (validated)
|
||||
{
|
||||
change(value);
|
||||
}
|
||||
else if (!validated && failure != null)
|
||||
{
|
||||
failure();
|
||||
}
|
||||
}
|
||||
|
||||
public static float FloatField(float value,
|
||||
FloatChangeHandler change, FloatFailureHandler failure = null, FloatValidationHandler validate = null,
|
||||
params GUILayoutOption[] options)
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
value = EditorGUILayout.FloatField(value, options);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
FloatApplyChangeHandlers(value, change, failure, validate);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
public static float FloatField(float value, GUIStyle style,
|
||||
FloatChangeHandler change, FloatFailureHandler failure = null, FloatValidationHandler validate = null,
|
||||
params GUILayoutOption[] options)
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
value = EditorGUILayout.FloatField(value, style, options);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
FloatApplyChangeHandlers(value, change, failure, validate);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
public static float FloatField(string label, float value,
|
||||
FloatChangeHandler change, FloatFailureHandler failure = null, FloatValidationHandler validate = null,
|
||||
params GUILayoutOption[] options)
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
value = EditorGUILayout.FloatField(label, value, options);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
FloatApplyChangeHandlers(value, change, failure, validate);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
public static float FloatField(string label, float value, GUIStyle style,
|
||||
FloatChangeHandler change, FloatFailureHandler failure = null, FloatValidationHandler validate = null,
|
||||
params GUILayoutOption[] options)
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
value = EditorGUILayout.FloatField(label, value, style, options);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
FloatApplyChangeHandlers(value, change, failure, validate);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
public static float FloatField(GUIContent label, float value,
|
||||
FloatChangeHandler change, FloatFailureHandler failure = null, FloatValidationHandler validate = null,
|
||||
params GUILayoutOption[] options)
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
value = EditorGUILayout.FloatField(label, value, options);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
FloatApplyChangeHandlers(value, change, failure, validate);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
public static float FloatField(GUIContent label, float value, GUIStyle style,
|
||||
FloatChangeHandler change, FloatFailureHandler failure = null, FloatValidationHandler validate = null,
|
||||
params GUILayoutOption[] options)
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
value = EditorGUILayout.FloatField(label, value, style, options);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
FloatApplyChangeHandlers(value, change, failure, validate);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Popup
|
||||
public delegate void IntChangeHandler(int value);
|
||||
public delegate void IntFailureHandler();
|
||||
public delegate bool IntValidationHandler(int value);
|
||||
|
||||
private static void IntApplyChangeHandlers(int value, IntChangeHandler change, IntFailureHandler failure, IntValidationHandler validate)
|
||||
{
|
||||
bool validated = (validate == null) ? true : validate(value);
|
||||
if (validated)
|
||||
{
|
||||
change(value);
|
||||
}
|
||||
else if (!validated && failure != null)
|
||||
{
|
||||
failure();
|
||||
}
|
||||
}
|
||||
|
||||
public static int Popup(int selectedIndex, string[] displayedOptions,
|
||||
IntChangeHandler change, IntFailureHandler failure = null, IntValidationHandler validate = null,
|
||||
params GUILayoutOption[] options)
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
selectedIndex = EditorGUILayout.Popup(selectedIndex, displayedOptions, options);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
IntApplyChangeHandlers(selectedIndex, change, failure, validate);
|
||||
}
|
||||
return selectedIndex;
|
||||
}
|
||||
public static int Popup(int selectedIndex, string[] displayedOptions, GUIStyle style,
|
||||
IntChangeHandler change, IntFailureHandler failure = null, IntValidationHandler validate = null,
|
||||
params GUILayoutOption[] options)
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
selectedIndex = EditorGUILayout.Popup(selectedIndex, displayedOptions, style, options);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
IntApplyChangeHandlers(selectedIndex, change, failure, validate);
|
||||
}
|
||||
return selectedIndex;
|
||||
}
|
||||
public static int Popup(int selectedIndex, GUIContent[] displayedOptions,
|
||||
IntChangeHandler change, IntFailureHandler failure = null, IntValidationHandler validate = null,
|
||||
params GUILayoutOption[] options)
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
selectedIndex = EditorGUILayout.Popup(selectedIndex, displayedOptions, options);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
IntApplyChangeHandlers(selectedIndex, change, failure, validate);
|
||||
}
|
||||
return selectedIndex;
|
||||
}
|
||||
public static int Popup(int selectedIndex, GUIContent[] displayedOptions, GUIStyle style,
|
||||
IntChangeHandler change, IntFailureHandler failure = null, IntValidationHandler validate = null,
|
||||
params GUILayoutOption[] options)
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
selectedIndex = EditorGUILayout.Popup(selectedIndex, displayedOptions, style, options);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
IntApplyChangeHandlers(selectedIndex, change, failure, validate);
|
||||
}
|
||||
return selectedIndex;
|
||||
}
|
||||
public static int Popup(string label, int selectedIndex, string[] displayedOptions,
|
||||
IntChangeHandler change, IntFailureHandler failure = null, IntValidationHandler validate = null,
|
||||
params GUILayoutOption[] options)
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
selectedIndex = EditorGUILayout.Popup(label, selectedIndex, displayedOptions, options);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
IntApplyChangeHandlers(selectedIndex, change, failure, validate);
|
||||
}
|
||||
return selectedIndex;
|
||||
}
|
||||
public static int Popup(string label, int selectedIndex, string[] displayedOptions, GUIStyle style,
|
||||
IntChangeHandler change, IntFailureHandler failure = null, IntValidationHandler validate = null,
|
||||
params GUILayoutOption[] options)
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
selectedIndex = EditorGUILayout.Popup(label, selectedIndex, displayedOptions, style, options);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
IntApplyChangeHandlers(selectedIndex, change, failure, validate);
|
||||
}
|
||||
return selectedIndex;
|
||||
}
|
||||
public static int Popup(GUIContent label, int selectedIndex, GUIContent[] displayedOptions,
|
||||
IntChangeHandler change, IntFailureHandler failure = null, IntValidationHandler validate = null,
|
||||
params GUILayoutOption[] options)
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
selectedIndex = EditorGUILayout.Popup(label, selectedIndex, displayedOptions, options);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
IntApplyChangeHandlers(selectedIndex, change, failure, validate);
|
||||
}
|
||||
return selectedIndex;
|
||||
}
|
||||
public static int Popup(GUIContent label, int selectedIndex, GUIContent[] displayedOptions, GUIStyle style,
|
||||
IntChangeHandler change, IntFailureHandler failure = null, IntValidationHandler validate = null,
|
||||
params GUILayoutOption[] options)
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
selectedIndex = EditorGUILayout.Popup(label, selectedIndex, displayedOptions, style, options);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
IntApplyChangeHandlers(selectedIndex, change, failure, validate);
|
||||
}
|
||||
return selectedIndex;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region TextField
|
||||
public delegate void TextFieldChangeHandler(string text);
|
||||
public delegate void TextFieldFailureHandler();
|
||||
public delegate bool TextFieldValidationHandler(string text);
|
||||
|
||||
private static void TextFieldApplyChangeHandlers(string text, TextFieldChangeHandler change, TextFieldFailureHandler failure, TextFieldValidationHandler validate)
|
||||
{
|
||||
bool validated = (validate == null) ? true : validate(text);
|
||||
if (validated)
|
||||
{
|
||||
change(text);
|
||||
}
|
||||
else if (!validated && failure != null)
|
||||
{
|
||||
failure();
|
||||
}
|
||||
}
|
||||
|
||||
public static string TextField(string text,
|
||||
TextFieldChangeHandler change,
|
||||
TextFieldFailureHandler failure = null,
|
||||
TextFieldValidationHandler validate = null,
|
||||
params GUILayoutOption[] options)
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
text = EditorGUILayout.TextField(text, options);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
TextFieldApplyChangeHandlers(text, change, failure, validate);
|
||||
}
|
||||
return text;
|
||||
}
|
||||
public static string TextField(string text, GUIStyle style,
|
||||
TextFieldChangeHandler change,
|
||||
TextFieldFailureHandler failure = null,
|
||||
TextFieldValidationHandler validate = null,
|
||||
params GUILayoutOption[] options)
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
text = EditorGUILayout.TextField(text, style, options);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
TextFieldApplyChangeHandlers(text, change, failure, validate);
|
||||
}
|
||||
return text;
|
||||
}
|
||||
public static string TextField(string label, string text,
|
||||
TextFieldChangeHandler change,
|
||||
TextFieldFailureHandler failure = null,
|
||||
TextFieldValidationHandler validate = null,
|
||||
params GUILayoutOption[] options)
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
text = EditorGUILayout.TextField(label, text, options);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
TextFieldApplyChangeHandlers(text, change, failure, validate);
|
||||
}
|
||||
return text;
|
||||
}
|
||||
public static string TextField(string label, string text, GUIStyle style,
|
||||
TextFieldChangeHandler change,
|
||||
TextFieldFailureHandler failure = null,
|
||||
TextFieldValidationHandler validate = null,
|
||||
params GUILayoutOption[] options)
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
text = EditorGUILayout.TextField(label, text, style, options);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
TextFieldApplyChangeHandlers(text, change, failure, validate);
|
||||
}
|
||||
return text;
|
||||
}
|
||||
public static string TextField(GUIContent label, string text,
|
||||
TextFieldChangeHandler change,
|
||||
TextFieldFailureHandler failure = null,
|
||||
TextFieldValidationHandler validate = null,
|
||||
params GUILayoutOption[] options)
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
text = EditorGUILayout.TextField(label, text, options);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
TextFieldApplyChangeHandlers(text, change, failure, validate);
|
||||
}
|
||||
return text;
|
||||
}
|
||||
public static string TextField(GUIContent label, string text, GUIStyle style,
|
||||
TextFieldChangeHandler change,
|
||||
TextFieldFailureHandler failure = null,
|
||||
TextFieldValidationHandler validate = null,
|
||||
params GUILayoutOption[] options)
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
text = EditorGUILayout.TextField(label, text, style, options);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
TextFieldApplyChangeHandlers(text, change, failure, validate);
|
||||
}
|
||||
return text;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Toggle
|
||||
public delegate void ToggleChangeHandler(bool value);
|
||||
public delegate void ToggleFailureHandler();
|
||||
public delegate bool ToggleValidationHandler(bool value);
|
||||
|
||||
private static void ToggleApplyChangeHandlers(bool value,
|
||||
ToggleChangeHandler change,
|
||||
ToggleFailureHandler failure,
|
||||
ToggleValidationHandler validate)
|
||||
{
|
||||
bool validated = (validate == null) ? true : validate(value);
|
||||
if (validated)
|
||||
{
|
||||
change(value);
|
||||
}
|
||||
else if (!validated && failure != null)
|
||||
{
|
||||
failure();
|
||||
}
|
||||
}
|
||||
|
||||
public static bool Toggle(bool value,
|
||||
ToggleChangeHandler change,
|
||||
ToggleFailureHandler failure = null,
|
||||
ToggleValidationHandler validate = null,
|
||||
params GUILayoutOption[] options)
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
value = EditorGUILayout.ToggleLeft("", value, options);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
ToggleApplyChangeHandlers(value, change, failure, validate);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
public static bool Toggle(string label, bool value,
|
||||
ToggleChangeHandler change,
|
||||
ToggleFailureHandler failure = null,
|
||||
ToggleValidationHandler validate = null,
|
||||
params GUILayoutOption[] options)
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
value = EditorGUILayout.ToggleLeft(label, value, options);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
ToggleApplyChangeHandlers(value, change, failure, validate);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
public static bool Toggle(GUIContent label, bool value,
|
||||
ToggleChangeHandler change,
|
||||
ToggleFailureHandler failure = null,
|
||||
ToggleValidationHandler validate = null,
|
||||
params GUILayoutOption[] options)
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
value = EditorGUILayout.ToggleLeft(label, value, options);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
ToggleApplyChangeHandlers(value, change, failure, validate);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
public static bool Toggle(bool value, GUIStyle style,
|
||||
ToggleChangeHandler change,
|
||||
ToggleFailureHandler failure = null,
|
||||
ToggleValidationHandler validate = null,
|
||||
params GUILayoutOption[] options)
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
value = EditorGUILayout.ToggleLeft("", value, style, options);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
ToggleApplyChangeHandlers(value, change, failure, validate);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
public static bool Toggle(string label, bool value, GUIStyle style,
|
||||
ToggleChangeHandler change,
|
||||
ToggleFailureHandler failure = null,
|
||||
ToggleValidationHandler validate = null,
|
||||
params GUILayoutOption[] options)
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
value = EditorGUILayout.ToggleLeft(label, value, style, options);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
ToggleApplyChangeHandlers(value, change, failure, validate);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
public static bool Toggle(GUIContent label, bool value, GUIStyle style,
|
||||
ToggleChangeHandler change,
|
||||
ToggleFailureHandler failure = null,
|
||||
ToggleValidationHandler validate = null,
|
||||
params GUILayoutOption[] options)
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
value = EditorGUILayout.ToggleLeft(label, value, style, options);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
ToggleApplyChangeHandlers(value, change, failure, validate);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 43ea6d38276954c8db58acd019e1122c
|
||||
timeCreated: 1471196349
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,20 @@
|
|||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace UnityAnalytics360VideoHeatmap
|
||||
{
|
||||
public class HeatmapClipNameList : MonoBehaviour
|
||||
{
|
||||
public delegate void ChangeHandler(string[] array);
|
||||
|
||||
public static void ListGroup(string[] array, ChangeHandler change)
|
||||
{
|
||||
if (array == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
change(array);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 07d2af98bf0104a96a2459bc72894088
|
||||
timeCreated: 1511757496
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,61 @@
|
|||
/// <summary>
|
||||
/// Visual component for managing a list of popup lists.
|
||||
/// </summary>
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityAnalytics360VideoHeatmap
|
||||
{
|
||||
public class AnalyticsListGroup
|
||||
{
|
||||
|
||||
public delegate void ChangeHandler(List<int> value);
|
||||
|
||||
|
||||
public static List<int> ListGroup(List<int>value, List<List<string>> lists, ChangeHandler change)
|
||||
{
|
||||
////Debug.Log(value.ToString());
|
||||
////Debug.Log(lists.ToString());
|
||||
if (lists == null || value == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
if (value.Count > 1)
|
||||
{
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
EditorGUILayout.LabelField("Data Set Options", GUILayout.Width(EditorGUIUtility.labelWidth - 4));
|
||||
|
||||
using (new EditorGUILayout.VerticalScope())
|
||||
{
|
||||
for (int a = 0; a < value.Count; a++)
|
||||
{
|
||||
////Debug.Log(value[a]);
|
||||
////Debug.Log(lists);
|
||||
if (lists[a].Contains("Heatmap.PlayerLook"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var listArray = lists[a].ToArray();
|
||||
value[a] = EditorGUILayout.Popup(value[a], listArray);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
change(value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 20e613089e0a74d51b7f242a94f6b824
|
||||
timeCreated: 1471377655
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,73 @@
|
|||
using System;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using System.Linq;
|
||||
|
||||
namespace UnityAnalytics360VideoHeatmap
|
||||
{
|
||||
public class AnalyticsSmootherControl
|
||||
{
|
||||
private static GUIContent[] s_SmootherOptionsContent;
|
||||
|
||||
private static Texture2D darkSkinUnionIcon = Resources.Load("unity_analytics_heatmaps_union_dark") as Texture2D;
|
||||
private static Texture2D darkSkinNumberIcon = Resources.Load("unity_analytics_heatmaps_number_dark") as Texture2D;
|
||||
private static Texture2D darkSkinNoneIcon = Resources.Load("unity_analytics_heatmaps_none_dark") as Texture2D;
|
||||
|
||||
private static Texture2D lightSkinUnionIcon = Resources.Load("unity_analytics_heatmaps_union_light") as Texture2D;
|
||||
private static Texture2D lightSkinNumberIcon = Resources.Load("unity_analytics_heatmaps_number_light") as Texture2D;
|
||||
private static Texture2D lightSkinNoneIcon = Resources.Load("unity_analytics_heatmaps_none_light") as Texture2D;
|
||||
|
||||
public delegate void ChangeHandler(int toggler, float value);
|
||||
|
||||
public static void SmootherControl (int toggler, float value,
|
||||
string label, string tooltip, ChangeHandler change,
|
||||
int endIndex = -1)
|
||||
{
|
||||
if (s_SmootherOptionsContent == null)
|
||||
{
|
||||
var unionIcon = lightSkinUnionIcon;
|
||||
var smoothIcon = lightSkinNumberIcon;
|
||||
var noneIcon = lightSkinNoneIcon;
|
||||
if (EditorGUIUtility.isProSkin)
|
||||
{
|
||||
unionIcon = darkSkinUnionIcon;
|
||||
smoothIcon = darkSkinNumberIcon;
|
||||
noneIcon = darkSkinNoneIcon;
|
||||
}
|
||||
|
||||
s_SmootherOptionsContent = new GUIContent[] {
|
||||
new GUIContent(smoothIcon, "Smooth to value"),
|
||||
new GUIContent(noneIcon, "No smoothing"),
|
||||
new GUIContent(unionIcon, "Unify all")
|
||||
};
|
||||
}
|
||||
|
||||
using (new EditorGUILayout.VerticalScope())
|
||||
{
|
||||
var options = endIndex == -1 ? s_SmootherOptionsContent :
|
||||
s_SmootherOptionsContent.Take(endIndex).ToArray();
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
int oldToggle = toggler;
|
||||
toggler = GUILayout.Toolbar(toggler, options, GUILayout.MaxWidth(100));
|
||||
|
||||
float lw = EditorGUIUtility.labelWidth;
|
||||
EditorGUIUtility.labelWidth = 50;
|
||||
float fw = EditorGUIUtility.fieldWidth;
|
||||
EditorGUIUtility.fieldWidth = 20;
|
||||
EditorGUI.BeginDisabledGroup(toggler != HeatmapDataProcessor.SMOOTH_VALUE);
|
||||
value = EditorGUILayout.FloatField(new GUIContent(label, tooltip), value);
|
||||
value = Mathf.Max(0, value);
|
||||
EditorGUI.EndDisabledGroup();
|
||||
EditorGUIUtility.labelWidth = lw;
|
||||
EditorGUIUtility.fieldWidth = fw;
|
||||
|
||||
if (EditorGUI.EndChangeCheck() || oldToggle != toggler)
|
||||
{
|
||||
change(toggler, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fa489924348944ae0a643f341085edd3
|
||||
timeCreated: 1471231413
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,56 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
namespace UnityAnalytics360VideoHeatmap
|
||||
{
|
||||
public class AnalyticsTextFieldList
|
||||
{
|
||||
private static GUIContent s_AddFieldContent = new GUIContent("+", "Add field");
|
||||
private static GUILayoutOption s_ButtonWidth = GUILayout.MaxWidth(20f);
|
||||
|
||||
|
||||
public delegate void TextFieldListChangeHandler(List<string> list);
|
||||
|
||||
public static List<string> TextFieldList (List<string> m_ArbitraryFields, TextFieldListChangeHandler change)
|
||||
{
|
||||
|
||||
if (m_ArbitraryFields.Count == 0)
|
||||
{
|
||||
m_ArbitraryFields.Add("Field name");
|
||||
}
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
for (var a = 0; a < m_ArbitraryFields.Count; a++)
|
||||
{
|
||||
using (new GUILayout.HorizontalScope())
|
||||
{
|
||||
m_ArbitraryFields[a] = EditorGUILayout.TextField(m_ArbitraryFields[a]);
|
||||
|
||||
EditorGUI.BeginDisabledGroup(m_ArbitraryFields.Count == 1);
|
||||
if (GUILayout.Button("-", s_ButtonWidth))
|
||||
{
|
||||
m_ArbitraryFields.RemoveAt(a);
|
||||
break;
|
||||
}
|
||||
EditorGUI.EndDisabledGroup();
|
||||
|
||||
if (a == m_ArbitraryFields.Count-1 && GUILayout.Button(s_AddFieldContent, s_ButtonWidth))
|
||||
{
|
||||
m_ArbitraryFields.Add("Field name");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
change(m_ArbitraryFields);
|
||||
}
|
||||
|
||||
return m_ArbitraryFields;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 26d9ebf15fbb74732a06602c84474b51
|
||||
timeCreated: 1471232169
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,52 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
namespace UnityAnalytics360VideoHeatmap
|
||||
{
|
||||
public class FlattenedHeatmapView : EditorWindow
|
||||
{
|
||||
RenderTexture _composite;
|
||||
|
||||
[MenuItem("Window/Unity Analytics/360 Video Heatmaps/Flattened Heatmap View")]
|
||||
static void ShowPreviewWindow()
|
||||
{
|
||||
EditorWindow.GetWindow(typeof(FlattenedHeatmapView));
|
||||
}
|
||||
|
||||
void OnGUI()
|
||||
{
|
||||
if (_composite == null)
|
||||
{
|
||||
var go = GameObject.Find("UnityAnalytics__Heatmap");
|
||||
if (go)
|
||||
{
|
||||
var heatmap = go.GetComponent<Hotspots>();
|
||||
if (heatmap)
|
||||
{
|
||||
_composite = heatmap.composite;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float x = 0;
|
||||
float y = 0;
|
||||
float w = position.width;
|
||||
float h = 0;
|
||||
|
||||
if (_composite != null)
|
||||
{
|
||||
h = _composite.height * w / _composite.width;
|
||||
EditorGUI.DrawPreviewTexture(new Rect(x, y, w, h), _composite);
|
||||
}
|
||||
|
||||
y += h;
|
||||
}
|
||||
|
||||
void OnInspectorUpdate()
|
||||
{
|
||||
Repaint();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 33a5b2e52e86d4dea9be8bde90e20067
|
||||
timeCreated: 1513107479
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,372 @@
|
|||
/// <summary>
|
||||
/// Heat map renderer inspector.
|
||||
/// </summary>
|
||||
/// This code manages the portion of the inspector that
|
||||
/// controls the Heat Map renderer.
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Video;
|
||||
using System.Reflection;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace UnityAnalytics360VideoHeatmap
|
||||
{
|
||||
public class HeatmapRendererInspector
|
||||
{
|
||||
const string k_Renderer = "UnityAnalyticsHeatmapRenderer";
|
||||
|
||||
const string k_StartTimeKey = "UnityAnalyticsHeatmapStartTime";
|
||||
const string k_EndTimeKey = "UnityAnalyticsHeatmapEndTime";
|
||||
const string k_PlaySpeedKey = "UnityAnalyticsHeatmapPlaySpeed";
|
||||
|
||||
const string k_LowXKey = "UnityAnalyticsHeatmapLowX";
|
||||
const string k_HighXKey = "UnityAnalyticsHeatmapHighX";
|
||||
const string k_LowYKey = "UnityAnalyticsHeatmapLowY";
|
||||
const string k_HighYKey = "UnityAnalyticsHeatmapHighY";
|
||||
const string k_LowZKey = "UnityAnalyticsHeatmapLowZ";
|
||||
const string k_HighZKey = "UnityAnalyticsHeatmapHighZ";
|
||||
|
||||
const string k_ShowTipsKey = "UnityAnalyticsHeatmapShowRendererTooltips";
|
||||
|
||||
const string k_ClipName = "UnityAnalyticsHeatmapClipName";
|
||||
|
||||
Heatmapper m_Heatmapper;
|
||||
|
||||
int m_MaxTime = -1;
|
||||
|
||||
int m_ClipNameIndex = 0;
|
||||
Rect m_ClipDropdownRect;
|
||||
|
||||
int m_QualityIndex = 0;
|
||||
|
||||
float m_minRadius = 1.0f;
|
||||
float m_maxRaidus = 50.0f;
|
||||
|
||||
float m_minDecay = 0.0f;
|
||||
float m_maxDecay = 1.0f;
|
||||
|
||||
const int k_NoFollow = 0;
|
||||
const int k_SceneFollow = 1;
|
||||
const int k_MainCameraFollow = 2;
|
||||
|
||||
GameObject m_GameObject;
|
||||
VideoRenderer videoRenderer;
|
||||
|
||||
Texture2D darkSkinPlayIcon = Resources.Load("unity_analytics_heatmaps_play_dark") as Texture2D;
|
||||
Texture2D darkSkinPauseIcon = Resources.Load("unity_analytics_heatmaps_pause_dark") as Texture2D;
|
||||
Texture2D darkSkinRewindIcon = Resources.Load("unity_analytics_heatmaps_rwd_dark") as Texture2D;
|
||||
|
||||
Texture2D lightSkinPlayIcon = Resources.Load("unity_analytics_heatmaps_play_light") as Texture2D;
|
||||
Texture2D lightSkinPauseIcon = Resources.Load("unity_analytics_heatmaps_pause_light") as Texture2D;
|
||||
Texture2D lightSkinRewindIcon = Resources.Load("unity_analytics_heatmaps_rwd_light") as Texture2D;
|
||||
|
||||
GUIContent m_RestartContent;
|
||||
GUIContent m_PlayContent;
|
||||
GUIContent m_PauseContent;
|
||||
|
||||
GUIContent m_ClipDropdown = new GUIContent("Video Clip", "Select the video clip Name");
|
||||
|
||||
GUIContent m_MinRadiusContent = new GUIContent(" Radius");
|
||||
GUIContent m_DecayRateContent = new GUIContent(" Decay Rate");
|
||||
GUIContent m_FrameContent = new GUIContent(" Frame");
|
||||
|
||||
GUIContent m_FunnelContent = new GUIContent("Funnel", "Display the player progression");
|
||||
public delegate void FunnelDataChangeHandler(Dictionary<string, HeatPoint[]> points);
|
||||
|
||||
public HeatmapRendererInspector()
|
||||
{
|
||||
var playIcon = lightSkinPlayIcon;
|
||||
var pauseIcon = lightSkinPauseIcon;
|
||||
var rwdIcon = lightSkinRewindIcon;
|
||||
if (EditorGUIUtility.isProSkin)
|
||||
{
|
||||
playIcon = darkSkinPlayIcon;
|
||||
pauseIcon = darkSkinPauseIcon;
|
||||
rwdIcon = darkSkinRewindIcon;
|
||||
}
|
||||
|
||||
m_RestartContent = new GUIContent(rwdIcon, "Back to Start");
|
||||
m_PlayContent = new GUIContent(playIcon, "Play");
|
||||
m_PauseContent = new GUIContent(pauseIcon, "Pause");
|
||||
|
||||
HeatmapViewModel.HeatpointsUpdated += SetLimits;
|
||||
HeatmapViewModel.FinalFrameUpdated += HeatmapViewModel_FinalFrameUpdated;
|
||||
}
|
||||
|
||||
void HeatmapViewModel_FinalFrameUpdated(int endFrame)
|
||||
{
|
||||
m_MaxTime = endFrame;
|
||||
}
|
||||
|
||||
public static HeatmapRendererInspector Init(Heatmapper heatmapper, HeatmapDataProcessor processor)
|
||||
{
|
||||
var inspector = new HeatmapRendererInspector();
|
||||
inspector.m_Heatmapper = heatmapper;
|
||||
return inspector;
|
||||
}
|
||||
|
||||
int ConvertNormalizedTimeToFrame (float t)
|
||||
{
|
||||
if (HeatmapViewModel.videoPlayer != null && HeatmapViewModel.videoPlayer.isPrepared)
|
||||
return Convert.ToInt32(t * (float)m_MaxTime);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void OnGUI()
|
||||
{
|
||||
if(m_MaxTime == -1)
|
||||
{
|
||||
m_MaxTime = HeatmapViewModel.endFrame;
|
||||
}
|
||||
|
||||
using (new GUILayout.VerticalScope())
|
||||
{
|
||||
videoRenderer.videoMaterial = EditorGUILayout.ObjectField("Video Material", videoRenderer.videoMaterial, typeof(Material), true) as Material;
|
||||
|
||||
var separators = HeatmapViewModel.GetSeparators();
|
||||
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
EditorGUILayout.LabelField(m_ClipDropdown, GUILayout.Width(EditorGUIUtility.labelWidth - 4));
|
||||
m_ClipDropdownRect = EditorGUILayout.BeginVertical();
|
||||
EditorGUILayout.LabelField("", EditorStyles.boldLabel);
|
||||
EditorGUILayout.EndVertical();
|
||||
var clipNameSep = separators["clipName"];
|
||||
EditorGUI.BeginChangeCheck();
|
||||
m_ClipNameIndex = EditorGUI.Popup(m_ClipDropdownRect, m_ClipNameIndex, clipNameSep.separatorValues.ToArray());
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
clipNameSep.selectedValue = clipNameSep.separatorValues[m_ClipNameIndex];
|
||||
HeatmapViewModel.UpdateSeparator("clipName", clipNameSep);
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUILayout.LabelField("Render Options", GUILayout.Width(EditorGUIUtility.labelWidth - 4));
|
||||
var _player = HeatmapViewModel.videoPlayer;
|
||||
//Disable render options if the videoplayer hasn't been assigned
|
||||
EditorGUI.BeginDisabledGroup(_player == null);
|
||||
using (new EditorGUILayout.VerticalScope())
|
||||
{
|
||||
if (videoRenderer != null)
|
||||
{
|
||||
videoRenderer.minRadius = EditorGUILayout.Slider(m_MinRadiusContent, videoRenderer.minRadius, m_minRadius, m_maxRaidus);
|
||||
videoRenderer.maxRadius = videoRenderer.minRadius;
|
||||
videoRenderer.decay = EditorGUILayout.Slider(m_DecayRateContent, videoRenderer.decay, m_minDecay, m_maxDecay);
|
||||
|
||||
m_QualityIndex = EditorGUILayout.Popup(" Quality", m_QualityIndex, new string[]{"1X", "2X", "5X"});
|
||||
|
||||
if (_player != null)
|
||||
{
|
||||
int m_HeatMapWidthBase = (int)_player.clip.width / 5;
|
||||
int m_HeatMapHeightBase = (int)_player.clip.height / 5;
|
||||
|
||||
switch (m_QualityIndex)
|
||||
{
|
||||
case 0:
|
||||
videoRenderer.heatMapWidth = m_HeatMapWidthBase;
|
||||
videoRenderer.heatMapHeight = m_HeatMapHeightBase;
|
||||
break; ;
|
||||
case 1:
|
||||
videoRenderer.heatMapWidth = m_HeatMapWidthBase * 2;
|
||||
videoRenderer.heatMapHeight = m_HeatMapHeightBase * 2;
|
||||
break;
|
||||
case 2:
|
||||
videoRenderer.heatMapWidth = m_HeatMapWidthBase * 5;
|
||||
videoRenderer.heatMapHeight = m_HeatMapHeightBase * 5;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
videoRenderer.numPoints = EditorGUILayout.IntSlider(" Points", videoRenderer.numPoints, 1, 2000);
|
||||
videoRenderer.gradientSize = EditorGUILayout.IntSlider(" Gradient Fidelity", videoRenderer.gradientSize, 1, 256);
|
||||
|
||||
|
||||
EditorGUI.BeginDisabledGroup(_player != null && _player.isPrepared == false);
|
||||
if (_player != null)
|
||||
{
|
||||
var oldStartTime = ConvertNormalizedTimeToFrame(HeatmapViewModel.heatpointShowStartTime);
|
||||
var temp = ConvertNormalizedTimeToFrame(HeatmapViewModel.heatpointShowStartTime);
|
||||
|
||||
if(_player.isPlaying)
|
||||
{
|
||||
EditorGUI.BeginDisabledGroup(true);
|
||||
temp = EditorGUILayout.IntSlider(m_FrameContent, Convert.ToInt32(_player.frame), 1, m_MaxTime);
|
||||
EditorGUI.EndDisabledGroup();
|
||||
}
|
||||
else
|
||||
{
|
||||
temp = EditorGUILayout.IntSlider(m_FrameContent, (int)temp, 1, m_MaxTime);
|
||||
if (temp != oldStartTime)
|
||||
{
|
||||
_player.frame = temp;
|
||||
}
|
||||
}
|
||||
if (temp != oldStartTime)
|
||||
{
|
||||
HeatmapViewModel.UpdateHeatpointShowTimes(GetNormalizedTime(temp), GetNormalizedTime(temp + 1));
|
||||
m_Heatmapper.Repaint();
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
EditorGUILayout.LabelField("", GUILayout.Width(EditorGUIUtility.labelWidth - 4));
|
||||
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
if (GUILayout.Button(m_RestartContent))
|
||||
{
|
||||
_player.Pause();
|
||||
_player.frame = 1;
|
||||
Restart();
|
||||
}
|
||||
GUIContent playButtonContent = _player != null && _player.isPlaying ? m_PauseContent : m_PlayContent;
|
||||
if (GUILayout.Button(playButtonContent))
|
||||
{
|
||||
if (_player.isPlaying)
|
||||
{
|
||||
_player.Pause();
|
||||
}
|
||||
else
|
||||
{
|
||||
_player.Play();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
EditorGUI.EndDisabledGroup();
|
||||
EditorGUILayout.Space();
|
||||
}
|
||||
}
|
||||
EditorGUI.EndDisabledGroup();
|
||||
DisplayFunnelGui();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void SetLimits(Dictionary<string, HeatPoint[]> points)
|
||||
{
|
||||
float maxDensity = 0;
|
||||
|
||||
foreach (KeyValuePair<string, HeatPoint[]> entry in points)
|
||||
{
|
||||
for (int a = 0; a < entry.Value.Length; a++)
|
||||
{
|
||||
maxDensity = Mathf.Max(maxDensity, entry.Value[a].density);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float GetNormalizedTime(float frameNum)
|
||||
{
|
||||
return frameNum / (float)m_MaxTime;
|
||||
}
|
||||
|
||||
void Restart()
|
||||
{
|
||||
HeatmapViewModel.UpdateHeatpointShowTimes(GetNormalizedTime(1), GetNormalizedTime(2));
|
||||
}
|
||||
|
||||
public void SetGameObject(GameObject go)
|
||||
{
|
||||
m_GameObject = go;
|
||||
if (m_GameObject != null)
|
||||
{
|
||||
videoRenderer = m_GameObject.GetComponent<VideoRenderer>();
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateClipNameDropDown(string[] clipNames)
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
m_ClipNameIndex = EditorGUI.Popup(m_ClipDropdownRect, m_ClipNameIndex, clipNames);
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
string m_clipName = clipNames[m_ClipNameIndex];
|
||||
|
||||
// do something if clip changed
|
||||
PlayerPrefs.SetString(k_ClipName, m_clipName);
|
||||
}
|
||||
}
|
||||
|
||||
void DisplayFunnelGui()
|
||||
{
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
EditorGUILayout.LabelField(m_FunnelContent, EditorStyles.boldLabel, GUILayout.Width(EditorGUIUtility.labelWidth - 4));
|
||||
|
||||
using (new EditorGUILayout.VerticalScope())
|
||||
{
|
||||
AnimationCurve m_Curve = CreateFunnel();
|
||||
EditorGUI.CurveField(EditorGUILayout.GetControlRect(), m_Curve);
|
||||
var _player = HeatmapViewModel.videoPlayer;
|
||||
if (_player != null && _player.isPrepared)
|
||||
{
|
||||
EditorGUI.BeginDisabledGroup(true);
|
||||
float _StandardTime = _player.frame / (float)_player.frameCount;
|
||||
EditorGUILayout.LabelField(string.Format("Total number of players present: {0}", GetPresentPlayer(m_Curve, _StandardTime)), EditorStyles.label);
|
||||
EditorGUI.EndDisabledGroup();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (HeatmapViewModel.GetHeatpointToSessionMapping() == null || HeatmapViewModel.GetHeatpointToSessionMapping().Count() == 0)
|
||||
{
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.HelpBox("There is no data currently to display.", MessageType.Warning);
|
||||
}
|
||||
}
|
||||
|
||||
AnimationCurve CreateFunnel()
|
||||
{
|
||||
AnimationCurve curve = new AnimationCurve();
|
||||
|
||||
Dictionary<float, int> _CountTable = new Dictionary<float, int>();
|
||||
|
||||
foreach (KeyValuePair<string, HeatPoint[]> kv in HeatmapViewModel.GetHeatpointToSessionMapping())
|
||||
{
|
||||
for (int i = 0; i < kv.Value.Length; i++)
|
||||
{
|
||||
if (_CountTable.ContainsKey(kv.Value[i].time))
|
||||
{
|
||||
_CountTable[kv.Value[i].time] = _CountTable[kv.Value[i].time] + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
_CountTable.Add(kv.Value[i].time, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (float m_time in _CountTable.Keys)
|
||||
{
|
||||
curve.AddKey(m_time, _CountTable[m_time]);
|
||||
}
|
||||
|
||||
return curve;
|
||||
}
|
||||
|
||||
int GetPresentPlayer(AnimationCurve curve, float time)
|
||||
{
|
||||
if (curve.keys.Length == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (time > 1f || time < 0f)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (int)curve.Evaluate(time);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 61597699cb653465786a93e272bef2fa
|
||||
timeCreated: 1438296107
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,173 @@
|
|||
/// <summary>
|
||||
/// Heatmapper inspector.
|
||||
/// </summary>
|
||||
/// This code drives the Heatmapper inspector
|
||||
/// The HeatmapDataParser handles loading and parsing the data.
|
||||
/// The HeatmapRendererInspector speaks to the Renderer to achieve a desired look.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using UnityAnalytics360VideoHeatmap;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Video;
|
||||
using System;
|
||||
|
||||
namespace UnityAnalytics360VideoHeatmap
|
||||
{
|
||||
public class Heatmapper : EditorWindow
|
||||
{
|
||||
[MenuItem("Window/Unity Analytics/360 Video Heatmaps/Heatmapper")]
|
||||
static void HeatmapperMenuOption()
|
||||
{
|
||||
EditorWindow.GetWindow(typeof(Heatmapper));
|
||||
}
|
||||
|
||||
static Texture m_HeatmapperIconTexture;
|
||||
|
||||
// Views
|
||||
AggregationInspector m_AggregationView;
|
||||
HeatmapRendererInspector m_RenderView;
|
||||
|
||||
// Data handler
|
||||
HeatmapDataProcessor m_Processor;
|
||||
|
||||
//ViewModel
|
||||
HeatmapViewModel viewModel;
|
||||
|
||||
GameObject m_HeatMapInstance;
|
||||
|
||||
Vector2 m_ScrollPosition;
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
EnsureHeatmapInstance();
|
||||
viewModel = HeatmapViewModel.instance;
|
||||
m_Processor = new HeatmapDataProcessor();
|
||||
m_Processor.RestoreSettings();
|
||||
m_RenderView = HeatmapRendererInspector.Init(this, m_Processor);
|
||||
m_AggregationView = AggregationInspector.Init(m_Processor);
|
||||
m_AggregationView.OnEnable();
|
||||
m_HeatmapperIconTexture = Resources.Load("unity_analytics_heatmaps_heatmapper") as Texture;
|
||||
viewModel.ManualOverride();
|
||||
|
||||
}
|
||||
|
||||
void OnFocus()
|
||||
{
|
||||
SystemProcess();
|
||||
}
|
||||
|
||||
void OnGUI()
|
||||
{
|
||||
if (Event.current.type == EventType.Layout)
|
||||
{
|
||||
EnsureHeatmapInstance();
|
||||
}
|
||||
|
||||
// Guistyle
|
||||
GUIStyle m_boxStyle = new GUIStyle("box");
|
||||
m_boxStyle.padding = new RectOffset(6, 6, 8, 8);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.LabelField(new GUIContent(" 360 Video Heatmapper", m_HeatmapperIconTexture), EditorStyles.boldLabel);
|
||||
|
||||
using (new EditorGUILayout.VerticalScope(m_boxStyle))
|
||||
{
|
||||
using (var scroll = new EditorGUILayout.ScrollViewScope(m_ScrollPosition))
|
||||
{
|
||||
m_ScrollPosition = scroll.scrollPosition;
|
||||
|
||||
using (new EditorGUILayout.VerticalScope())
|
||||
{
|
||||
m_AggregationView.OnGUI();
|
||||
}
|
||||
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
//TODO: Clean up
|
||||
EditorGUILayout.LabelField("Video Player", EditorStyles.boldLabel, GUILayout.Width(EditorGUIUtility.labelWidth - 4));
|
||||
var temp = EditorGUILayout.ObjectField(HeatmapViewModel.videoPlayer, typeof(VideoPlayer), allowSceneObjects: true) as VideoPlayer;
|
||||
if(temp != null)
|
||||
HeatmapViewModel.videoPlayer = temp;
|
||||
}
|
||||
|
||||
using (new EditorGUILayout.VerticalScope())
|
||||
{
|
||||
if (m_RenderView != null)
|
||||
{
|
||||
m_RenderView.OnGUI();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
Repaint();
|
||||
}
|
||||
|
||||
void SystemProcess()
|
||||
{
|
||||
EnsureHeatmapInstance();
|
||||
}
|
||||
|
||||
public void SwapRenderer(Type renderer)
|
||||
{
|
||||
AttemptReconnectWithHeatmapInstance();
|
||||
CreateHeatmapInstance(renderer);
|
||||
}
|
||||
|
||||
void EnsureHeatmapInstance()
|
||||
{
|
||||
AttemptReconnectWithHeatmapInstance();
|
||||
if (m_HeatMapInstance == null)
|
||||
{
|
||||
CreateHeatmapInstance();
|
||||
}
|
||||
if (m_RenderView != null)
|
||||
{
|
||||
m_RenderView.SetGameObject(m_HeatMapInstance);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to reconnect with a heatmap instance.
|
||||
/// </summary>
|
||||
void AttemptReconnectWithHeatmapInstance()
|
||||
{
|
||||
m_HeatMapInstance = GameObject.Find("UnityAnalytics__Heatmap");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the heat map instance.
|
||||
/// </summary>
|
||||
void CreateHeatmapInstance(bool force = false)
|
||||
{
|
||||
if (force)
|
||||
{
|
||||
DestroyHeatmapInstance();
|
||||
}
|
||||
CreateHeatmapInstance(typeof(VideoRenderer));
|
||||
}
|
||||
|
||||
void CreateHeatmapInstance(Type t)
|
||||
{
|
||||
DestroyHeatmapInstance();
|
||||
m_HeatMapInstance = new GameObject();
|
||||
m_HeatMapInstance.tag = "EditorOnly";
|
||||
m_HeatMapInstance.name = "UnityAnalytics__Heatmap";
|
||||
m_HeatMapInstance.AddComponent(t);
|
||||
m_HeatMapInstance.GetComponent<IHeatmapRenderer>().allowRender = true;
|
||||
}
|
||||
|
||||
void DestroyHeatmapInstance()
|
||||
{
|
||||
if (m_HeatMapInstance)
|
||||
{
|
||||
m_HeatMapInstance.transform.parent = null;
|
||||
DestroyImmediate(m_HeatMapInstance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 37d29778284e24f8186804b8cfa2a858
|
||||
timeCreated: 1437429523
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 4923726aa9e5a4d07a43247389e81ebc
|
||||
folderAsset: yes
|
||||
timeCreated: 1509999757
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,688 @@
|
|||
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using UnityAnalytics360VideoHeatmap;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections;
|
||||
using UnityAnalytics;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
|
||||
namespace UnityAnalytics360VideoHeatmap
|
||||
{
|
||||
public class RawDataInspector : EditorWindow
|
||||
{
|
||||
private static string k_FetchKey = "UnityAnalyticsRawDataGenFetchKey";
|
||||
private static string k_Installed = "UnityAnalyticsRawDataGenInstallKey";
|
||||
private static string k_StartDate = "UnityAnalyticsRawDataStartDateKey";
|
||||
private static string k_EndDate = "UnityAnalyticsRawDataEndDateKey";
|
||||
private static string k_DataPathKey = "UnityAnalyticsRawDataGenDataPath";
|
||||
private static string k_DeviceCountKey = "UnityAnalyticsRawDataGenDeviceCount";
|
||||
private static string k_SessionCountKey = "UnityAnalyticsRawDataGenSessionCount";
|
||||
private static string k_EventNamesKey = "UnityAnalyticsRawDataGenEventNames";
|
||||
private static string k_CustomEventsKey = "UnityAnalyticsRawDataGenCustomEvents";
|
||||
private static string k_EventCountKey = "UnityAnalyticsRawDataGenEventCount";
|
||||
|
||||
private static string k_IncludeTimeKey = "UnityAnalyticsRawDataGenIncludeTime";
|
||||
|
||||
private static string k_IncludeLevelKey = "UnityAnalyticsRawDataGenIncludeLevel";
|
||||
private static string k_MinLevel = "UnityAnalyticsRawDataGenMinLevel";
|
||||
private static string k_MaxLevel = "UnityAnalyticsRawDataGenMaxLevel";
|
||||
|
||||
private static string k_IncludeFPSKey = "UnityAnalyticsRawDataGenIncludeFPS";
|
||||
private static string k_MinFPS = "UnityAnalyticsRawDataGenMinFPS";
|
||||
private static string k_MaxFPS = "UnityAnalyticsRawDataGenMaxFPS";
|
||||
|
||||
private static string k_IncludeXKey = "UnityAnalyticsRawDataGenIncludeX";
|
||||
private static string k_MinX = "UnityAnalyticsRawDataGenMinX";
|
||||
private static string k_MaxX = "UnityAnalyticsRawDataGenMaxX";
|
||||
|
||||
private static string k_IncludeYKey = "UnityAnalyticsRawDataGenIncludeY";
|
||||
private static string k_MinY = "UnityAnalyticsRawDataGenMinY";
|
||||
private static string k_MaxY = "UnityAnalyticsRawDataGenMaxY";
|
||||
|
||||
private static string k_IncludeZKey = "UnityAnalyticsRawDataGenIncludeZ";
|
||||
private static string k_MinZ = "UnityAnalyticsRawDataGenMinZ";
|
||||
private static string k_MaxZ = "UnityAnalyticsRawDataGenMaxZ";
|
||||
|
||||
private static string k_RotationKey = "UnityAnalyticsRawDataGenRotation";
|
||||
private static string k_MinRX = "UnityAnalyticsRawDataGenMinRX";
|
||||
private static string k_MaxRX = "UnityAnalyticsRawDataGenMaxRX";
|
||||
private static string k_MinRY = "UnityAnalyticsRawDataGenMinRY";
|
||||
private static string k_MaxRY = "UnityAnalyticsRawDataGenMaxRY";
|
||||
private static string k_MinRZ = "UnityAnalyticsRawDataGenMinRZ";
|
||||
private static string k_MaxRZ = "UnityAnalyticsRawDataGenMaxRZ";
|
||||
|
||||
private static string k_MinDX = "UnityAnalyticsRawDataGenMinDX";
|
||||
private static string k_MaxDX = "UnityAnalyticsRawDataGenMaxDX";
|
||||
private static string k_MinDY = "UnityAnalyticsRawDataGenMinDY";
|
||||
private static string k_MaxDY = "UnityAnalyticsRawDataGenMaxDY";
|
||||
private static string k_MinDZ = "UnityAnalyticsRawDataGenMinDZ";
|
||||
private static string k_MaxDZ = "UnityAnalyticsRawDataGenMaxDZ";
|
||||
|
||||
private static Color s_BoxColor = new Color(.9f, .9f, .9f);
|
||||
|
||||
private GUIContent m_AddEventContent = new GUIContent("+ Event Name", "Events to be randomly added into the created data.");
|
||||
|
||||
private GUIContent m_UpidContent = new GUIContent("UPID", "Copy the Unity Project ID from Services > Settings or the 'Editing Project' page of your project dashboard");
|
||||
private GUIContent m_SecretKeyContent = new GUIContent("API Key", "Copy the key from the 'Editing Project' page of your project dashboard");
|
||||
private GUIContent m_StartDateContent = new GUIContent("Start Date (YYYY-MM-DD)", "Start date as ISO-8601 datetime");
|
||||
private GUIContent m_EndDateContent = new GUIContent("End Date (YYYY-MM-DD)", "End date as ISO-8601 datetime");
|
||||
|
||||
private GUIContent m_ContinueJobContent = new GUIContent(">", "Continue job");
|
||||
private GUIContent m_DownloadJobContent = new GUIContent("Download", "Download job files");
|
||||
private GUIContent m_GetJobsContent = new GUIContent("Get Jobs", "Load the manifest of job files");
|
||||
private GUIContent m_DownloadAllContent = new GUIContent("Download All", "Download the files for all jobs");
|
||||
|
||||
private GUIContent m_FailedContent;
|
||||
private GUIContent m_CompleteContent;
|
||||
private GUIContent m_RunningContent;
|
||||
|
||||
private static int defaultEventCount = 100;
|
||||
private static int defaultDeviceCount = 5;
|
||||
private static int defaultSessionCount = 10;
|
||||
private static float defaultMinAngle = 0f;
|
||||
private static float defaultMaxAngle = 360f;
|
||||
private static float defaultMinSpace = -100f;
|
||||
private static float defaultMaxSpace = 100f;
|
||||
private static int defaultRotational = 0;
|
||||
private static int defaultMinLevel = 1;
|
||||
private static int defaultMaxLevel = 99;
|
||||
private static float defaultMinFPS = 1f;
|
||||
private static float defaultMaxFPS = 99f;
|
||||
|
||||
public const string headers = "ts\tappid\ttype\tuserid\tsessionid\tremote_ip\tplatform\tsdk_ver\tdebug_device\tuser_agent\tsubmit_time\tname\tcustom_params\n";
|
||||
|
||||
[MenuItem("Window/Unity Analytics/360 Video Heatmaps/Raw Data")]
|
||||
static void RawDataInspectorMenuOption()
|
||||
{
|
||||
EditorWindow.GetWindow(typeof(RawDataInspector));
|
||||
}
|
||||
|
||||
string m_DataPath = "";
|
||||
bool m_ValidManifest = false;
|
||||
|
||||
int m_EventCount = defaultEventCount;
|
||||
int m_DeviceCount = defaultDeviceCount;
|
||||
int m_SessionCount = defaultSessionCount;
|
||||
|
||||
string m_AppId = "";
|
||||
string m_SecretKey = "";
|
||||
string m_StartDate = "";
|
||||
string m_EndDate = "";
|
||||
|
||||
List<RawDataReport> m_Jobs = null;
|
||||
bool[] m_JobFoldouts;
|
||||
|
||||
int m_DataSource = 0;
|
||||
static int FETCH = 0;
|
||||
List<string> m_EventNames = new List<string> { };
|
||||
|
||||
bool m_IncludeTime = true;
|
||||
|
||||
bool m_IncludeX = true;
|
||||
float m_MinX = defaultMinSpace;
|
||||
float m_MaxX = defaultMaxSpace;
|
||||
|
||||
bool m_IncludeY = true;
|
||||
float m_MinY = defaultMinSpace;
|
||||
float m_MaxY = defaultMaxSpace;
|
||||
|
||||
bool m_IncludeZ = true;
|
||||
float m_MinZ = defaultMinSpace;
|
||||
float m_MaxZ = defaultMaxSpace;
|
||||
|
||||
// Flag for rotation vs destination
|
||||
int m_Rotational = defaultRotational;
|
||||
|
||||
float m_MinRX = defaultMinAngle;
|
||||
float m_MaxRX = defaultMaxAngle;
|
||||
float m_MinRY = defaultMinAngle;
|
||||
float m_MaxRY = defaultMaxAngle;
|
||||
float m_MinRZ = defaultMinAngle;
|
||||
float m_MaxRZ = defaultMaxAngle;
|
||||
|
||||
float m_MinDX = defaultMinSpace;
|
||||
float m_MaxDX = defaultMaxSpace;
|
||||
float m_MinDY = defaultMinSpace;
|
||||
float m_MaxDY = defaultMaxSpace;
|
||||
float m_MinDZ = defaultMinSpace;
|
||||
float m_MaxDZ = defaultMaxSpace;
|
||||
|
||||
bool m_IncludeLevel = false;
|
||||
int m_MinLevel = defaultMinLevel;
|
||||
int m_MaxLevel = defaultMaxLevel;
|
||||
|
||||
bool m_IncludeFPS = false;
|
||||
float m_MinFPS = defaultMinFPS;
|
||||
float m_MaxFPS = defaultMaxFPS;
|
||||
|
||||
Vector2 m_ScrollPosition;
|
||||
|
||||
RawDataClient m_RawDataClient;
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
if (m_RawDataClient == null)
|
||||
{
|
||||
Texture2D failedIcon = Resources.Load("unity_analytics_heatmaps_failed") as Texture2D;
|
||||
Texture2D completeIcon = Resources.Load("unity_analytics_heatmaps_success") as Texture2D;
|
||||
Texture2D runningIcon = Resources.Load("unity_analytics_heatmaps_running") as Texture2D;
|
||||
|
||||
m_RawDataClient = RawDataClient.GetInstance();
|
||||
if (m_DataSource == FETCH && !m_ValidManifest)
|
||||
{
|
||||
m_RawDataClient.GetJobs(GetJobsCompletionHandler);
|
||||
m_ValidManifest = true;
|
||||
}
|
||||
titleContent = new GUIContent("Raw Data");
|
||||
|
||||
m_FailedContent = new GUIContent(failedIcon, "Status: Failed");
|
||||
m_CompleteContent = new GUIContent(completeIcon, "Status: Completed");
|
||||
m_RunningContent = new GUIContent(runningIcon, "Status: Running");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void OnFocus()
|
||||
{
|
||||
if (EditorPrefs.GetBool(k_Installed))
|
||||
{
|
||||
RestoreValues();
|
||||
}
|
||||
else
|
||||
{
|
||||
SetInitValues();
|
||||
}
|
||||
}
|
||||
|
||||
void OnGUI()
|
||||
{
|
||||
EditorPrefs.SetString(k_DataPathKey, m_DataPath);
|
||||
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
if (GUILayout.Button("Reset"))
|
||||
{
|
||||
if (EditorUtility.DisplayDialog("Resetting to factory defaults", "Are you sure?", "Reset", "Cancel"))
|
||||
{
|
||||
SetInitValues();
|
||||
}
|
||||
}
|
||||
if (GUILayout.Button("Open Folder"))
|
||||
{
|
||||
EditorUtility.RevealInFinder(m_DataPath + "/RawDataFolder");
|
||||
}
|
||||
}
|
||||
|
||||
//output path
|
||||
m_DataPath = Application.dataPath;
|
||||
|
||||
using (new GUILayout.VerticalScope("box"))
|
||||
{
|
||||
EditorGUILayout.LabelField("Output path", EditorStyles.boldLabel);
|
||||
EditorGUILayout.SelectableLabel(m_DataPath + "/RawDataFolder");
|
||||
}
|
||||
|
||||
if (m_DataSource == FETCH)
|
||||
{
|
||||
OnGUIFetchView();
|
||||
}
|
||||
}
|
||||
|
||||
void OnGUIFetchView()
|
||||
{
|
||||
if (Event.current.type == EventType.Layout)
|
||||
{
|
||||
m_RawDataClient.TestFilesAreLocal(m_Jobs);
|
||||
}
|
||||
|
||||
using (new GUILayout.VerticalScope("box"))
|
||||
{
|
||||
string oldKey = m_SecretKey;
|
||||
m_AppId = EditorGUILayout.TextField(m_UpidContent, m_AppId);
|
||||
RestoreAppId();
|
||||
m_SecretKey = EditorGUILayout.TextField(m_SecretKeyContent, m_SecretKey);
|
||||
|
||||
m_RawDataClient.m_DataPath = m_DataPath;
|
||||
m_RawDataClient.m_AppId = m_AppId;
|
||||
m_RawDataClient.m_SecretKey = m_SecretKey;
|
||||
|
||||
if (oldKey != m_SecretKey && !string.IsNullOrEmpty(m_SecretKey))
|
||||
{
|
||||
EditorPrefs.SetString(k_FetchKey, m_SecretKey);
|
||||
}
|
||||
}
|
||||
|
||||
using (new GUILayout.VerticalScope("box"))
|
||||
{
|
||||
GUILayout.Label("New Job", EditorStyles.boldLabel);
|
||||
|
||||
var oldStartDate = m_StartDate;
|
||||
var oldEndDate = m_EndDate;
|
||||
m_StartDate = EditorGUILayout.TextField(m_StartDateContent, m_StartDate);
|
||||
m_EndDate = EditorGUILayout.TextField(m_EndDateContent, m_EndDate);
|
||||
if (oldStartDate != m_StartDate || oldEndDate != m_EndDate)
|
||||
{
|
||||
EditorPrefs.SetString(k_StartDate, m_StartDate);
|
||||
EditorPrefs.SetString(k_EndDate, m_EndDate);
|
||||
}
|
||||
if (GUILayout.Button("Create Job"))
|
||||
{
|
||||
RawDataReport report = null;
|
||||
try
|
||||
{
|
||||
DateTime startDate = DateTime.Parse(m_StartDate).ToUniversalTime();
|
||||
DateTime endDate = DateTime.Parse(m_EndDate).ToUniversalTime();
|
||||
report = m_RawDataClient.CreateJob("custom", startDate, endDate);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string exText = "Unknown exception.";
|
||||
if (ex is FormatException)
|
||||
{
|
||||
exText = "Date formats appear to be incorrect. Start and End Dates must be ISO-8601 format (YYYY-MM-DD).";
|
||||
}
|
||||
else if (ex is WebException)
|
||||
{
|
||||
WebException webEx = ex as WebException;
|
||||
exText = webEx.Message;
|
||||
}
|
||||
EditorUtility.DisplayDialog("Can't create job", exText, "OK");
|
||||
}
|
||||
if (m_Jobs == null)
|
||||
{
|
||||
m_Jobs = new List<RawDataReport>();
|
||||
}
|
||||
if (report != null)
|
||||
{
|
||||
m_Jobs.Add(report);
|
||||
}
|
||||
m_JobFoldouts = m_Jobs.Select(fb => false).ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
using (new GUILayout.VerticalScope("box"))
|
||||
{
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
if (GUILayout.Button(m_GetJobsContent))
|
||||
{
|
||||
m_RawDataClient.GetJobs(GetJobsCompletionHandler);
|
||||
}
|
||||
if (GUILayout.Button(m_DownloadAllContent))
|
||||
{
|
||||
m_RawDataClient.DownloadAll(m_Jobs);
|
||||
}
|
||||
}
|
||||
m_ScrollPosition = EditorGUILayout.BeginScrollView(m_ScrollPosition);
|
||||
if (m_Jobs != null)
|
||||
{
|
||||
for (int a = m_Jobs.Count - 1; a > -1; a--)
|
||||
{
|
||||
var job = m_Jobs[a];
|
||||
string start = String.Format("{0:yyyy-MM-dd}", job.request.startDate);
|
||||
string end = String.Format("{0:yyyy-MM-dd}", job.request.endDate);
|
||||
string shortStart = String.Format("{0:MM-dd}", job.request.startDate);
|
||||
string shortEnd = String.Format("{0:MM-dd}", job.request.endDate);
|
||||
string created = String.Format("{0:yyyy-MM-dd hh:mm:ss}", job.createdAt);
|
||||
string type = job.request.dataset;
|
||||
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
float windowWidth = EditorGUIUtility.currentViewWidth;
|
||||
float foldoutWidth = windowWidth * .5f;
|
||||
float downloadButtonWidth = 75f;
|
||||
float continueButtonWidth = 25f;
|
||||
float downloadedWidth = downloadButtonWidth;
|
||||
float statusWidth = 20f;
|
||||
|
||||
GUIContent foldoutContent = new GUIContent(type + ": " + shortStart + " to " + shortEnd, start + " — " + end + "\n" + job.id);
|
||||
Rect pos = GUILayoutUtility.GetRect(foldoutContent, "foldout");
|
||||
Rect rect = new Rect(pos.x, pos.y, foldoutWidth, 20f);
|
||||
m_JobFoldouts[a] = EditorGUI.Foldout(
|
||||
rect,
|
||||
m_JobFoldouts[a],
|
||||
foldoutContent,
|
||||
true
|
||||
);
|
||||
|
||||
var statusContent = m_CompleteContent;
|
||||
switch (job.status)
|
||||
{
|
||||
case RawDataReport.Failed:
|
||||
statusContent = m_FailedContent;
|
||||
break;
|
||||
case RawDataReport.Running:
|
||||
statusContent = m_RunningContent;
|
||||
break;
|
||||
}
|
||||
GUILayout.Label(statusContent, GUILayout.Width(statusWidth));
|
||||
|
||||
if (job.status == RawDataReport.Completed)
|
||||
{
|
||||
if (job.isLocal)
|
||||
{
|
||||
GUILayout.Label("Downloaded", GUILayout.Width(downloadedWidth));
|
||||
}
|
||||
else if (job.result != null && job.result.size == 0)
|
||||
{
|
||||
GUILayout.Label("No Data", GUILayout.Width(downloadedWidth));
|
||||
}
|
||||
else if (GUILayout.Button(m_DownloadJobContent, GUILayout.Width(downloadButtonWidth)))
|
||||
{
|
||||
m_RawDataClient.Download(job);
|
||||
}
|
||||
if (GUILayout.Button(m_ContinueJobContent, GUILayout.Width(continueButtonWidth)))
|
||||
{
|
||||
RawDataReport report = m_RawDataClient.ContinueFromJob(job);
|
||||
m_Jobs.Add(report);
|
||||
m_JobFoldouts = m_Jobs.Select(fb => false).ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (m_JobFoldouts[a])
|
||||
{
|
||||
Color defaultColor = GUI.color;
|
||||
GUI.backgroundColor = s_BoxColor;
|
||||
using (new GUILayout.VerticalScope("box"))
|
||||
{
|
||||
GUILayout.Label("ID: " + job.id);
|
||||
GUILayout.Label("Created: " + created);
|
||||
GUILayout.Label("Duration: " + (job.duration / 1000) + " seconds");
|
||||
if (job.result != null)
|
||||
{
|
||||
GUILayout.Label("# Events: " + job.result.eventCount);
|
||||
GUILayout.Label("# Bytes: " + job.result.size);
|
||||
GUILayout.Label("# Files: " + job.result.fileList.Count);
|
||||
GUILayout.Label("Partial day: " + job.result.intraDay);
|
||||
}
|
||||
}
|
||||
GUI.backgroundColor = defaultColor;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_Jobs.Count == 0)
|
||||
{
|
||||
GUILayout.Label("No jobs found", EditorStyles.boldLabel);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GUILayout.Label("No data yet", EditorStyles.boldLabel);
|
||||
}
|
||||
GUILayout.Space(10f);
|
||||
EditorGUILayout.EndScrollView();
|
||||
}
|
||||
|
||||
|
||||
|
||||
using (new GUILayout.HorizontalScope())
|
||||
{
|
||||
if (GUILayout.Button("Purge"))
|
||||
{
|
||||
PurgeData();
|
||||
}
|
||||
if (GUILayout.Button("Dashboard"))
|
||||
{
|
||||
Application.OpenURL(m_RawDataClient.DashboardPath);
|
||||
}
|
||||
if (GUILayout.Button("Project Config"))
|
||||
{
|
||||
Application.OpenURL(m_RawDataClient.ConfigPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void GetJobsCompletionHandler(bool success, List<RawDataReport> list, string reason = "")
|
||||
{
|
||||
m_Jobs = list;
|
||||
m_JobFoldouts = m_Jobs.Select(fb => false).ToArray();
|
||||
}
|
||||
|
||||
void CreateHeadersFile()
|
||||
{
|
||||
SaveFile(headers, "custom_headers.gz", true);
|
||||
}
|
||||
|
||||
void CreateManifestFile(List<RawDataReport> list)
|
||||
{
|
||||
var manifest = m_RawDataClient.GenerateManifest(list);
|
||||
SaveFile(manifest, "manifest.json", false);
|
||||
}
|
||||
|
||||
bool IncludeSet(ref bool value, string label, string key, bool force = false)
|
||||
{
|
||||
string tooltip = force ? label + " must be included" : null;
|
||||
var content = new GUIContent(label, tooltip);
|
||||
EditorGUI.BeginDisabledGroup(force);
|
||||
value = EditorGUILayout.Toggle(content, value);
|
||||
EditorGUI.EndDisabledGroup();
|
||||
EditorPrefs.SetBool(key, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
void DrawFloatRange(ref float min, ref float max, string minKey, string maxKey)
|
||||
{
|
||||
float oldMin = min;
|
||||
min = EditorGUILayout.FloatField(min);
|
||||
if (oldMin != min)
|
||||
{
|
||||
EditorPrefs.SetFloat(minKey, min);
|
||||
}
|
||||
float oldMax = max;
|
||||
max = EditorGUILayout.FloatField(max);
|
||||
if (oldMax != max)
|
||||
{
|
||||
EditorPrefs.SetFloat(maxKey, max);
|
||||
}
|
||||
}
|
||||
|
||||
void DrawIntRange(ref int min, ref int max, string minKey, string maxKey)
|
||||
{
|
||||
int oldMin = min;
|
||||
min = EditorGUILayout.IntField(min);
|
||||
if (oldMin != min)
|
||||
{
|
||||
EditorPrefs.SetInt(minKey, min);
|
||||
}
|
||||
int oldMax = max;
|
||||
max = EditorGUILayout.IntField(max);
|
||||
if (oldMax != max)
|
||||
{
|
||||
EditorPrefs.SetInt(maxKey, max);
|
||||
}
|
||||
}
|
||||
|
||||
int SaveCustomFile(string data, double firstDate)
|
||||
{
|
||||
return SaveFile(data, firstDate + "_custom.gz", true);
|
||||
}
|
||||
|
||||
int SaveFile(string data, string fileName, bool compress)
|
||||
{
|
||||
string savePath = System.IO.Path.Combine(GetSavePath(), "RawDataFolder");
|
||||
// Create the save path if necessary
|
||||
if (!System.IO.Directory.Exists(savePath))
|
||||
{
|
||||
System.IO.Directory.CreateDirectory(savePath);
|
||||
}
|
||||
string outputFileName = fileName;
|
||||
string path = System.IO.Path.Combine(savePath, outputFileName);
|
||||
int size = 0;
|
||||
if (compress)
|
||||
{
|
||||
IonicGZip.CompressAndSave(path, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
using (System.IO.StreamWriter file =
|
||||
new System.IO.StreamWriter(path))
|
||||
{
|
||||
file.Write(data);
|
||||
}
|
||||
}
|
||||
System.IO.FileInfo fileInfo = new System.IO.FileInfo(path);
|
||||
size = (int)fileInfo.Length;
|
||||
return size;
|
||||
}
|
||||
|
||||
string GetSavePath()
|
||||
{
|
||||
return m_DataPath;
|
||||
}
|
||||
|
||||
public void PurgeData()
|
||||
{
|
||||
if (EditorUtility.DisplayDialog("Destroy local data?", "You are about to delete your local heatmaps data cache, meaning you'll have to reload from the server (or regenerate from this tool). Are you sure?", "Purge", "Cancel"))
|
||||
{
|
||||
string savePath = System.IO.Path.Combine(GetSavePath(), "RawDataFolder");
|
||||
if (System.IO.Directory.Exists(savePath))
|
||||
{
|
||||
System.IO.Directory.Delete(savePath, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void SetInitValues()
|
||||
{
|
||||
m_DataPath = "";
|
||||
m_IncludeTime = true;
|
||||
m_IncludeX = m_IncludeY = m_IncludeZ = true;
|
||||
m_IncludeLevel = m_IncludeFPS = false;
|
||||
m_Rotational = defaultRotational;
|
||||
m_MinX = m_MinY = m_MinZ = m_MinDX = m_MinDY = m_MinDZ = defaultMinSpace;
|
||||
m_MaxX = m_MaxY = m_MaxZ = defaultMaxSpace;
|
||||
m_MinRX = m_MinRY = m_MinRZ = defaultMinAngle;
|
||||
m_MaxRX = m_MaxRY = m_MaxRZ = defaultMaxAngle;
|
||||
m_MinLevel = defaultMinLevel;
|
||||
m_MaxLevel = defaultMaxLevel;
|
||||
m_MinFPS = defaultMinFPS;
|
||||
m_MaxFPS = defaultMaxFPS;
|
||||
string[] eventsList = new string[] { "PlayerPosition" };
|
||||
m_EventNames = new List<string>(eventsList);
|
||||
|
||||
EditorPrefs.SetFloat(k_MinX, m_MinX);
|
||||
EditorPrefs.SetFloat(k_MinY, m_MinY);
|
||||
EditorPrefs.SetFloat(k_MinZ, m_MinZ);
|
||||
EditorPrefs.SetFloat(k_MinDX, m_MinDX);
|
||||
EditorPrefs.SetFloat(k_MinDY, m_MinDY);
|
||||
EditorPrefs.SetFloat(k_MinDZ, m_MinDZ);
|
||||
EditorPrefs.SetFloat(k_MaxX, m_MaxX);
|
||||
EditorPrefs.SetFloat(k_MaxY, m_MaxY);
|
||||
EditorPrefs.SetFloat(k_MaxZ, m_MaxZ);
|
||||
EditorPrefs.SetFloat(k_MaxDX, m_MaxDX);
|
||||
EditorPrefs.SetFloat(k_MaxDY, m_MaxDY);
|
||||
EditorPrefs.SetFloat(k_MaxDZ, m_MaxDZ);
|
||||
|
||||
EditorPrefs.SetFloat(k_MinRX, m_MinRX);
|
||||
EditorPrefs.SetFloat(k_MinRY, m_MinRY);
|
||||
EditorPrefs.SetFloat(k_MinRZ, m_MinRZ);
|
||||
EditorPrefs.SetFloat(k_MaxRX, m_MaxRX);
|
||||
EditorPrefs.SetFloat(k_MaxRY, m_MaxRY);
|
||||
EditorPrefs.SetFloat(k_MaxRZ, m_MaxRZ);
|
||||
|
||||
EditorPrefs.SetInt(k_MinLevel, m_MinLevel);
|
||||
EditorPrefs.SetInt(k_MaxLevel, m_MaxLevel);
|
||||
EditorPrefs.SetFloat(k_MinFPS, m_MinFPS);
|
||||
EditorPrefs.SetFloat(k_MaxFPS, m_MaxFPS);
|
||||
EditorPrefs.SetString(k_EventNamesKey, eventsList[0]);
|
||||
EditorPrefs.SetString(k_CustomEventsKey, eventsList[0]);
|
||||
EditorPrefs.SetInt(k_DeviceCountKey, m_DeviceCount);
|
||||
EditorPrefs.SetInt(k_SessionCountKey, m_SessionCount);
|
||||
EditorPrefs.SetBool(k_Installed, true);
|
||||
}
|
||||
|
||||
protected void RestoreAppId()
|
||||
{
|
||||
if (string.IsNullOrEmpty(m_AppId) && !string.IsNullOrEmpty(Application.cloudProjectId))
|
||||
{
|
||||
m_AppId = Application.cloudProjectId;
|
||||
}
|
||||
}
|
||||
|
||||
protected void RestoreValues()
|
||||
{
|
||||
RestoreAppId();
|
||||
|
||||
m_SecretKey = EditorPrefs.GetString(k_FetchKey, m_SecretKey);
|
||||
m_StartDate = EditorPrefs.GetString(k_StartDate, m_StartDate);
|
||||
m_EndDate = EditorPrefs.GetString(k_EndDate, m_EndDate);
|
||||
m_IncludeTime = EditorPrefs.GetBool(k_IncludeTimeKey, m_IncludeTime);
|
||||
m_IncludeX = EditorPrefs.GetBool(k_IncludeXKey, m_IncludeX);
|
||||
m_MinX = EditorPrefs.GetFloat(k_MinX, m_MinX);
|
||||
m_MaxX = EditorPrefs.GetFloat(k_MaxX, m_MaxX);
|
||||
m_IncludeY = EditorPrefs.GetBool(k_IncludeYKey, m_IncludeY);
|
||||
m_MinY = EditorPrefs.GetFloat(k_MinY, m_MinY);
|
||||
m_MaxY = EditorPrefs.GetFloat(k_MaxY, m_MaxY);
|
||||
m_IncludeZ = EditorPrefs.GetBool(k_IncludeZKey, m_IncludeZ);
|
||||
m_MinZ = EditorPrefs.GetFloat(k_MinZ, m_MinZ);
|
||||
m_MaxZ = EditorPrefs.GetFloat(k_MaxZ, m_MaxZ);
|
||||
|
||||
m_Rotational = EditorPrefs.GetInt(k_RotationKey, m_Rotational);
|
||||
m_MinRX = EditorPrefs.GetFloat(k_MinRX, m_MinRX);
|
||||
m_MaxRX = EditorPrefs.GetFloat(k_MaxRX, m_MaxRX);
|
||||
m_MinRY = EditorPrefs.GetFloat(k_MinRY, m_MinRY);
|
||||
m_MaxRY = EditorPrefs.GetFloat(k_MaxRY, m_MaxRY);
|
||||
m_MinRZ = EditorPrefs.GetFloat(k_MinRZ, m_MinRZ);
|
||||
m_MaxRZ = EditorPrefs.GetFloat(k_MaxRZ, m_MaxRZ);
|
||||
|
||||
m_MinDX = EditorPrefs.GetFloat(k_MinDX, m_MinDX);
|
||||
m_MaxDX = EditorPrefs.GetFloat(k_MaxDX, m_MaxDX);
|
||||
m_MinDY = EditorPrefs.GetFloat(k_MinDY, m_MinDY);
|
||||
m_MaxDY = EditorPrefs.GetFloat(k_MaxDY, m_MaxDY);
|
||||
m_MinDZ = EditorPrefs.GetFloat(k_MinDZ, m_MinDZ);
|
||||
m_MaxDZ = EditorPrefs.GetFloat(k_MaxDZ, m_MaxDZ);
|
||||
|
||||
m_IncludeLevel = EditorPrefs.GetBool(k_IncludeLevelKey, m_IncludeLevel);
|
||||
m_MinLevel = EditorPrefs.GetInt(k_MinLevel, m_MinLevel);
|
||||
m_MaxLevel = EditorPrefs.GetInt(k_MaxLevel, m_MaxLevel);
|
||||
|
||||
m_IncludeFPS = EditorPrefs.GetBool(k_IncludeFPSKey, m_IncludeFPS);
|
||||
m_MinFPS = EditorPrefs.GetFloat(k_MinFPS, m_MinFPS);
|
||||
m_MaxFPS = EditorPrefs.GetFloat(k_MaxFPS, m_MaxFPS);
|
||||
|
||||
m_EventCount = EditorPrefs.GetInt(k_EventCountKey, m_EventCount);
|
||||
string loadedEventNames = EditorPrefs.GetString(k_EventNamesKey);
|
||||
string[] eventNamesList;
|
||||
if (string.IsNullOrEmpty(loadedEventNames))
|
||||
{
|
||||
eventNamesList = new string[] { };
|
||||
}
|
||||
else
|
||||
{
|
||||
eventNamesList = loadedEventNames.Split('|');
|
||||
}
|
||||
m_EventNames = new List<string>(eventNamesList);
|
||||
}
|
||||
|
||||
void ViewEventNames()
|
||||
{
|
||||
string oldEventsString = string.Join("|", m_EventNames.ToArray());
|
||||
if (GUILayout.Button(m_AddEventContent))
|
||||
{
|
||||
m_EventNames.Add("Event name");
|
||||
}
|
||||
for (var a = 0; a < m_EventNames.Count; a++)
|
||||
{
|
||||
using (new GUILayout.HorizontalScope())
|
||||
{
|
||||
if (GUILayout.Button("-", GUILayout.MaxWidth(20f)))
|
||||
{
|
||||
m_EventNames.RemoveAt(a);
|
||||
break;
|
||||
}
|
||||
m_EventNames[a] = EditorGUILayout.TextField(m_EventNames[a]);
|
||||
}
|
||||
}
|
||||
string currentEventsString = string.Join("|", m_EventNames.ToArray());
|
||||
|
||||
if (oldEventsString != currentEventsString)
|
||||
{
|
||||
EditorPrefs.SetString(k_EventNamesKey, currentEventsString);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d0c2ffc68c6f4488a8b8e328a9049f83
|
||||
timeCreated: 1461961853
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6ee84e478a26b43ed897ed7b69c9b6ff
|
||||
folderAsset: yes
|
||||
timeCreated: 1437429523
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 539cd1dc7f3cb4859928b76482359a8f
|
||||
folderAsset: yes
|
||||
timeCreated: 1509999950
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,78 @@
|
|||
using System;
|
||||
using UnityEngine;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Ionic.Zlib;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
||||
public class IonicGZip
|
||||
{
|
||||
|
||||
public static string[] DecompressFiles(string[] args)
|
||||
{
|
||||
var results = new List<string>();
|
||||
foreach(var fileName in args)
|
||||
{
|
||||
string response = DecompressFile(fileName);
|
||||
results.Add(response);
|
||||
}
|
||||
return results.ToArray();
|
||||
}
|
||||
|
||||
public static string DecompressFile(string fileName)
|
||||
{
|
||||
byte[] file = File.ReadAllBytes(fileName);
|
||||
byte[] decompressed = Decompress(file);
|
||||
return Encoding.UTF8.GetString(decompressed);
|
||||
}
|
||||
|
||||
static byte[] Decompress(byte[] gzip)
|
||||
{
|
||||
// Create a GZIP stream with decompression mode.
|
||||
// ... Then create a buffer and write into while reading from the GZIP stream.
|
||||
using (GZipStream stream = new GZipStream(new MemoryStream(gzip), CompressionMode.Decompress))
|
||||
{
|
||||
const int size = 4096;
|
||||
byte[] buffer = new byte[size];
|
||||
using (MemoryStream memory = new MemoryStream())
|
||||
{
|
||||
int count = 0;
|
||||
do
|
||||
{
|
||||
count = stream.Read(buffer, 0, size);
|
||||
if (count > 0)
|
||||
{
|
||||
memory.Write(buffer, 0, count);
|
||||
}
|
||||
}
|
||||
while (count > 0);
|
||||
return memory.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void CompressAndSave(string savePath, string data)
|
||||
{
|
||||
// Write string to temporary file.
|
||||
string temp = Path.GetTempFileName();
|
||||
File.WriteAllText(temp, data);
|
||||
|
||||
// Read file into byte array buffer.
|
||||
byte[] b;
|
||||
using (FileStream f = new FileStream(temp, FileMode.Open))
|
||||
{
|
||||
b = new byte[f.Length];
|
||||
f.Read(b, 0, (int)f.Length);
|
||||
}
|
||||
|
||||
// Use GZipStream to write compressed bytes to target file.
|
||||
using (FileStream f2 = new FileStream(savePath, FileMode.Create))
|
||||
{
|
||||
using (GZipStream gz = new GZipStream(f2, CompressionMode.Compress, false))
|
||||
{
|
||||
gz.Write(b, 0, b.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f7fd47e454afe48218b7d4e1e5e221d3
|
||||
timeCreated: 1464048959
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c5c608afd7add48c88e7fdc16c3a391e
|
||||
folderAsset: yes
|
||||
timeCreated: 1437429523
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 563986ea2eed04fdcb7b9b2fa6556ea3
|
||||
folderAsset: yes
|
||||
timeCreated: 1512760550
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,225 @@
|
|||
/// <summary>
|
||||
/// Adapter API for sending Heatmap analytics events
|
||||
/// </summary>
|
||||
/// This is <i>simply</i> an adapter. As such, you could choose not to
|
||||
/// use it at all, but by passing your events through this API you gain type
|
||||
/// safety and ensure that you're conforming to the data that the aggregator
|
||||
/// and Heatmapper expect to receive.
|
||||
///
|
||||
/// The script is designed to work in Unity 4.6 > 5.x
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using System.IO;
|
||||
|
||||
using analyticsResultNamespace = UnityEngine.Analytics;
|
||||
using analyticsEventNamespace = UnityEngine.Analytics.Analytics;
|
||||
|
||||
namespace UnityAnalytics360VideoHeatmap
|
||||
{
|
||||
public class HeatmapEvent
|
||||
{
|
||||
private static Dictionary<string, object> s_Dictionary = new Dictionary<string, object>();
|
||||
|
||||
private static bool s_SaveToLocal = false;
|
||||
private static string s_LocalSavePath;
|
||||
|
||||
private static string s_SessionId;
|
||||
|
||||
/// <summary>
|
||||
/// When set to true, HeatmapEvents are saved to a local file, instead of sent to the server.
|
||||
/// </summary>
|
||||
/// <param name="value">If set to <c>true</c> save to a local file.</param>
|
||||
public static bool saveToLocal
|
||||
{
|
||||
get
|
||||
{
|
||||
return s_SaveToLocal;
|
||||
}
|
||||
set
|
||||
{
|
||||
s_SaveToLocal = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the local save path.
|
||||
/// </summary>
|
||||
/// <value>The path on the local drive where HeatmapEvents will be saved.</param>
|
||||
public static string localSavePath
|
||||
{
|
||||
get
|
||||
{
|
||||
return s_LocalSavePath;
|
||||
}
|
||||
set
|
||||
{
|
||||
s_LocalSavePath = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send the event with position, rotation, time and an optional dictionary.
|
||||
/// </summary>
|
||||
public static analyticsResultNamespace.AnalyticsResult Send(string eventName, Transform trans, float time, Dictionary<string, object> options = null)
|
||||
{
|
||||
AddXY(trans.position.x, trans.position.y);
|
||||
AddZ(trans.position.z);
|
||||
AddRotation(trans.forward);
|
||||
AddTime(time);
|
||||
AddOptions(options);
|
||||
return Commit(eventName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Transmit the event
|
||||
/// </summary>
|
||||
protected static analyticsResultNamespace.AnalyticsResult Commit(string eventName)
|
||||
{
|
||||
analyticsResultNamespace.AnalyticsResult result;
|
||||
if (s_SaveToLocal)
|
||||
{
|
||||
string path = String.IsNullOrEmpty(s_LocalSavePath) ? System.IO.Path.Combine(Application.dataPath, "RawDataFolder") : s_LocalSavePath;
|
||||
result = analyticsResultNamespace.AnalyticsResult.Ok;
|
||||
using (var writer = new StreamWriter(path, true))
|
||||
{
|
||||
s_SessionId = (String.IsNullOrEmpty(s_SessionId)) ? System.Guid.NewGuid().ToString() : s_SessionId;
|
||||
////Debug.Log(s_Dictionary.ContainsKey("x"));
|
||||
string evt = WriteEvent("Heatmap." + eventName, s_Dictionary, "TestDevice-3", s_SessionId, Application.platform.ToString(), Debug.isDebugBuild);
|
||||
writer.WriteLine(evt);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result = analyticsEventNamespace.CustomEvent("Heatmap." + eventName, s_Dictionary);
|
||||
}
|
||||
s_Dictionary.Clear();
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convenience method for adding X/Y to dict
|
||||
/// </summary>
|
||||
protected static void AddXY(float x, float y)
|
||||
{
|
||||
////Debug.Log("x = " + x + " y = " + y);
|
||||
s_Dictionary["x"] = x;
|
||||
s_Dictionary["y"] = y;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convenience method for adding Z to dict
|
||||
/// </summary>
|
||||
protected static void AddZ(float z)
|
||||
{
|
||||
s_Dictionary["z"] = z;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convenience method for adding time to dict
|
||||
/// </summary>
|
||||
protected static void AddTime(float time)
|
||||
{
|
||||
s_Dictionary["t"] = time;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convenience method for adding rotation
|
||||
/// </summary>
|
||||
protected static void AddRotation(Vector3 r)
|
||||
{
|
||||
s_Dictionary["rx"] = r.x;
|
||||
s_Dictionary["ry"] = r.y;
|
||||
s_Dictionary["rz"] = r.z;
|
||||
}
|
||||
|
||||
protected static void AddDestination(Vector3 v)
|
||||
{
|
||||
s_Dictionary["dx"] = v.x;
|
||||
s_Dictionary["dy"] = v.y;
|
||||
s_Dictionary["dz"] = v.z;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convenience method for adding options to dict
|
||||
/// </summary>
|
||||
protected static void AddOptions(Dictionary<string, object> options)
|
||||
{
|
||||
if (options != null)
|
||||
{
|
||||
foreach (KeyValuePair<string, object> entry in options)
|
||||
{
|
||||
s_Dictionary[entry.Key] = entry.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string WriteEvent(string eventName, Dictionary<string, object> parameters, string deviceId, string sessionId, string platform, bool isDebug = false)
|
||||
{
|
||||
double currentMilliseconds = Math.Floor((DateTime.UtcNow - UnityAnalytics.DateTimeUtils.s_Epoch).TotalMilliseconds);
|
||||
|
||||
string evt = "";
|
||||
evt += currentMilliseconds + "\t";
|
||||
|
||||
// AppID
|
||||
#if UNITY_5
|
||||
evt += (string.IsNullOrEmpty(Application.cloudProjectId)) ? "1234-abcd-5678-efgh" : Application.cloudProjectId;
|
||||
#else
|
||||
evt += "1234-abcd-5678-efgh";
|
||||
#endif
|
||||
evt += "\t";
|
||||
|
||||
// Event Type
|
||||
evt += "custom\t";
|
||||
|
||||
// User ID, Session ID
|
||||
evt += deviceId + "\t";
|
||||
evt += sessionId + "\t";
|
||||
|
||||
// Remote IP
|
||||
evt += "1.1.1.1\t";
|
||||
|
||||
// Platform
|
||||
evt += platform + "\t";
|
||||
|
||||
// SDK Version
|
||||
evt += "5.6,3f1\t";
|
||||
|
||||
// IsDebug
|
||||
evt += isDebug + "\t";
|
||||
|
||||
// User agent
|
||||
evt += "Corridor%20Z/3 CFNetwork/758.2.8 Darwin/15.0.0\t";
|
||||
|
||||
// Submit time
|
||||
evt += currentMilliseconds + "\t";
|
||||
|
||||
// Event Name
|
||||
evt += eventName + "\t";
|
||||
|
||||
evt += WriteParams(eventName, parameters);
|
||||
|
||||
return evt;
|
||||
}
|
||||
|
||||
static string WriteParams(string eventName, Dictionary<string, object> parameters)
|
||||
{
|
||||
string json = "{";
|
||||
|
||||
foreach(KeyValuePair<string, object> kv in parameters)
|
||||
{
|
||||
json += Quotify(kv.Key) + ":" + Quotify(kv.Value.ToString());
|
||||
json += ",";
|
||||
}
|
||||
json += Quotify("unity.name") + ":" + Quotify(eventName) + "}";
|
||||
return json;
|
||||
}
|
||||
|
||||
static string Quotify(string value)
|
||||
{
|
||||
return "\"" + value + "\"";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0b2a6822dabcf433db9bbd852dfaee1f
|
||||
timeCreated: 1437429523
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,121 @@
|
|||
/// <summary>
|
||||
/// Send Heatmap event based on VideoPlayer.
|
||||
/// </summary>
|
||||
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Video;
|
||||
using UnityAnalytics360VideoHeatmap;
|
||||
|
||||
namespace UnityAnalytics360VideoHeatmap
|
||||
{
|
||||
public class HeatmapSender : MonoBehaviour
|
||||
{
|
||||
public VideoPlayer videoPlayer;
|
||||
|
||||
private int k_currentSendEventRatio;
|
||||
private bool k_eventSender;
|
||||
|
||||
private int k_eventLimit = 5000;
|
||||
private float k_eventInterval = 1.0f;
|
||||
private WaitForSeconds k_waitForSecond;
|
||||
private Dictionary<string, object> k_clipDict;
|
||||
|
||||
void Start()
|
||||
{
|
||||
if (videoPlayer == null)
|
||||
{
|
||||
videoPlayer = FindObjectOfType<VideoPlayer>();
|
||||
}
|
||||
|
||||
EnsureRatio();
|
||||
k_eventInterval = DetermineEventInterval(k_eventLimit);
|
||||
k_waitForSecond = new WaitForSeconds(k_eventInterval);
|
||||
|
||||
#if UNITY_EDITOR
|
||||
StartCoroutine(SendHeatmapEvent());
|
||||
#else
|
||||
if (k_eventSender)
|
||||
StartCoroutine(SendHeatmapEvent());
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Make sure the ratio is most updated.
|
||||
/// </summary>
|
||||
private void EnsureRatio()
|
||||
{
|
||||
k_eventSender = PlayerPrefs.GetInt("_360VideoHeatMap_EventSender", 0) == 0 ? true : false;
|
||||
k_currentSendEventRatio = PlayerPrefs.GetInt("_360VideoHeatMap_EventRatio", 10);
|
||||
|
||||
int m_newSendEventRatio = RemoteSettings.GetInt("heatmaps_sample_rate", 10);
|
||||
|
||||
// If the ratio has changed or the role has not been assigned before, reassign the user.
|
||||
if (!PlayerPrefs.HasKey("_360VideoHeatMap_EventSender") || k_currentSendEventRatio != m_newSendEventRatio)
|
||||
{
|
||||
k_currentSendEventRatio = m_newSendEventRatio;
|
||||
EnsureUserRole();
|
||||
PlayerPrefs.SetInt("_360VideoHeatMap_EventSender", k_eventSender == true ? 0 : 1);
|
||||
PlayerPrefs.SetInt("_360VideoHeatMap_EventRatio", k_currentSendEventRatio);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the user is allowed to send event based on the RemoteSetting key.
|
||||
/// </summary>
|
||||
private void EnsureUserRole()
|
||||
{
|
||||
if (k_currentSendEventRatio >= 100)
|
||||
{
|
||||
k_eventSender = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (k_currentSendEventRatio <= 0)
|
||||
{
|
||||
k_eventSender = false;
|
||||
return;
|
||||
}
|
||||
|
||||
int m_random = Random.Range(0, 100);
|
||||
if (m_random <= k_currentSendEventRatio)
|
||||
{
|
||||
k_eventSender = true;
|
||||
return;
|
||||
}
|
||||
|
||||
k_eventSender = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send the event only when VideoPlayer, clip exist and the video is playing.
|
||||
/// </summary>
|
||||
IEnumerator SendHeatmapEvent()
|
||||
{
|
||||
if (k_clipDict == null)
|
||||
k_clipDict = new Dictionary<string, object>();
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (videoPlayer != null && videoPlayer.clip != null && videoPlayer.isPlaying)
|
||||
{
|
||||
float m_standardTime = videoPlayer.frame / (float)videoPlayer.frameCount;
|
||||
k_clipDict["clipName"] = videoPlayer.clip.name;
|
||||
HeatmapEvent.Send("PlayerLook", this.transform, m_standardTime, k_clipDict);
|
||||
}
|
||||
|
||||
yield return k_waitForSecond;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine what's the time interval for event sending to not exceed the event limit.
|
||||
/// </summary>
|
||||
float DetermineEventInterval(int eventLimit)
|
||||
{
|
||||
float m_minimumInterval = 3600 / (float)eventLimit;
|
||||
return Mathf.Ceil(m_minimumInterval);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 334944594a826499d8df0f639515cca4
|
||||
timeCreated: 1511216740
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 84f7580997b7341a1b4b9b21eebd5a49
|
||||
folderAsset: yes
|
||||
timeCreated: 1512760710
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,218 @@
|
|||
Shader "Skybox/Panoramic-Heatmap" {
|
||||
Properties {
|
||||
_Tint ("Tint Color", Color) = (.5, .5, .5, .5)
|
||||
[Gamma] _Exposure ("Exposure", Range(0, 8)) = 1.0
|
||||
_Rotation ("Rotation", Range(0, 360)) = 0
|
||||
[NoScaleOffset] _MainTex ("Spherical (HDR)", 2D) = "grey" {}
|
||||
[NoScaleOffset] _HeatmapTex ("Spherical Heatmap (HDR)", 2D) = "grey" {}
|
||||
[NoScaleOffset] _HeatmapGradient ("Gradient Lookup", 2D) = "grey" {}
|
||||
[KeywordEnum(6 Frames Layout, Latitude Longitude Layout)] _Mapping("Mapping", Float) = 1
|
||||
[Enum(360 Degrees, 0, 180 Degrees, 1)] _ImageType("Image Type", Float) = 0
|
||||
[Toggle] _MirrorOnBack("Mirror on Back", Float) = 0
|
||||
[Enum(None, 0, Side by Side, 1, Over Under, 2)] _Layout("3D Layout", Float) = 0
|
||||
}
|
||||
|
||||
SubShader {
|
||||
Tags { "Queue"="Background" "RenderType"="Background" "PreviewType"="Skybox" }
|
||||
Cull Off ZWrite Off
|
||||
|
||||
Pass {
|
||||
|
||||
CGPROGRAM
|
||||
#pragma vertex vert
|
||||
#pragma fragment frag
|
||||
#pragma target 2.0
|
||||
#pragma multi_compile __ _MAPPING_6_FRAMES_LAYOUT
|
||||
|
||||
#include "UnityCG.cginc"
|
||||
|
||||
sampler2D _MainTex;
|
||||
sampler2D _HeatmapTex;
|
||||
sampler2D _HeatmapGradient;
|
||||
float4 _MainTex_TexelSize;
|
||||
half4 _MainTex_HDR;
|
||||
half4 _Tint;
|
||||
half _Exposure;
|
||||
float _Rotation;
|
||||
#ifndef _MAPPING_6_FRAMES_LAYOUT
|
||||
bool _MirrorOnBack;
|
||||
int _ImageType;
|
||||
int _Layout;
|
||||
#endif
|
||||
|
||||
#ifndef _MAPPING_6_FRAMES_LAYOUT
|
||||
inline float2 ToRadialCoords(float3 coords)
|
||||
{
|
||||
float3 normalizedCoords = normalize(coords);
|
||||
float latitude = acos(normalizedCoords.y);
|
||||
float longitude = atan2(normalizedCoords.z, normalizedCoords.x);
|
||||
float2 sphereCoords = float2(longitude, latitude) * float2(0.5/UNITY_PI, 1.0/UNITY_PI);
|
||||
return float2(0.5,1.0) - sphereCoords;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _MAPPING_6_FRAMES_LAYOUT
|
||||
inline float2 ToCubeCoords(float3 coords, float3 layout, float4 edgeSize, float4 faceXCoordLayouts, float4 faceYCoordLayouts, float4 faceZCoordLayouts)
|
||||
{
|
||||
// Determine the primary axis of the normal
|
||||
float3 absn = abs(coords);
|
||||
float3 absdir = absn > float3(max(absn.y,absn.z), max(absn.x,absn.z), max(absn.x,absn.y)) ? 1 : 0;
|
||||
// Convert the normal to a local face texture coord [-1,+1], note that tcAndLen.z==dot(coords,absdir)
|
||||
// and thus its sign tells us whether the normal is pointing positive or negative
|
||||
float3 tcAndLen = mul(absdir, float3x3(coords.zyx, coords.xzy, float3(-coords.xy,coords.z)));
|
||||
tcAndLen.xy /= tcAndLen.z;
|
||||
// Flip-flop faces for proper orientation and normalize to [-0.5,+0.5]
|
||||
bool2 positiveAndVCross = float2(tcAndLen.z, layout.x) > 0;
|
||||
tcAndLen.xy *= (positiveAndVCross[0] ? absdir.yx : (positiveAndVCross[1] ? float2(absdir[2],0) : float2(0,absdir[2]))) - 0.5;
|
||||
// Clamp values which are close to the face edges to avoid bleeding/seams (ie. enforce clamp texture wrap mode)
|
||||
tcAndLen.xy = clamp(tcAndLen.xy, edgeSize.xy, edgeSize.zw);
|
||||
// Scale and offset texture coord to match the proper square in the texture based on layout.
|
||||
float4 coordLayout = mul(float4(absdir,0), float4x4(faceXCoordLayouts, faceYCoordLayouts, faceZCoordLayouts, faceZCoordLayouts));
|
||||
tcAndLen.xy = (tcAndLen.xy + (positiveAndVCross[0] ? coordLayout.xy : coordLayout.zw)) * layout.yz;
|
||||
return tcAndLen.xy;
|
||||
}
|
||||
#endif
|
||||
|
||||
float3 RotateAroundYInDegrees (float3 vertex, float degrees)
|
||||
{
|
||||
float alpha = degrees * UNITY_PI / 180.0;
|
||||
float sina, cosa;
|
||||
sincos(alpha, sina, cosa);
|
||||
float2x2 m = float2x2(cosa, -sina, sina, cosa);
|
||||
return float3(mul(m, vertex.xz), vertex.y).xzy;
|
||||
}
|
||||
|
||||
struct appdata_t {
|
||||
float4 vertex : POSITION;
|
||||
UNITY_VERTEX_INPUT_INSTANCE_ID
|
||||
};
|
||||
|
||||
struct v2f {
|
||||
float4 vertex : SV_POSITION;
|
||||
float3 texcoord : TEXCOORD0;
|
||||
#ifdef _MAPPING_6_FRAMES_LAYOUT
|
||||
float3 layout : TEXCOORD1;
|
||||
float4 edgeSize : TEXCOORD2;
|
||||
float4 faceXCoordLayouts : TEXCOORD3;
|
||||
float4 faceYCoordLayouts : TEXCOORD4;
|
||||
float4 faceZCoordLayouts : TEXCOORD5;
|
||||
#else
|
||||
float2 image180ScaleAndCutoff : TEXCOORD1;
|
||||
float4 layout3DScaleAndOffset : TEXCOORD2;
|
||||
#endif
|
||||
UNITY_VERTEX_OUTPUT_STEREO
|
||||
};
|
||||
|
||||
v2f vert (appdata_t v)
|
||||
{
|
||||
v2f o;
|
||||
UNITY_SETUP_INSTANCE_ID(v);
|
||||
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
|
||||
float3 rotated = RotateAroundYInDegrees(v.vertex, _Rotation);
|
||||
o.vertex = UnityObjectToClipPos(rotated);
|
||||
o.texcoord = v.vertex.xyz;
|
||||
#ifdef _MAPPING_6_FRAMES_LAYOUT
|
||||
// layout and edgeSize are solely based on texture dimensions and can thus be precalculated in the vertex shader.
|
||||
float sourceAspect = float(_MainTex_TexelSize.z) / float(_MainTex_TexelSize.w);
|
||||
// Use the halfway point between the 1:6 and 3:4 aspect ratios of the strip and cross layouts to
|
||||
// guess at the correct format.
|
||||
bool3 aspectTest =
|
||||
sourceAspect >
|
||||
float3(1.0, 1.0f / 6.0f + (3.0f / 4.0f - 1.0f / 6.0f) / 2.0f, 6.0f / 1.0f + (4.0f / 3.0f - 6.0f / 1.0f) / 2.0f);
|
||||
// For a given face layout, the coordinates of the 6 cube faces are fixed: build a compact representation of the
|
||||
// coordinates of the center of each face where the first float4 represents the coordinates of the X axis faces,
|
||||
// the second the Y, and the third the Z. The first two float componenents (xy) of each float4 represent the face
|
||||
// coordinates on the positive axis side of the cube, and the second (zw) the negative.
|
||||
// layout.x is a boolean flagging the vertical cross layout (for special handling of flip-flops later)
|
||||
// layout.yz contains the inverse of the layout dimensions (ie. the scale factor required to convert from
|
||||
// normalized face coords to full texture coordinates)
|
||||
if (aspectTest[0]) // horizontal
|
||||
{
|
||||
if (aspectTest[2])
|
||||
{ // horizontal strip
|
||||
o.faceXCoordLayouts = float4(0.5,0.5,1.5,0.5);
|
||||
o.faceYCoordLayouts = float4(2.5,0.5,3.5,0.5);
|
||||
o.faceZCoordLayouts = float4(4.5,0.5,5.5,0.5);
|
||||
o.layout = float3(-1,1.0/6.0,1.0/1.0);
|
||||
}
|
||||
else
|
||||
{ // horizontal cross
|
||||
o.faceXCoordLayouts = float4(2.5,1.5,0.5,1.5);
|
||||
o.faceYCoordLayouts = float4(1.5,2.5,1.5,0.5);
|
||||
o.faceZCoordLayouts = float4(1.5,1.5,3.5,1.5);
|
||||
o.layout = float3(-1,1.0/4.0,1.0/3.0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (aspectTest[1])
|
||||
{ // vertical cross
|
||||
o.faceXCoordLayouts = float4(2.5,2.5,0.5,2.5);
|
||||
o.faceYCoordLayouts = float4(1.5,3.5,1.5,1.5);
|
||||
o.faceZCoordLayouts = float4(1.5,2.5,1.5,0.5);
|
||||
o.layout = float3(1,1.0/3.0,1.0/4.0);
|
||||
}
|
||||
else
|
||||
{ // vertical strip
|
||||
o.faceXCoordLayouts = float4(0.5,5.5,0.5,4.5);
|
||||
o.faceYCoordLayouts = float4(0.5,3.5,0.5,2.5);
|
||||
o.faceZCoordLayouts = float4(0.5,1.5,0.5,0.5);
|
||||
o.layout = float3(-1,1.0/1.0,1.0/6.0);
|
||||
}
|
||||
}
|
||||
// edgeSize specifies the minimum (xy) and maximum (zw) normalized face texture coordinates that will be used for
|
||||
// sampling in the texture. Setting these to the effective size of a half pixel horizontally and vertically
|
||||
// effectively enforces clamp mode texture wrapping for each individual face.
|
||||
o.edgeSize.xy = _MainTex_TexelSize.xy * 0.5 / o.layout.yz - 0.5;
|
||||
o.edgeSize.zw = -o.edgeSize.xy;
|
||||
#else // !_MAPPING_6_FRAMES_LAYOUT
|
||||
// Calculate constant horizontal scale and cutoff for 180 (vs 360) image type
|
||||
if (_ImageType == 0) // 360 degree
|
||||
o.image180ScaleAndCutoff = float2(1.0, 1.0);
|
||||
else // 180 degree
|
||||
o.image180ScaleAndCutoff = float2(2.0, _MirrorOnBack ? 1.0 : 0.5);
|
||||
// Calculate constant scale and offset for 3D layouts
|
||||
if (_Layout == 0) // No 3D layout
|
||||
o.layout3DScaleAndOffset = float4(0,0,1,1);
|
||||
else if (_Layout == 1) // Side-by-Side 3D layout
|
||||
o.layout3DScaleAndOffset = float4(unity_StereoEyeIndex,0,0.5,1);
|
||||
else // Over-Under 3D layout
|
||||
o.layout3DScaleAndOffset = float4(0, 1-unity_StereoEyeIndex,1,0.5);
|
||||
#endif
|
||||
return o;
|
||||
}
|
||||
|
||||
fixed4 frag (v2f i) : SV_Target
|
||||
{
|
||||
#ifdef _MAPPING_6_FRAMES_LAYOUT
|
||||
float2 tc = ToCubeCoords(i.texcoord, i.layout, i.edgeSize, i.faceXCoordLayouts, i.faceYCoordLayouts, i.faceZCoordLayouts);
|
||||
#else
|
||||
float2 tc = ToRadialCoords(i.texcoord);
|
||||
if (tc.x > i.image180ScaleAndCutoff[1])
|
||||
return half4(0,0,0,1);
|
||||
tc.x = fmod(tc.x*i.image180ScaleAndCutoff[0], 1);
|
||||
tc = (tc + i.layout3DScaleAndOffset.xy) * i.layout3DScaleAndOffset.zw;
|
||||
#endif
|
||||
|
||||
half4 tex = tex2D (_MainTex, tc);
|
||||
|
||||
// apply heat
|
||||
float heat = tex2D (_HeatmapTex, tc);
|
||||
float4 grad = tex2D (_HeatmapGradient, float2(heat, heat));
|
||||
tex.rgb = (1 - grad.w) * tex.rgb + grad.w * tex.rgb * grad.xyz;
|
||||
|
||||
half3 c = DecodeHDR (tex, _MainTex_HDR);
|
||||
c = c * _Tint.rgb * unity_ColorSpaceDouble.rgb;
|
||||
c *= _Exposure;
|
||||
|
||||
return half4(c, 1);
|
||||
}
|
||||
ENDCG
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CustomEditor "SkyboxPanoramicShaderGUI"
|
||||
Fallback Off
|
||||
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c6bc35204d28841369e212c37e8b22c5
|
||||
timeCreated: 1505407735
|
||||
licenseType: Pro
|
||||
ShaderImporter:
|
||||
externalObjects: {}
|
||||
defaultTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Default</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ItemType>GenericProject</ItemType>
|
||||
<ProjectGuid>{CB6F8974-2395-4B9E-B8AE-0705AC6509F2}</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Default|AnyCPU' ">
|
||||
<OutputPath>.\</OutputPath>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Editor\" />
|
||||
<Folder Include="Examples\" />
|
||||
<Folder Include="Renderer\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Editor\HeatMapDataParser.cs" />
|
||||
<None Include="Editor\UnityAnalyticsIntegration.cs" />
|
||||
<None Include="Examples\BotDeathTracker.cs" />
|
||||
<None Include="Examples\HeatmapToggler.cs" />
|
||||
<None Include="Examples\IAnalyticsDispatcher.cs" />
|
||||
<None Include="Examples\LoginSubmissionForm.cs" />
|
||||
<None Include="Examples\PositionTracker.cs" />
|
||||
<None Include="Examples\UAUniqueUsername.cs" />
|
||||
<None Include="Renderer\HeatMapRenderer.cs" />
|
||||
<None Include="Renderer\HeatPoint.cs" />
|
||||
<None Include="Renderer\IHeatmapRenderer.cs" />
|
||||
<None Include="HeatMapEvent.cs" />
|
||||
<None Include="Editor\HeatMapController.cs" />
|
||||
<None Include="Editor\HeatMapInspector.cs" />
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3ca3c691e42eb48f0baff5a632e91350
|
||||
timeCreated: 1437429523
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c823b6cdb9bf14ed8a0ad66690227c68
|
||||
folderAsset: yes
|
||||
timeCreated: 1512760561
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0930d3a2e921d40bbb5f4bb4377c2b3f
|
||||
folderAsset: yes
|
||||
timeCreated: 1444707935
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,15 @@
|
|||
using System;
|
||||
|
||||
namespace UnityAnalytics360VideoHeatmap
|
||||
{
|
||||
// Note variance from C# code standard. We need these to match consts on server.
|
||||
public enum UnityAnalyticsEventType
|
||||
{
|
||||
appStart,
|
||||
appRunning,
|
||||
custom,
|
||||
transaction,
|
||||
userInfo,
|
||||
deviceInfo,
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 440389feffcb2451697647ef5086b4cf
|
||||
timeCreated: 1438818367
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1080133c164f04a9e8c95a4f35f374dd
|
||||
folderAsset: yes
|
||||
timeCreated: 1470595871
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,259 @@
|
|||
/// <summary>
|
||||
/// Manages the loading and processing of Heatmap data
|
||||
/// </summary>
|
||||
///
|
||||
/// Heatmap data is loaded from GZip or text files and stored in the
|
||||
/// HeatmapViewModel as a CustomRawData[]. From there, it is aggregated
|
||||
/// into a HeatPoint[] before being sent to the renderer.
|
||||
///
|
||||
/// This class manages all that loading and processing, working out the
|
||||
/// minimum work required to dynamically update the map.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityAnalytics;
|
||||
using UnityEditor;
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
|
||||
namespace UnityAnalytics360VideoHeatmap
|
||||
{
|
||||
public class HeatmapDataProcessor
|
||||
{
|
||||
const string k_DataPathKey = "UnityAnalyticsHeatmapDataPathKey";
|
||||
const string k_SpaceKey = "UnityAnalyticsHeatmapAggregationSpace";
|
||||
const string k_KeyToTime = "UnityAnalyticsHeatmapAggregationTime";
|
||||
const string k_RotationKey = "UnityAnalyticsHeatmapAggregationRotation";
|
||||
const string k_SmoothSpaceKey = "UnityAnalyticsHeatmapAggregationAggregateSpace";
|
||||
const string k_SmoothTimeKey = "UnityAnalyticsHeatmapAggregationAggregateTime";
|
||||
const string k_SmoothRotationKey = "UnityAnalyticsHeatmapAggregationAggregateRotation";
|
||||
const string k_StartTimeKey = "UnityAnalyticsHeatmapAggregateStartTime";
|
||||
const string k_EndTimeKey = "UnityAnalyticsHeatmapAggregateEndTime";
|
||||
|
||||
|
||||
const string k_SeparateSessionKey = "UnityAnalyticsHeatmapAggregationAggregateSessionIDs";
|
||||
const string k_SeparateDebugKey = "UnityAnalyticsHeatmapAggregationAggregateDebug";
|
||||
const string k_SeparatePlatformKey = "UnityAnalyticsHeatmapAggregationAggregatePlatform";
|
||||
const string k_SeparateCustomKey = "UnityAnalyticsHeatmapAggregationAggregateCustom";
|
||||
|
||||
const string k_ArbitraryFieldsKey = "UnityAnalyticsHeatmapAggregationArbitraryFields";
|
||||
|
||||
const float k_DefaultSpace = 10f;
|
||||
const float k_DefaultTime = 10f;
|
||||
const float k_DefaultRotation = 15f;
|
||||
|
||||
|
||||
public const int SMOOTH_VALUE = 0;
|
||||
public const int SMOOTH_NONE = 1;
|
||||
public const int SMOOTH_UNION = 2;
|
||||
|
||||
public HeatmapViewModel m_ViewModel;
|
||||
public HeatmapAggregator m_Aggregator;
|
||||
|
||||
bool m_DateChangeHasOccurred = true;
|
||||
|
||||
private string _rawDataPath = "";
|
||||
public string m_RawDataPath
|
||||
{
|
||||
get{
|
||||
return _rawDataPath;
|
||||
}
|
||||
set{
|
||||
_rawDataPath = value;
|
||||
m_Aggregator.SetDataPath(_rawDataPath);
|
||||
EditorPrefs.SetString(k_DataPathKey, value);
|
||||
}
|
||||
}
|
||||
[SerializeField]
|
||||
string _startDate = "";
|
||||
public string m_StartDate
|
||||
{
|
||||
get {
|
||||
return _startDate;
|
||||
}
|
||||
set {
|
||||
string oldDate = _startDate;
|
||||
_startDate = value;
|
||||
if (_startDate != oldDate)
|
||||
{
|
||||
EditorPrefs.SetString(Application.cloudProjectId + k_StartTimeKey, _startDate);
|
||||
m_DateChangeHasOccurred = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
[SerializeField]
|
||||
string _endDate = "";
|
||||
public string m_EndDate
|
||||
{
|
||||
get {
|
||||
return _endDate;
|
||||
}
|
||||
set {
|
||||
string oldDate = _endDate;
|
||||
_endDate = value;
|
||||
if (_endDate != oldDate)
|
||||
{
|
||||
EditorPrefs.SetString(Application.cloudProjectId + k_EndTimeKey, _endDate);
|
||||
m_DateChangeHasOccurred = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool _separateSessions = false;
|
||||
public bool m_SeparateSessions{
|
||||
get{
|
||||
return _separateSessions;
|
||||
}
|
||||
set{
|
||||
_separateSessions = value;
|
||||
EditorPrefs.SetBool(k_SeparateSessionKey, _separateSessions);
|
||||
}
|
||||
}
|
||||
bool _separatePlatform;
|
||||
public bool m_SeparatePlatform
|
||||
{
|
||||
get {
|
||||
return _separatePlatform;
|
||||
}
|
||||
set {
|
||||
_separatePlatform = value;
|
||||
EditorPrefs.SetBool(k_SeparateSessionKey, _separatePlatform);
|
||||
}
|
||||
}
|
||||
bool _separateDebug;
|
||||
public bool m_SeparateDebug
|
||||
{
|
||||
get {
|
||||
return _separateDebug;
|
||||
}
|
||||
set {
|
||||
_separateDebug = value;
|
||||
EditorPrefs.SetBool(k_SeparateDebugKey, _separateDebug);
|
||||
}
|
||||
}
|
||||
bool _separateCustomField;
|
||||
public bool m_SeparateCustomField
|
||||
{
|
||||
get {
|
||||
return _separateCustomField;
|
||||
}
|
||||
set {
|
||||
_separateCustomField = value;
|
||||
EditorPrefs.SetBool(k_SeparateCustomKey, _separateCustomField);
|
||||
}
|
||||
}
|
||||
|
||||
List<string> _separationFields = new List<string>();
|
||||
public List<string> m_SeparationFields
|
||||
{
|
||||
get {
|
||||
return _separationFields;
|
||||
}
|
||||
set {
|
||||
_separationFields = value;
|
||||
string currentArbitraryFieldsString = string.Join("|", _separationFields.ToArray());
|
||||
EditorPrefs.SetString(k_ArbitraryFieldsKey, currentArbitraryFieldsString);
|
||||
}
|
||||
}
|
||||
|
||||
public delegate void AggregationHandler(string jsonPath);
|
||||
public delegate void PointHandler(HeatPoint[] heatData);
|
||||
|
||||
|
||||
static public AggregationMethod[] m_RemapOptionIds = new AggregationMethod[]{
|
||||
AggregationMethod.Increment,
|
||||
AggregationMethod.Cumulative,
|
||||
AggregationMethod.Average,
|
||||
AggregationMethod.Min,
|
||||
AggregationMethod.Max,
|
||||
AggregationMethod.First,
|
||||
AggregationMethod.Last,
|
||||
AggregationMethod.Percentile
|
||||
};
|
||||
|
||||
public HeatmapDataProcessor()
|
||||
{
|
||||
m_Aggregator = new HeatmapAggregator(m_RawDataPath);
|
||||
HeatmapViewModel.StartEndDateUpdated += HeatmapViewModel_StartEndDateUpdated;
|
||||
}
|
||||
|
||||
void HeatmapViewModel_StartEndDateUpdated(string startDate, string endDate)
|
||||
{
|
||||
m_StartDate = startDate;
|
||||
m_EndDate = endDate;
|
||||
RawDataClient.GetInstance().m_DataPath = m_RawDataPath;
|
||||
ProcessAggregation();
|
||||
}
|
||||
|
||||
public void RestoreSettings()
|
||||
{
|
||||
// Restore cached paths
|
||||
m_RawDataPath = EditorPrefs.GetString(k_DataPathKey);
|
||||
|
||||
// Set dates based on today (should this be cached?)
|
||||
// Yes, yes it should.
|
||||
m_EndDate = EditorPrefs.HasKey(Application.cloudProjectId+k_EndTimeKey) ? EditorPrefs.GetString(Application.cloudProjectId+k_EndTimeKey) : String.Format("{0:yyyy-MM-dd}", DateTime.UtcNow);
|
||||
m_StartDate = EditorPrefs.HasKey(Application.cloudProjectId + k_StartTimeKey) ? EditorPrefs.GetString(Application.cloudProjectId + k_StartTimeKey) : String.Format("{0:yyyy-MM-dd}", DateTime.UtcNow.Subtract(new TimeSpan(5, 0, 0, 0)));
|
||||
|
||||
// Restore list of arbitrary separation fields
|
||||
string loadedArbitraryFields = EditorPrefs.GetString(k_ArbitraryFieldsKey);
|
||||
string[] arbitraryFieldsList;
|
||||
if (string.IsNullOrEmpty(loadedArbitraryFields))
|
||||
{
|
||||
arbitraryFieldsList = new string[]{ };
|
||||
}
|
||||
else
|
||||
{
|
||||
arbitraryFieldsList = loadedArbitraryFields.Split('|');
|
||||
}
|
||||
m_SeparationFields = new List<string>(arbitraryFieldsList);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fetch the files within the currently specified date range.
|
||||
/// </summary>
|
||||
public void Fetch()
|
||||
{
|
||||
RawDataClient.GetInstance().m_DataPath = m_RawDataPath;
|
||||
ProcessAggregation();
|
||||
}
|
||||
|
||||
void ProcessAggregation()
|
||||
{
|
||||
//TODO: Where settings for aggregation go
|
||||
DateTime start, end;
|
||||
try
|
||||
{
|
||||
start = DateTime.Parse(m_StartDate).ToUniversalTime();
|
||||
}
|
||||
catch
|
||||
{
|
||||
start = DateTime.Parse("2000-01-01").ToUniversalTime();
|
||||
}
|
||||
try
|
||||
{
|
||||
end = DateTime.Parse(m_EndDate).ToUniversalTime().Add(new TimeSpan(24,0,0));
|
||||
}
|
||||
catch
|
||||
{
|
||||
end = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
if (m_DateChangeHasOccurred || RawDataClient.GetInstance().m_ManifestInvalidated ||
|
||||
HeatmapViewModel.m_RawDataFileList == null || HeatmapViewModel.m_RawDataFileList.Count == 0)
|
||||
{
|
||||
RawDataClient.GetInstance().m_DataPath = m_RawDataPath;
|
||||
HeatmapViewModel.m_RawDataFileList = RawDataClient.GetInstance().GetFiles(
|
||||
new UnityAnalyticsEventType[]{ UnityAnalyticsEventType.custom }, start, end);
|
||||
m_DateChangeHasOccurred = false;
|
||||
if (HeatmapViewModel.m_RawDataFileList.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
m_Aggregator.Process(HeatmapViewModel.m_RawDataFileList, start, end);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7534739c6188a4755a42197820728221
|
||||
timeCreated: 1470595871
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: dfdf5ae6e9b3a41938676ed035d2e7e3
|
||||
folderAsset: yes
|
||||
timeCreated: 1438385450
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Двоичные данные
Assets/AssetStorePackage/Plugins/Heatmaps/Internal/Lib/Ionic.Zlib.dll
Executable file
|
@ -0,0 +1,32 @@
|
|||
fileFormatVersion: 2
|
||||
guid: abd1f95c0baf24d4ba1711633693c8b0
|
||||
timeCreated: 1463523671
|
||||
licenseType: Pro
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
Windows Store Apps: WindowsStoreApps
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,548 @@
|
|||
/*
|
||||
* Copyright (c) 2013 Calvin Rien
|
||||
*
|
||||
* Based on the JSON parser by Patrick van Bergen
|
||||
* http://techblog.procurios.nl/k/618/news/view/14605/14863/How-do-I-write-my-own-parser-for-JSON.html
|
||||
*
|
||||
* Simplified it so that it doesn't throw exceptions
|
||||
* and can be used in Unity iPhone with maximum code stripping.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace MiniJSON {
|
||||
// Example usage:
|
||||
//
|
||||
// using UnityEngine;
|
||||
// using System.Collections;
|
||||
// using System.Collections.Generic;
|
||||
// using MiniJSON;
|
||||
//
|
||||
// public class MiniJSONTest : MonoBehaviour {
|
||||
// void Start () {
|
||||
// var jsonString = "{ \"array\": [1.44,2,3], " +
|
||||
// "\"object\": {\"key1\":\"value1\", \"key2\":256}, " +
|
||||
// "\"string\": \"The quick brown fox \\\"jumps\\\" over the lazy dog \", " +
|
||||
// "\"unicode\": \"\\u3041 Men\u00fa sesi\u00f3n\", " +
|
||||
// "\"int\": 65536, " +
|
||||
// "\"float\": 3.1415926, " +
|
||||
// "\"bool\": true, " +
|
||||
// "\"null\": null }";
|
||||
//
|
||||
// var dict = Json.Deserialize(jsonString) as Dictionary<string,object>;
|
||||
//
|
||||
// //Debug.Log("deserialized: " + dict.GetType());
|
||||
// //Debug.Log("dict['array'][0]: " + ((List<object>) dict["array"])[0]);
|
||||
// //Debug.Log("dict['string']: " + (string) dict["string"]);
|
||||
// //Debug.Log("dict['float']: " + (double) dict["float"]); // floats come out as doubles
|
||||
// //Debug.Log("dict['int']: " + (long) dict["int"]); // ints come out as longs
|
||||
// //Debug.Log("dict['unicode']: " + (string) dict["unicode"]);
|
||||
//
|
||||
// var str = Json.Serialize(dict);
|
||||
//
|
||||
// //Debug.Log("serialized: " + str);
|
||||
// }
|
||||
// }
|
||||
|
||||
/// <summary>
|
||||
/// This class encodes and decodes JSON strings.
|
||||
/// Spec. details, see http://www.json.org/
|
||||
///
|
||||
/// JSON uses Arrays and Objects. These correspond here to the datatypes IList and IDictionary.
|
||||
/// All numbers are parsed to doubles.
|
||||
/// </summary>
|
||||
public static class Json {
|
||||
/// <summary>
|
||||
/// Parses the string json into a value
|
||||
/// </summary>
|
||||
/// <param name="json">A JSON string.</param>
|
||||
/// <returns>An List<object>, a Dictionary<string, object>, a double, an integer,a string, null, true, or false</returns>
|
||||
public static object Deserialize(string json) {
|
||||
// save the string for debug information
|
||||
if (json == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Parser.Parse(json);
|
||||
}
|
||||
|
||||
sealed class Parser : IDisposable {
|
||||
const string WORD_BREAK = "{}[],:\"";
|
||||
|
||||
public static bool IsWordBreak(char c) {
|
||||
return Char.IsWhiteSpace(c) || WORD_BREAK.IndexOf(c) != -1;
|
||||
}
|
||||
|
||||
enum TOKEN {
|
||||
NONE,
|
||||
CURLY_OPEN,
|
||||
CURLY_CLOSE,
|
||||
SQUARED_OPEN,
|
||||
SQUARED_CLOSE,
|
||||
COLON,
|
||||
COMMA,
|
||||
STRING,
|
||||
NUMBER,
|
||||
TRUE,
|
||||
FALSE,
|
||||
NULL
|
||||
};
|
||||
|
||||
StringReader json;
|
||||
|
||||
Parser(string jsonString) {
|
||||
json = new StringReader(jsonString);
|
||||
}
|
||||
|
||||
public static object Parse(string jsonString) {
|
||||
using (var instance = new Parser(jsonString)) {
|
||||
return instance.ParseValue();
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
json.Dispose();
|
||||
json = null;
|
||||
}
|
||||
|
||||
Dictionary<string, object> ParseObject() {
|
||||
Dictionary<string, object> table = new Dictionary<string, object>();
|
||||
|
||||
// ditch opening brace
|
||||
json.Read();
|
||||
|
||||
// {
|
||||
while (true) {
|
||||
switch (NextToken) {
|
||||
case TOKEN.NONE:
|
||||
return null;
|
||||
case TOKEN.COMMA:
|
||||
continue;
|
||||
case TOKEN.CURLY_CLOSE:
|
||||
return table;
|
||||
default:
|
||||
// name
|
||||
string name = ParseString();
|
||||
if (name == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// :
|
||||
if (NextToken != TOKEN.COLON) {
|
||||
return null;
|
||||
}
|
||||
// ditch the colon
|
||||
json.Read();
|
||||
|
||||
// value
|
||||
table[name] = ParseValue();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<object> ParseArray() {
|
||||
List<object> array = new List<object>();
|
||||
|
||||
// ditch opening bracket
|
||||
json.Read();
|
||||
|
||||
// [
|
||||
var parsing = true;
|
||||
while (parsing) {
|
||||
TOKEN nextToken = NextToken;
|
||||
|
||||
switch (nextToken) {
|
||||
case TOKEN.NONE:
|
||||
return null;
|
||||
case TOKEN.COMMA:
|
||||
continue;
|
||||
case TOKEN.SQUARED_CLOSE:
|
||||
parsing = false;
|
||||
break;
|
||||
default:
|
||||
object value = ParseByToken(nextToken);
|
||||
|
||||
array.Add(value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
object ParseValue() {
|
||||
TOKEN nextToken = NextToken;
|
||||
return ParseByToken(nextToken);
|
||||
}
|
||||
|
||||
object ParseByToken(TOKEN token) {
|
||||
|
||||
switch (token) {
|
||||
case TOKEN.STRING:
|
||||
return ParseString();
|
||||
case TOKEN.NUMBER:
|
||||
return ParseNumber();
|
||||
case TOKEN.CURLY_OPEN:
|
||||
return ParseObject();
|
||||
case TOKEN.SQUARED_OPEN:
|
||||
return ParseArray();
|
||||
case TOKEN.TRUE:
|
||||
return true;
|
||||
case TOKEN.FALSE:
|
||||
return false;
|
||||
case TOKEN.NULL:
|
||||
return null;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
string ParseString() {
|
||||
StringBuilder s = new StringBuilder();
|
||||
char c;
|
||||
|
||||
// ditch opening quote
|
||||
json.Read();
|
||||
|
||||
bool parsing = true;
|
||||
while (parsing) {
|
||||
|
||||
if (json.Peek() == -1) {
|
||||
parsing = false;
|
||||
break;
|
||||
}
|
||||
|
||||
c = NextChar;
|
||||
switch (c) {
|
||||
case '"':
|
||||
parsing = false;
|
||||
break;
|
||||
case '\\':
|
||||
if (json.Peek() == -1) {
|
||||
parsing = false;
|
||||
break;
|
||||
}
|
||||
|
||||
c = NextChar;
|
||||
switch (c) {
|
||||
case '"':
|
||||
case '\\':
|
||||
case '/':
|
||||
s.Append(c);
|
||||
break;
|
||||
case 'b':
|
||||
s.Append('\b');
|
||||
break;
|
||||
case 'f':
|
||||
s.Append('\f');
|
||||
break;
|
||||
case 'n':
|
||||
s.Append('\n');
|
||||
break;
|
||||
case 'r':
|
||||
s.Append('\r');
|
||||
break;
|
||||
case 't':
|
||||
s.Append('\t');
|
||||
break;
|
||||
case 'u':
|
||||
var hex = new char[4];
|
||||
|
||||
for (int i=0; i< 4; i++) {
|
||||
hex[i] = NextChar;
|
||||
}
|
||||
|
||||
s.Append((char) Convert.ToInt32(new string(hex), 16));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
s.Append(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return s.ToString();
|
||||
}
|
||||
|
||||
object ParseNumber() {
|
||||
string number = NextWord;
|
||||
|
||||
if (number.IndexOf('.') == -1) {
|
||||
long parsedInt;
|
||||
Int64.TryParse(number, out parsedInt);
|
||||
return parsedInt;
|
||||
}
|
||||
|
||||
double parsedDouble;
|
||||
Double.TryParse(number, out parsedDouble);
|
||||
return parsedDouble;
|
||||
}
|
||||
|
||||
void EatWhitespace() {
|
||||
while (Char.IsWhiteSpace(PeekChar)) {
|
||||
json.Read();
|
||||
|
||||
if (json.Peek() == -1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char PeekChar {
|
||||
get {
|
||||
return Convert.ToChar(json.Peek());
|
||||
}
|
||||
}
|
||||
|
||||
char NextChar {
|
||||
get {
|
||||
return Convert.ToChar(json.Read());
|
||||
}
|
||||
}
|
||||
|
||||
string NextWord {
|
||||
get {
|
||||
StringBuilder word = new StringBuilder();
|
||||
|
||||
while (!IsWordBreak(PeekChar)) {
|
||||
word.Append(NextChar);
|
||||
|
||||
if (json.Peek() == -1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return word.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
TOKEN NextToken {
|
||||
get {
|
||||
EatWhitespace();
|
||||
|
||||
if (json.Peek() == -1) {
|
||||
return TOKEN.NONE;
|
||||
}
|
||||
|
||||
switch (PeekChar) {
|
||||
case '{':
|
||||
return TOKEN.CURLY_OPEN;
|
||||
case '}':
|
||||
json.Read();
|
||||
return TOKEN.CURLY_CLOSE;
|
||||
case '[':
|
||||
return TOKEN.SQUARED_OPEN;
|
||||
case ']':
|
||||
json.Read();
|
||||
return TOKEN.SQUARED_CLOSE;
|
||||
case ',':
|
||||
json.Read();
|
||||
return TOKEN.COMMA;
|
||||
case '"':
|
||||
return TOKEN.STRING;
|
||||
case ':':
|
||||
return TOKEN.COLON;
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
case '-':
|
||||
return TOKEN.NUMBER;
|
||||
}
|
||||
|
||||
switch (NextWord) {
|
||||
case "false":
|
||||
return TOKEN.FALSE;
|
||||
case "true":
|
||||
return TOKEN.TRUE;
|
||||
case "null":
|
||||
return TOKEN.NULL;
|
||||
}
|
||||
|
||||
return TOKEN.NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a IDictionary / IList object or a simple type (string, int, etc.) into a JSON string
|
||||
/// </summary>
|
||||
/// <param name="json">A Dictionary<string, object> / List<object></param>
|
||||
/// <returns>A JSON encoded string, or null if object 'json' is not serializable</returns>
|
||||
public static string Serialize(object obj) {
|
||||
return Serializer.Serialize(obj);
|
||||
}
|
||||
|
||||
sealed class Serializer {
|
||||
StringBuilder builder;
|
||||
|
||||
Serializer() {
|
||||
builder = new StringBuilder();
|
||||
}
|
||||
|
||||
public static string Serialize(object obj) {
|
||||
var instance = new Serializer();
|
||||
|
||||
instance.SerializeValue(obj);
|
||||
|
||||
return instance.builder.ToString();
|
||||
}
|
||||
|
||||
void SerializeValue(object value) {
|
||||
IList asList;
|
||||
IDictionary asDict;
|
||||
string asStr;
|
||||
|
||||
if (value == null) {
|
||||
builder.Append("null");
|
||||
} else if ((asStr = value as string) != null) {
|
||||
SerializeString(asStr);
|
||||
} else if (value is bool) {
|
||||
builder.Append((bool) value ? "true" : "false");
|
||||
} else if ((asList = value as IList) != null) {
|
||||
SerializeArray(asList);
|
||||
} else if ((asDict = value as IDictionary) != null) {
|
||||
SerializeObject(asDict);
|
||||
} else if (value is char) {
|
||||
SerializeString(new string((char) value, 1));
|
||||
} else {
|
||||
SerializeOther(value);
|
||||
}
|
||||
}
|
||||
|
||||
void SerializeObject(IDictionary obj) {
|
||||
bool first = true;
|
||||
|
||||
builder.Append('{');
|
||||
|
||||
foreach (object e in obj.Keys) {
|
||||
if (!first) {
|
||||
builder.Append(',');
|
||||
}
|
||||
|
||||
SerializeString(e.ToString());
|
||||
builder.Append(':');
|
||||
|
||||
SerializeValue(obj[e]);
|
||||
|
||||
first = false;
|
||||
}
|
||||
|
||||
builder.Append('}');
|
||||
}
|
||||
|
||||
void SerializeArray(IList anArray) {
|
||||
builder.Append('[');
|
||||
|
||||
bool first = true;
|
||||
|
||||
foreach (object obj in anArray) {
|
||||
if (!first) {
|
||||
builder.Append(',');
|
||||
}
|
||||
|
||||
SerializeValue(obj);
|
||||
|
||||
first = false;
|
||||
}
|
||||
|
||||
builder.Append(']');
|
||||
}
|
||||
|
||||
void SerializeString(string str) {
|
||||
builder.Append('\"');
|
||||
|
||||
char[] charArray = str.ToCharArray();
|
||||
foreach (var c in charArray) {
|
||||
switch (c) {
|
||||
case '"':
|
||||
builder.Append("\\\"");
|
||||
break;
|
||||
case '\\':
|
||||
builder.Append("\\\\");
|
||||
break;
|
||||
case '\b':
|
||||
builder.Append("\\b");
|
||||
break;
|
||||
case '\f':
|
||||
builder.Append("\\f");
|
||||
break;
|
||||
case '\n':
|
||||
builder.Append("\\n");
|
||||
break;
|
||||
case '\r':
|
||||
builder.Append("\\r");
|
||||
break;
|
||||
case '\t':
|
||||
builder.Append("\\t");
|
||||
break;
|
||||
default:
|
||||
int codepoint = Convert.ToInt32(c);
|
||||
if ((codepoint >= 32) && (codepoint <= 126)) {
|
||||
builder.Append(c);
|
||||
} else {
|
||||
builder.Append("\\u");
|
||||
builder.Append(codepoint.ToString("x4"));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
builder.Append('\"');
|
||||
}
|
||||
|
||||
void SerializeOther(object value) {
|
||||
// NOTE: decimals lose precision during serialization.
|
||||
// They always have, I'm just letting you know.
|
||||
// Previously floats and doubles lost precision too.
|
||||
if (value is float) {
|
||||
builder.Append(((float) value).ToString("R"));
|
||||
} else if (value is int
|
||||
|| value is uint
|
||||
|| value is long
|
||||
|| value is sbyte
|
||||
|| value is byte
|
||||
|| value is short
|
||||
|| value is ushort
|
||||
|| value is ulong) {
|
||||
builder.Append(value);
|
||||
} else if (value is double
|
||||
|| value is decimal) {
|
||||
builder.Append(Convert.ToDouble(value).ToString("R"));
|
||||
} else {
|
||||
SerializeString(value.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: adec011f8959049f5accb530c4586615
|
||||
timeCreated: 1444699744
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7d044b59d14c8483c8ddf2641f0995ea
|
||||
folderAsset: yes
|
||||
timeCreated: 1470590513
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
using System;
|
||||
namespace UnityAnalytics
|
||||
{
|
||||
public class DateTimeUtils
|
||||
{
|
||||
public static DateTime s_Epoch = new DateTime(1970,1,1,0,0,0,0,System.DateTimeKind.Utc);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1d7a4f98487b14ea0adfacc0eeca3639
|
||||
timeCreated: 1464232099
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,31 @@
|
|||
/// <summary>
|
||||
/// Heat point.
|
||||
/// </summary>
|
||||
/// This struct is used by the rendering system to define each individual
|
||||
/// heat map datum.
|
||||
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityAnalytics360VideoHeatmap
|
||||
{
|
||||
public struct HeatPoint : IEquatable<HeatPoint>
|
||||
{
|
||||
public Vector3 position;
|
||||
public Vector3 rotation;
|
||||
public int density;
|
||||
public float time;
|
||||
|
||||
public bool Equals(HeatPoint other)
|
||||
{
|
||||
if(position == other.position
|
||||
&& rotation == other.rotation
|
||||
&& density == other.density
|
||||
&& time == other.time)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1280ddf724987485a8cd8346a83f09f5
|
||||
timeCreated: 1437429523
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,442 @@
|
|||
/// <summary>
|
||||
/// Heatmap view model.
|
||||
/// </summary>
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Video;
|
||||
|
||||
namespace UnityAnalytics360VideoHeatmap
|
||||
{
|
||||
public class HeatmapViewModel
|
||||
{
|
||||
static HeatmapViewModel _instance;
|
||||
public static HeatmapViewModel instance
|
||||
{
|
||||
get {
|
||||
if (_instance == null)
|
||||
{
|
||||
_instance = new HeatmapViewModel();
|
||||
}
|
||||
else
|
||||
{
|
||||
Restore();
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The list of raw data files
|
||||
/// </summary>
|
||||
public static List<string> m_RawDataFileList = new List<string>();
|
||||
|
||||
///<summary>
|
||||
/// The list of all the event names
|
||||
/// </summary>
|
||||
static public List<string> eventNames = new List<string>();
|
||||
|
||||
///<summary>
|
||||
/// A mapping of a session's separators to event names
|
||||
/// </summary>
|
||||
//Dictionary of a Dictionary of HeatmapsSeparators
|
||||
static Dictionary<string, object> separatorsToEvents = new Dictionary<string, object>();
|
||||
///<summary>
|
||||
/// A mapping of a session's point data to event names
|
||||
/// </summary>
|
||||
//Dictionary of a Dictionary of a list of Heatpoints
|
||||
static Dictionary<string, object> heatpointsToEvents = new Dictionary<string, object>();
|
||||
|
||||
static Dictionary<string, SeparatorData> selectedSeparators = new Dictionary<string, SeparatorData>();
|
||||
|
||||
static Dictionary<string, HeatPoint[]> currentHeatpointsBySessions = new Dictionary<string, HeatPoint[]>();
|
||||
|
||||
public static float heatpointShowStartTime = 0.0f;
|
||||
public static float heatpointShowEndTime = 0.01f;
|
||||
[SerializeField]
|
||||
private static VideoPlayer _videoPlayer;
|
||||
public static VideoPlayer videoPlayer
|
||||
{
|
||||
get { return _videoPlayer; }
|
||||
set
|
||||
{
|
||||
if (value != null &&_videoPlayer == null || _videoPlayer != value)
|
||||
{
|
||||
_videoPlayer = value;
|
||||
if (_videoPlayer.isPrepared == false)
|
||||
{
|
||||
_videoPlayer.Prepare();
|
||||
_videoPlayer.prepareCompleted += _videoPlayer_PrepareCompleted;
|
||||
}
|
||||
else
|
||||
{
|
||||
_videoPlayer_PrepareCompleted(_videoPlayer);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static int endFrame = 1;
|
||||
|
||||
static string _startDate;
|
||||
public static string startDate
|
||||
{
|
||||
get {
|
||||
return _startDate;
|
||||
}
|
||||
set {
|
||||
if(_startDate != value)
|
||||
{
|
||||
_startDate = value;
|
||||
StartEndTimeUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
static string _endDate;
|
||||
public static string endDate
|
||||
{
|
||||
get
|
||||
{
|
||||
return _endDate;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_endDate != value)
|
||||
{
|
||||
_endDate = value;
|
||||
StartEndTimeUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public delegate void UpdateSeparatorsHandler();
|
||||
public static event UpdateSeparatorsHandler SeparatorsUpdated;
|
||||
|
||||
public delegate void UpdateEventNamesHandler();
|
||||
public static event UpdateEventNamesHandler EventNamesUpdated;
|
||||
|
||||
public delegate void UpdateHeatpointsHandler(Dictionary<string, HeatPoint[]> currentHeatpointsBySessions);
|
||||
public static event UpdateHeatpointsHandler HeatpointsUpdated;
|
||||
|
||||
public delegate void UpdateStartEndDateHandler(string startDate, string endDate);
|
||||
public static event UpdateStartEndDateHandler StartEndDateUpdated;
|
||||
|
||||
public delegate void UpdateCurrentHeatpointsUpdatedHandler(List<HeatPoint[]> newHeatpoints);
|
||||
public static event UpdateCurrentHeatpointsUpdatedHandler CurrentHeatpointsUpdated;
|
||||
|
||||
public delegate void UpdateVideoPlayerHandler(VideoPlayer newPlayer);
|
||||
public static event UpdateVideoPlayerHandler VideoPlayerUpdated;
|
||||
|
||||
public delegate void UpdateVideoFinalFrameHandler(int endFrame);
|
||||
public static event UpdateVideoFinalFrameHandler FinalFrameUpdated;
|
||||
|
||||
public HeatmapViewModel()
|
||||
{
|
||||
if(!HeatmapAggregator.IsEventHandlerRegistered_EventData(HeatmapAggregator_UpdateEventDataHandler))
|
||||
{
|
||||
HeatmapAggregator.UpdateEventData += HeatmapAggregator_UpdateEventDataHandler;
|
||||
}
|
||||
if (!HeatmapAggregator.IsEventHandlerRegistered_SepData(HeatmapAggregator_UpdateSeparators))
|
||||
{
|
||||
HeatmapAggregator.UpdateSeparators += HeatmapAggregator_UpdateSeparators;
|
||||
}
|
||||
if (!HeatmapAggregator.IsEventHandlerRegistered_EventNameData(HeatmapAggregator_UpdateEventNames))
|
||||
{
|
||||
HeatmapAggregator.UpdateEventNames += HeatmapAggregator_UpdateEventNames;
|
||||
}
|
||||
|
||||
//initialize
|
||||
//add separators
|
||||
InitalizeSeperators();
|
||||
//get start date/time
|
||||
endDate = EditorPrefs.HasKey(Application.cloudProjectId + k_EndTimeKey) ? EditorPrefs.GetString(Application.cloudProjectId + k_EndTimeKey) : String.Format("{0:yyyy-MM-dd}", DateTime.UtcNow);
|
||||
startDate = EditorPrefs.HasKey(Application.cloudProjectId + k_StartTimeKey) ? EditorPrefs.GetString(Application.cloudProjectId + k_StartTimeKey) : String.Format("{0:yyyy-MM-dd}", DateTime.UtcNow.Subtract(new TimeSpan(5, 0, 0, 0)));
|
||||
}
|
||||
|
||||
static void Restore ()
|
||||
{
|
||||
if(videoPlayer.isPrepared == false)
|
||||
{
|
||||
videoPlayer.Prepare();
|
||||
videoPlayer.prepareCompleted += _videoPlayer_PrepareCompleted;
|
||||
}
|
||||
else{
|
||||
_videoPlayer_PrepareCompleted(videoPlayer);
|
||||
}
|
||||
}
|
||||
|
||||
static void _videoPlayer_PrepareCompleted(VideoPlayer source)
|
||||
{
|
||||
_videoPlayer.prepareCompleted -= _videoPlayer_PrepareCompleted;
|
||||
if (VideoPlayerUpdated != null)
|
||||
VideoPlayerUpdated(_videoPlayer);
|
||||
|
||||
endFrame = (int)_videoPlayer.frameCount;
|
||||
if (FinalFrameUpdated != null)
|
||||
FinalFrameUpdated(endFrame);
|
||||
|
||||
_videoPlayer.frame = 0;
|
||||
}
|
||||
|
||||
public void ManualOverride ()
|
||||
{
|
||||
if (StartEndDateUpdated != null)
|
||||
StartEndDateUpdated(startDate, endDate);
|
||||
InitalizeSeperators();
|
||||
}
|
||||
|
||||
void HeatmapAggregator_UpdateSeparators(Dictionary<string, object> newSeparatorsToEvents)
|
||||
{
|
||||
separatorsToEvents = newSeparatorsToEvents;
|
||||
if (SeparatorsUpdated != null)
|
||||
SeparatorsUpdated();
|
||||
}
|
||||
|
||||
void HeatmapAggregator_UpdateEventNames(List<string> newEventNames)
|
||||
{
|
||||
eventNames = newEventNames;
|
||||
if (EventNamesUpdated != null)
|
||||
EventNamesUpdated();
|
||||
}
|
||||
|
||||
void HeatmapAggregator_UpdateEventDataHandler(Dictionary<string, object> newHeatpointsToEvents)
|
||||
{
|
||||
heatpointsToEvents = newHeatpointsToEvents;
|
||||
|
||||
InitalizeClipSeparator();
|
||||
|
||||
if (HeatpointsUpdated != null)
|
||||
HeatpointsUpdated(currentHeatpointsBySessions);
|
||||
}
|
||||
|
||||
static void StartEndTimeUpdate()
|
||||
{
|
||||
if (StartEndDateUpdated != null)
|
||||
StartEndDateUpdated(startDate, endDate);
|
||||
}
|
||||
|
||||
public static void UpdateHeatpointShowTimes(float startTime, float endTime)
|
||||
{
|
||||
heatpointShowStartTime = startTime;
|
||||
heatpointShowEndTime = endTime;
|
||||
|
||||
UpdateCurrentHeatpoints();
|
||||
}
|
||||
|
||||
//For 360 video purposes, this is hardcoded in
|
||||
public static string[] GetEventNames()
|
||||
{
|
||||
return new string[] { "Heatmap.PlayerLook" };
|
||||
}
|
||||
|
||||
public Dictionary<string, List<HeatmapSeparators>> GetSeparatorsForEvent(string eventName)
|
||||
{
|
||||
return (separatorsToEvents[eventName] as Dictionary<string, List<HeatmapSeparators>>);
|
||||
}
|
||||
|
||||
void InitalizeSeperators()
|
||||
{
|
||||
SeparatorData sep = new SeparatorData();
|
||||
sep.isActive = true;
|
||||
sep.selectedValue = "Heatmap.PlayerLook";
|
||||
sep.separatorValues = new List<string>();
|
||||
sep.separatorValues.Add("Heatmap.PlayerLook");
|
||||
sep.separatorKey = "eventName";
|
||||
UpdateSeparator("eventName", sep);
|
||||
sep = new SeparatorData();
|
||||
sep.isActive = true;
|
||||
sep.separatorKey = "clipName";
|
||||
sep.separatorValues = new List<string>();
|
||||
if (separatorsToEvents.ContainsKey("Heatmap.PlayerLook"))
|
||||
{
|
||||
|
||||
Dictionary<string, List<HeatmapSeparators>> eventSeps = separatorsToEvents["Heatmap.PlayerLook"] as Dictionary<string, List<HeatmapSeparators>>;
|
||||
foreach (KeyValuePair<string, List<HeatmapSeparators>> currSepList in eventSeps)
|
||||
{
|
||||
sep.separatorValues.AddRange(currSepList.Value.Where(x => !sep.separatorValues.Contains(x.clipName)).Select(x => x.clipName).ToList());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sep.separatorValues.Add("Unnamed");
|
||||
}
|
||||
sep.separatorKey = sep.separatorValues[0];
|
||||
UpdateSeparator("clipName", sep);
|
||||
}
|
||||
|
||||
void InitalizeClipSeparator()
|
||||
{
|
||||
var sep = new SeparatorData();
|
||||
sep.isActive = true;
|
||||
sep.separatorKey = "clipName";
|
||||
sep.separatorValues = new List<string>();
|
||||
if (separatorsToEvents.ContainsKey("Heatmap.PlayerLook"))
|
||||
{
|
||||
Dictionary<string, List<HeatmapSeparators>> eventSeps = separatorsToEvents["Heatmap.PlayerLook"] as Dictionary<string, List<HeatmapSeparators>>;
|
||||
foreach (KeyValuePair<string, List<HeatmapSeparators>> currSepList in eventSeps)
|
||||
{
|
||||
sep.separatorValues.AddRange(currSepList.Value.Where(x => !sep.separatorValues.Contains(x.clipName)).Select(x => x.clipName).ToList());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sep.separatorValues.Add("Unnamed");
|
||||
}
|
||||
sep.separatorKey = sep.separatorValues[0];
|
||||
UpdateSeparator("clipName", sep);
|
||||
}
|
||||
|
||||
public static Dictionary<string, SeparatorData> GetSeparators()
|
||||
{
|
||||
return selectedSeparators;
|
||||
}
|
||||
|
||||
public static void UpdateSeparator(string sep, SeparatorData value)
|
||||
{
|
||||
if (selectedSeparators.ContainsKey(sep))
|
||||
{
|
||||
selectedSeparators[sep] = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
selectedSeparators.Add(sep, value);
|
||||
}
|
||||
UpdateCurrentHeatpoints();
|
||||
//update appropriate settings objects
|
||||
}
|
||||
|
||||
static void UpdateCurrentHeatpoints()
|
||||
{
|
||||
if (selectedSeparators.ContainsKey("eventName") && heatpointsToEvents.ContainsKey(selectedSeparators["eventName"].selectedValue))
|
||||
{
|
||||
var currEventHeatpoints = heatpointsToEvents[selectedSeparators["eventName"].selectedValue] as Dictionary<string, List<HeatPoint>>;
|
||||
var currEventSeparators = separatorsToEvents[selectedSeparators["eventName"].selectedValue] as Dictionary<string, List<HeatmapSeparators>>;
|
||||
List<string> visibleSessionIds = currEventSeparators.Where(currEventSepKV =>
|
||||
{
|
||||
return currEventSepKV.Value.Any(sessSep =>
|
||||
{
|
||||
return sessSep.clipName == selectedSeparators["clipName"].selectedValue;
|
||||
});
|
||||
}).Select(kv => kv.Key).ToList();
|
||||
currentHeatpointsBySessions = currEventHeatpoints.Where(sessKV => visibleSessionIds.Contains(sessKV.Key)).Select(sessKV => new { sessionId = sessKV.Key, points = sessKV.Value }).ToDictionary(item => item.sessionId, item =>
|
||||
{
|
||||
//sorting hacky spot to put it
|
||||
var array = item.points.ToArray(); Array.Sort(array, delegate (HeatPoint x, HeatPoint y)
|
||||
{
|
||||
return x.time.CompareTo(y.time);
|
||||
}); return array;
|
||||
}) as Dictionary<string, HeatPoint[]>;
|
||||
|
||||
if (CurrentHeatpointsUpdated != null)
|
||||
CurrentHeatpointsUpdated(GetCurrentHeatpoints());
|
||||
}
|
||||
}
|
||||
|
||||
public List<string> GetCurrentSessions()
|
||||
{
|
||||
return currentHeatpointsBySessions.Keys.ToList();
|
||||
}
|
||||
|
||||
static List<HeatPoint[]> GetCurrentHeatpoints()
|
||||
{
|
||||
List<HeatPoint[]> retList = new List<HeatPoint[]>();
|
||||
foreach (HeatPoint[] heatpointArr in currentHeatpointsBySessions.Values.ToList())
|
||||
{
|
||||
List<HeatPoint> soonToBeRetArray = new List<HeatPoint>();
|
||||
bool pointAddedForSession = false;
|
||||
for (int a = 0; a < heatpointArr.Length; a++)
|
||||
{
|
||||
// FILTER FOR TIME & POSITION
|
||||
var pt = heatpointArr[a];
|
||||
if (FilterPoint(pt))
|
||||
{
|
||||
soonToBeRetArray.Add(pt);
|
||||
pointAddedForSession = true;
|
||||
}
|
||||
}
|
||||
if (pointAddedForSession == false)
|
||||
{
|
||||
soonToBeRetArray.Add(FilterForInterpolation(heatpointArr));
|
||||
}
|
||||
retList.Add(soonToBeRetArray.ToArray());
|
||||
}
|
||||
return retList;
|
||||
}
|
||||
|
||||
static bool FilterPoint(HeatPoint pt)
|
||||
{
|
||||
if (pt.time < heatpointShowStartTime || pt.time > heatpointShowEndTime)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
static HeatPoint FilterForInterpolation(HeatPoint[] pts)
|
||||
{
|
||||
//iterate through all the points, and take the two with the least difference before/after the bounds of timestamps
|
||||
HeatPoint[] closestPoints = new HeatPoint[2];
|
||||
|
||||
if(videoPlayer != null)
|
||||
{
|
||||
for (int i = 1; i < pts.Length; i++)
|
||||
{
|
||||
if (pts[i].time > heatpointShowStartTime)
|
||||
{
|
||||
closestPoints[0] = pts[i - 1];
|
||||
closestPoints[1] = pts[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//special handling for VideoPlayer and film
|
||||
int startFrame = (int)(heatpointShowStartTime * (int)videoPlayer.frameCount);
|
||||
|
||||
int dataStartFrame = (int)(closestPoints[0].time * (int)videoPlayer.frameCount);
|
||||
int dataEndFrame = (int)(closestPoints[1].time * (int)videoPlayer.frameCount);
|
||||
int dataNumFrames = dataEndFrame - dataStartFrame;
|
||||
if (dataNumFrames == 0)
|
||||
{
|
||||
dataNumFrames = 1;
|
||||
}
|
||||
|
||||
float T = ((float)startFrame - (float)dataStartFrame) / (float)dataNumFrames;
|
||||
HeatPoint interpolatedPoint = new HeatPoint();
|
||||
|
||||
interpolatedPoint.rotation = Vector3.Slerp(closestPoints[0].rotation, closestPoints[1].rotation, T);
|
||||
interpolatedPoint.density = (int)Mathf.Lerp(closestPoints[0].density, closestPoints[1].density, T);
|
||||
return interpolatedPoint;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new HeatPoint();
|
||||
}
|
||||
}
|
||||
|
||||
public static Dictionary<string, HeatPoint[]> GetHeatpointToSessionMapping ()
|
||||
{
|
||||
return currentHeatpointsBySessions;
|
||||
}
|
||||
|
||||
|
||||
const string k_StartTimeKey = "UnityAnalyticsHeatmapAggregateStartTime";
|
||||
const string k_EndTimeKey = "UnityAnalyticsHeatmapAggregateEndTime";
|
||||
}
|
||||
|
||||
|
||||
|
||||
public struct SeparatorData
|
||||
{
|
||||
public string separatorKey;
|
||||
public bool isActive;
|
||||
public List<string> separatorValues;
|
||||
public string selectedValue;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: dccd48c0fb03a4ce3bfed4cec201164d
|
||||
timeCreated: 1470590513
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5ecd5096688ba475ea13c7b46da06db9
|
||||
folderAsset: yes
|
||||
timeCreated: 1437429523
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,17 @@
|
|||
using System;
|
||||
|
||||
namespace UnityAnalytics360VideoHeatmap
|
||||
{
|
||||
public enum AggregationMethod
|
||||
{
|
||||
Increment,
|
||||
Cumulative,
|
||||
Average,
|
||||
Max,
|
||||
Min,
|
||||
First,
|
||||
Last,
|
||||
Percentile
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 15515b3140cec4ea7b0c6348978fe058
|
||||
timeCreated: 1461623559
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,38 @@
|
|||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityAnalytics360VideoHeatmap
|
||||
{
|
||||
public class GradientContainer : MonoBehaviour
|
||||
{
|
||||
public Gradient ColorGradient;
|
||||
|
||||
static Color s_HighDensityColor = new Color(1f, 0, 0, 1f);
|
||||
static Color s_MediumDensityColor = new Color(1f, 1f, 0, 1f);
|
||||
static Color s_LowDensityColor = new Color(0, 1f, 1f, 1f);
|
||||
|
||||
|
||||
public GradientContainer()
|
||||
{
|
||||
ColorGradient = new Gradient();
|
||||
GradientColorKey[] colorKeys = new GradientColorKey[3];
|
||||
colorKeys[0].color = s_LowDensityColor;
|
||||
colorKeys[0].time = 0f;
|
||||
colorKeys[1].color = s_MediumDensityColor;
|
||||
colorKeys[1].time = 0.1f;
|
||||
colorKeys[2].color = s_HighDensityColor;
|
||||
colorKeys[2].time = 1f;
|
||||
|
||||
GradientAlphaKey[] alphaKeys = new GradientAlphaKey[3];
|
||||
alphaKeys[0].alpha = .2f;
|
||||
alphaKeys[0].time = 0f;
|
||||
alphaKeys[1].alpha = .5f;
|
||||
alphaKeys[1].time = .1f;
|
||||
alphaKeys[2].alpha = 1f;
|
||||
alphaKeys[2].time = 1f;
|
||||
|
||||
ColorGradient.SetKeys(colorKeys, alphaKeys);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7fddd7b3aa09845f38cee8786e39337d
|
||||
timeCreated: 1460506453
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|