├── DemoAssets ├── Materials │ ├── lambert1.mat │ ├── bounce.physicMaterial │ ├── lambert1.mat.meta │ └── bounce.physicMaterial.meta ├── Scenes │ ├── ExportToMayaAnimation.unity │ ├── UnityRuntimeRecorder.unity │ ├── ExportToMayaAnimation.unity.meta │ └── UnityRuntimeRecorder.unity.meta ├── Materials.meta ├── Models.meta ├── Scenes.meta └── Models │ └── triangles.ma.meta ├── README.md.meta ├── DemoAssets.meta ├── Unity Runtime Recorder.meta ├── Unity Runtime Recorder ├── Scripts.meta └── Scripts │ ├── BigNumber.meta │ ├── General.meta │ ├── MayaExporter │ ├── MayaNodeDataContainer.cs.meta │ ├── Editor.meta │ ├── MayaAnimationRecorder.cs.meta │ ├── Editor │ │ ├── MayaAnimationRecorderEditor.cs.meta │ │ └── MayaAnimationRecorderEditor.cs │ ├── MayaAnimationRecorder.cs │ └── MayaNodeDataContainer.cs │ ├── FbxExporter.meta │ ├── MayaExporter.meta │ ├── UnityAnimSaver.meta │ ├── UnityAnimSaver │ ├── Editor.meta │ ├── UnityCurveContainer.cs.meta │ ├── UnityObjectAnimation.cs.meta │ ├── UnityAnimationRecorder.cs.meta │ ├── UnityBlendShapeAnimation.cs.meta │ ├── Editor │ │ ├── UnityAnimationRecorderEditor.cs.meta │ │ └── UnityAnimationRecorderEditor.cs │ ├── UnityCurveContainer.cs │ ├── UnityBlendShapeAnimation.cs │ ├── UnityObjectAnimation.cs │ └── UnityAnimationRecorder.cs │ ├── BigNumber │ ├── BigInteger.cs.meta │ └── BigInteger.cs │ ├── FbxExporter │ ├── FbxHelper.cs.meta │ ├── testFBX.cs.meta │ ├── FbxDataNode.cs.meta │ ├── FbxExporter.cs.meta │ ├── FbxObjectNode.cs.meta │ ├── FbxConnectionObj.cs.meta │ ├── FbxObjectSubNode.cs.meta │ ├── FbxObjectsManager.cs.meta │ ├── FbxConnectionsManager.cs.meta │ ├── FbxDefinitionManager.cs.meta │ ├── FbxDefinitionManager.cs │ ├── FbxHelper.cs │ ├── FbxObjectNode.cs │ ├── FbxObjectSubNode.cs │ ├── testFBX.cs │ ├── FbxConnectionObj.cs │ ├── FbxConnectionsManager.cs │ ├── FbxObjectsManager.cs │ ├── FbxDataNode.cs │ └── FbxExporter.cs │ ├── General │ ├── ExportHelper.cs.meta │ ├── TransformTracker.cs.meta │ ├── TransformTracker.cs │ └── ExportHelper.cs │ ├── AnimationRecorderHelper.cs.meta │ └── AnimationRecorderHelper.cs ├── LICENSE.md └── README.md /DemoAssets/Materials/lambert1.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/newyellow/Unity-Runtime-Animation-Recorder/HEAD/DemoAssets/Materials/lambert1.mat -------------------------------------------------------------------------------- /DemoAssets/Materials/bounce.physicMaterial: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/newyellow/Unity-Runtime-Animation-Recorder/HEAD/DemoAssets/Materials/bounce.physicMaterial -------------------------------------------------------------------------------- /DemoAssets/Scenes/ExportToMayaAnimation.unity: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/newyellow/Unity-Runtime-Animation-Recorder/HEAD/DemoAssets/Scenes/ExportToMayaAnimation.unity -------------------------------------------------------------------------------- /DemoAssets/Scenes/UnityRuntimeRecorder.unity: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/newyellow/Unity-Runtime-Animation-Recorder/HEAD/DemoAssets/Scenes/UnityRuntimeRecorder.unity -------------------------------------------------------------------------------- /README.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c5b198b789b8a42cd84cc65f4b17ea68 3 | timeCreated: 1458154907 4 | licenseType: Pro 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /DemoAssets.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8f297068a68d44a3e84bc8972e043e86 3 | folderAsset: yes 4 | timeCreated: 1457806804 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /DemoAssets/Materials/lambert1.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b0fdec05ef49c4057aebe15576507ffb 3 | timeCreated: 1457806805 4 | licenseType: Pro 5 | NativeFormatImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /DemoAssets/Materials/bounce.physicMaterial.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 700ee6cacf7e441b98b2f7199c2cbcac 3 | timeCreated: 1457806888 4 | licenseType: Pro 5 | NativeFormatImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /DemoAssets/Scenes/ExportToMayaAnimation.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5e668b4a0c392428abc319f8ea2e2544 3 | timeCreated: 1457806862 4 | licenseType: Pro 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /DemoAssets/Scenes/UnityRuntimeRecorder.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fdd17d7568d9b48589c191a5aa4d0a04 3 | timeCreated: 1458145382 4 | licenseType: Pro 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /DemoAssets/Materials.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4a68ed9fa7b5546468d99caac87db07e 3 | folderAsset: yes 4 | timeCreated: 1457806805 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /DemoAssets/Models.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5e574ff52257645dd98f52c86adb8db9 3 | folderAsset: yes 4 | timeCreated: 1458145434 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /DemoAssets/Scenes.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 530b6f5fe83284828847ab0e2240545e 3 | folderAsset: yes 4 | timeCreated: 1458145453 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Unity Runtime Recorder.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 162c3d11bc79a4e749cb9ca062f08322 3 | folderAsset: yes 4 | timeCreated: 1457257419 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 474051f197d4f4bf499db22e47296333 3 | folderAsset: yes 4 | timeCreated: 1457257430 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts/BigNumber.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 221cbc6d6c3f74ea99193693a98f26ac 3 | folderAsset: yes 4 | timeCreated: 1507563195 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts/General.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2197cba6776d349c88b0fdf711fb27e1 3 | folderAsset: yes 4 | timeCreated: 1507368868 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts/MayaExporter/MayaNodeDataContainer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c56e7d6acbae44ea696ca765e4f762e1 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | userData: 9 | -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts/FbxExporter.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ea2ad166eb36546e79df07cfe05cd24f 3 | folderAsset: yes 4 | timeCreated: 1507446292 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts/MayaExporter.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 697f95c1b26164a70bb0f3d47f41e185 3 | folderAsset: yes 4 | timeCreated: 1457864020 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts/UnityAnimSaver.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 081de68ca02bb4776b3e627d0f073d6a 3 | folderAsset: yes 4 | timeCreated: 1457863999 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts/MayaExporter/Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 79935bc25d1764069b5d48e9be6c897c 3 | folderAsset: yes 4 | timeCreated: 1457864061 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts/UnityAnimSaver/Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 918f9fa32aea14b03827c103e817b321 3 | folderAsset: yes 4 | timeCreated: 1458144013 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts/BigNumber/BigInteger.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cfeb33ce348ef4e1fa0afa94abd9a2d3 3 | timeCreated: 1507563201 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts/FbxExporter/FbxHelper.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b39c151acc4f14e7290380b60501c0b4 3 | timeCreated: 1507553363 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts/FbxExporter/testFBX.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2c1f326ede6004556a569ab967c98185 3 | timeCreated: 1507446298 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts/General/ExportHelper.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cd28a2b9ce5f54dccb50a2b62a8756b7 3 | timeCreated: 1507369187 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts/AnimationRecorderHelper.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: faf88db2597384c74919a3be46d2deee 3 | timeCreated: 1458117919 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts/FbxExporter/FbxDataNode.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5f470e4bf797b4b2c8247d4d92b9bb4a 3 | timeCreated: 1507565239 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts/FbxExporter/FbxExporter.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 452148c5daec3463e8ce370884fed1d6 3 | timeCreated: 1507538300 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts/FbxExporter/FbxObjectNode.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0d442d8bdbb34466d84311d5689950d0 3 | timeCreated: 1507536629 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts/General/TransformTracker.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ee039b0acee3b41dba3ddacf8fc18266 3 | timeCreated: 1507368911 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts/FbxExporter/FbxConnectionObj.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: dc3086ca71f54494783b3839787b945f 3 | timeCreated: 1507549470 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts/FbxExporter/FbxObjectSubNode.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2a747a321cc7c4a96be98f04af964a7a 3 | timeCreated: 1507540324 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts/FbxExporter/FbxObjectsManager.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b2ed675e6aabc4c879f4d9c623d96588 3 | timeCreated: 1507538320 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts/FbxExporter/FbxConnectionsManager.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 189a614dc7d434055b97321d908df471 3 | timeCreated: 1507548350 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts/FbxExporter/FbxDefinitionManager.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 278fb85fc4f464cb8b5e8f765858f326 3 | timeCreated: 1507564936 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts/MayaExporter/MayaAnimationRecorder.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f6272a0c874e44c39a1eb66510a66797 3 | timeCreated: 1457807050 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts/UnityAnimSaver/UnityCurveContainer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5bc061fccc1664207927b5bdaa37419f 3 | timeCreated: 1457258850 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts/UnityAnimSaver/UnityObjectAnimation.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4f06ea47b3ceb40cca4ba8424e7259b8 3 | timeCreated: 1457260381 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts/FbxExporter/FbxDefinitionManager.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | public class FbxDefinitionManager : MonoBehaviour { 6 | 7 | // Use this for initialization 8 | void Start () { 9 | 10 | } 11 | 12 | // Update is called once per frame 13 | void Update () { 14 | 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts/UnityAnimSaver/UnityAnimationRecorder.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a9d61879c2b6b4edcabca7e5b99f7d55 3 | timeCreated: 1457260986 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts/UnityAnimSaver/UnityBlendShapeAnimation.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3f725a1e7cd084215b2926fbe05fa2a6 3 | timeCreated: 1457260381 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts/MayaExporter/Editor/MayaAnimationRecorderEditor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a697db0003ed14b499e9abda58ad9546 3 | timeCreated: 1457864069 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts/UnityAnimSaver/Editor/UnityAnimationRecorderEditor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1c6fc927933504d688a04d84f3081acb 3 | timeCreated: 1458144024 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts/FbxExporter/FbxHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using ScottGarland; 5 | 6 | public static class FbxHelper { 7 | 8 | public static string getFbxSeconds ( int frameIndex, int frameRate ) { 9 | BigInteger result = new BigInteger("46186158000"); 10 | result = BigInteger.Multiply (result, frameIndex); 11 | result = BigInteger.Divide (result, frameRate); 12 | 13 | return result.ToString (); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts/UnityAnimSaver/UnityCurveContainer.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | public class UnityCurveContainer { 5 | 6 | public string propertyName = ""; 7 | public AnimationCurve animCurve; 8 | 9 | public UnityCurveContainer( string _propertyName ) { 10 | animCurve = new AnimationCurve (); 11 | propertyName = _propertyName; 12 | } 13 | 14 | public void AddValue( float animTime, float animValue ) 15 | { 16 | Keyframe key = new Keyframe (animTime, animValue, 0.0f, 0.0f); 17 | animCurve.AddKey (key); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts/AnimationRecorderHelper.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | public static class AnimationRecorderHelper { 5 | 6 | public static string GetTransformPathName ( Transform rootTransform, Transform targetTransform ) { 7 | 8 | string returnName = targetTransform.name; 9 | Transform tempObj = targetTransform; 10 | 11 | // it is the root transform 12 | if (tempObj == rootTransform) 13 | return ""; 14 | 15 | while (tempObj.parent != rootTransform) { 16 | returnName = tempObj.parent.name + "/" + returnName; 17 | tempObj = tempObj.parent; 18 | } 19 | 20 | return returnName; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Newyellow 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts/General/TransformTracker.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | public class TransformTracker { 6 | 7 | Transform targetTransform; 8 | 9 | bool recordPos = false; 10 | bool recordRot = false; 11 | bool recordScale = false; 12 | 13 | public List posDataList; 14 | public List rotDataList; 15 | public List scaleDataList; 16 | 17 | public TransformTracker (Transform targetObj, bool trackPos, bool trackRot, bool trackScale) { 18 | 19 | targetTransform = targetObj; 20 | 21 | if (trackPos) { 22 | posDataList = new List (); 23 | recordPos = trackPos; 24 | } 25 | 26 | if (trackRot) { 27 | rotDataList = new List (); 28 | recordRot = trackRot; 29 | } 30 | 31 | if (trackScale) { 32 | scaleDataList = new List (); 33 | recordScale = trackScale; 34 | } 35 | } 36 | 37 | public void recordFrame() { 38 | if( recordPos ) 39 | posDataList.Add (targetTransform.localPosition); 40 | 41 | if (recordRot) 42 | rotDataList.Add (targetTransform.localRotation); 43 | 44 | if (recordScale) 45 | scaleDataList.Add (targetTransform.localScale); 46 | } 47 | } -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts/UnityAnimSaver/UnityBlendShapeAnimation.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | public class UnityBlendShapeAnimation { 5 | 6 | public UnityCurveContainer[] curves; 7 | public SkinnedMeshRenderer skinMeshObj; 8 | string[] blendShapeNames; 9 | int blendShapeCount = 0; 10 | public string pathName = ""; 11 | 12 | public UnityBlendShapeAnimation( string hierarchyPath, SkinnedMeshRenderer observeSkinnedMeshRenderer ) { 13 | pathName = hierarchyPath; 14 | skinMeshObj = observeSkinnedMeshRenderer; 15 | 16 | //int blendShapeCount = skinMeshObj.getbl 17 | Mesh blendShapeMesh = skinMeshObj.sharedMesh; 18 | blendShapeCount = blendShapeMesh.blendShapeCount; 19 | 20 | blendShapeNames = new string[blendShapeCount]; 21 | curves = new UnityCurveContainer[blendShapeCount]; 22 | 23 | // create curve objs and add names 24 | for (int i = 0; i < blendShapeCount; i++) { 25 | blendShapeNames [i] = blendShapeMesh.GetBlendShapeName (i); 26 | curves [i] = new UnityCurveContainer ("blendShape." + blendShapeNames [i]); 27 | } 28 | } 29 | 30 | public void AddFrame ( float time ) { 31 | 32 | for (int i = 0; i < blendShapeCount; i++) 33 | curves [i].AddValue (time, skinMeshObj.GetBlendShapeWeight (i)); 34 | 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts/FbxExporter/FbxObjectNode.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | public class FbxObjectNode { 6 | 7 | public string nodeName; 8 | public string nodeValue; 9 | 10 | string headerString = ""; 11 | 12 | List subNodes; 13 | 14 | public FbxObjectNode (string nodeType, string nodeId, string nodeName, string subType) { 15 | headerString = nodeType + ": " + nodeId + ", \"" + nodeName + "\", \"" + subType + "\" {\n"; 16 | subNodes = new List (); 17 | } 18 | 19 | public void AddSubnode ( string inputName, string inputValue ) { 20 | FbxObjectSubNode newSubNode = new FbxObjectSubNode (); 21 | newSubNode.SetupData (inputName, inputValue); 22 | 23 | subNodes.Add (newSubNode); 24 | } 25 | 26 | public void AddSubnode ( string inputName, float[] inputFloatData ) { 27 | FbxObjectSubNode newSubNode = new FbxObjectSubNode (); 28 | newSubNode.SetupData (inputName, inputFloatData); 29 | 30 | subNodes.Add (newSubNode); 31 | } 32 | 33 | public void AddSubnode ( string inputName, string[] inputStringData ) { 34 | FbxObjectSubNode newSubNode = new FbxObjectSubNode (); 35 | newSubNode.SetupData (inputName, inputStringData); 36 | 37 | subNodes.Add (newSubNode); 38 | } 39 | 40 | public void AddSubnode ( string inputName, int[] inputIntData ) { 41 | FbxObjectSubNode newSubNode = new FbxObjectSubNode (); 42 | newSubNode.SetupData (inputName, inputIntData); 43 | 44 | subNodes.Add (newSubNode); 45 | } 46 | 47 | public string GetResultString () { 48 | string resultStr = "\t" + headerString; 49 | 50 | for (int i = 0; i < subNodes.Count; i++) 51 | resultStr += "\t\t" + subNodes [i].GetResultString (); 52 | 53 | resultStr += "\t}\n"; 54 | 55 | return resultStr; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts/FbxExporter/FbxObjectSubNode.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | public class FbxObjectSubNode { 6 | 7 | public string nodeName; 8 | public string nodeValue; 9 | 10 | public FbxObjectSubNode () { 11 | nodeName = ""; 12 | nodeValue = ""; 13 | } 14 | 15 | public void SetupData ( string inputName, string inputValue ) { 16 | nodeName = inputName + ": "; 17 | nodeValue = inputValue; 18 | } 19 | 20 | public void SetupData ( string inputName, float[] inputData ) { 21 | nodeName = inputName + ": *" + inputData.Length.ToString() + " "; 22 | nodeValue = "{\n\t\t\ta: "; 23 | 24 | for( int i=0; i< inputData.Length; i++ ) 25 | { 26 | if (i == 0) 27 | nodeValue += inputData[i].ToString (); 28 | else 29 | nodeValue += "," + inputData[i].ToString (); 30 | } 31 | nodeValue += "\n\t\t}"; 32 | } 33 | 34 | public void SetupData ( string inputName, int[] inputData ) { 35 | nodeName = inputName + ": *" + inputData.Length.ToString() + " "; 36 | nodeValue = "{\n\t\t\ta: "; 37 | 38 | for( int i=0; i< inputData.Length; i++ ) 39 | { 40 | if (i == 0) 41 | nodeValue += inputData[i].ToString (); 42 | else 43 | nodeValue += "," + inputData[i].ToString (); 44 | } 45 | nodeValue += "\n\t\t}"; 46 | } 47 | 48 | public void SetupData ( string inputName, string[] inputData ) { 49 | nodeName = inputName + ": *" + inputData.Length.ToString() + " "; 50 | nodeValue = "{\n\t\t\ta: "; 51 | 52 | for( int i=0; i< inputData.Length; i++ ) 53 | { 54 | if (i == 0) 55 | nodeValue += inputData[i]; 56 | else 57 | nodeValue += "," + inputData[i]; 58 | } 59 | nodeValue += "\n\t\t}"; 60 | } 61 | 62 | public string GetResultString () { 63 | return nodeName + nodeValue + "\n"; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts/UnityAnimSaver/UnityObjectAnimation.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | public class UnityObjectAnimation { 5 | 6 | public UnityCurveContainer[] curves; 7 | public Transform observeGameObject; 8 | public string pathName = ""; 9 | 10 | public UnityObjectAnimation( string hierarchyPath, Transform observeObj ) { 11 | pathName = hierarchyPath; 12 | observeGameObject = observeObj; 13 | 14 | curves = new UnityCurveContainer[10]; 15 | 16 | curves [0] = new UnityCurveContainer( "localPosition.x" ); 17 | curves [1] = new UnityCurveContainer( "localPosition.y" ); 18 | curves [2] = new UnityCurveContainer( "localPosition.z" ); 19 | 20 | curves [3] = new UnityCurveContainer( "localRotation.x" ); 21 | curves [4] = new UnityCurveContainer( "localRotation.y" ); 22 | curves [5] = new UnityCurveContainer( "localRotation.z" ); 23 | curves [6] = new UnityCurveContainer( "localRotation.w" ); 24 | 25 | 26 | curves [7] = new UnityCurveContainer( "localScale.x" ); 27 | curves [8] = new UnityCurveContainer( "localScale.y" ); 28 | curves [9] = new UnityCurveContainer( "localScale.z" ); 29 | } 30 | 31 | public void AddFrame ( float time ) { 32 | 33 | curves [0].AddValue (time, observeGameObject.localPosition.x); 34 | curves [1].AddValue (time, observeGameObject.localPosition.y); 35 | curves [2].AddValue (time, observeGameObject.localPosition.z); 36 | 37 | curves [3].AddValue (time, observeGameObject.localRotation.x); 38 | curves [4].AddValue (time, observeGameObject.localRotation.y); 39 | curves [5].AddValue (time, observeGameObject.localRotation.z); 40 | curves [6].AddValue (time, observeGameObject.localRotation.w); 41 | 42 | curves [7].AddValue (time, observeGameObject.localScale.x); 43 | curves [8].AddValue (time, observeGameObject.localScale.y); 44 | curves [9].AddValue (time, observeGameObject.localScale.z); 45 | 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts/FbxExporter/testFBX.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using System.Text.RegularExpressions; 5 | using System.IO; 6 | 7 | public class testFBX : MonoBehaviour 8 | { 9 | 10 | public string filePath; 11 | 12 | // Use this for initialization 13 | void Start () 14 | { 15 | LoadAttribute ("Connections"); 16 | } 17 | 18 | // Update is called once per frame 19 | void Update () 20 | { 21 | 22 | } 23 | 24 | void LoadAttribute (string attributeName) 25 | { 26 | 27 | Match matchData = Regex.Match (File.ReadAllText (filePath), attributeName + ":[ ]*\\{[^\\}]*\\}"); 28 | 29 | Debug.Log (matchData.Length); 30 | Debug.Log (matchData.Value); 31 | 32 | // ;AnimCurveNode::R, AnimLayer::BaseLayer 33 | // C: "OO",105553119832896,140244214405232 34 | // string searchPattern = ";([a-z0-9]*)::([a-z0-9]*),\\s([a-z0-9]*)::([^\\n]*)\\n\\tC:\\s\"([a-z]*)\",([0-9]*),([0-9]*),\\s\"([^\"]*)\""; 35 | // MatchCollection matches = Regex.Matches (matchData.Value, searchPattern, RegexOptions.IgnoreCase); 36 | // 37 | // for (int i = 0; i < matches.Count; i++) { 38 | // Match tempMatch = matches [i]; 39 | // Debug.Log (tempMatch.Value); 40 | // 41 | // for (int g = 0; g < tempMatch.Groups.Count; g++) 42 | // Debug.Log (tempMatch.Groups [g].Value); 43 | // } 44 | 45 | 46 | // string searchPattern = ";([a-z0-9]*)::([a-z0-9]*),\\s([a-z0-9]*)::([^\\n]*)\\n\\tC:\\s\"([a-z]*)\",([0-9]*),([0-9]*)([^\\n]*)"; 47 | // MatchCollection matches = Regex.Matches (matchData.Value, searchPattern, RegexOptions.IgnoreCase); 48 | // 49 | // for (int i = 0; i < matches.Count; i++) { 50 | // Match tempMatch = matches [i]; 51 | // Debug.Log (tempMatch.Value); 52 | // 53 | // for (int g = 0; g < tempMatch.Groups.Count; g++) 54 | // Debug.Log (tempMatch.Groups [g].Value); 55 | // } 56 | 57 | int startIndex = File.ReadAllText (filePath).IndexOf ("Objects:"); 58 | Debug.Log (startIndex); 59 | int readCounter = 0; 60 | 61 | StreamReader reader = new StreamReader (filePath); 62 | 63 | for (int i = 0; i < startIndex; i++) 64 | reader.Read (); 65 | 66 | // find first '{' 67 | while (true) { 68 | char tempChar = (char)reader.Read (); 69 | ++readCounter; 70 | 71 | if (tempChar == '{') 72 | break; 73 | } 74 | 75 | int bracketBalancer = 1; 76 | 77 | while (true) { 78 | char temp = (char)reader.Read (); 79 | ++readCounter; 80 | 81 | if (temp == '{') 82 | bracketBalancer += 1; 83 | else if (temp == '}') { 84 | bracketBalancer -= 1; 85 | if (bracketBalancer == 0) 86 | break; 87 | } 88 | } 89 | 90 | Debug.Log (readCounter); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts/FbxExporter/FbxConnectionObj.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using System.Text.RegularExpressions; 5 | 6 | public class FbxConnectionObj { 7 | 8 | /* 9 | * ;AnimCurveNode::T, Model::pCube1 10 | * C: "OP",105553124109952,140364338281984, "Lcl Translation" 11 | * 12 | */ 13 | 14 | public string type1; 15 | public string name1; 16 | public string id1; 17 | 18 | public string type2; 19 | public string name2; 20 | public string id2; 21 | 22 | public string relation; 23 | public string relationDesc; 24 | bool hasRelationDesc = false; 25 | 26 | public bool isSucceed = false; 27 | 28 | public FbxConnectionObj (string type1, string name1, string id1, string type2, string name2, string id2, string relation, string relationDesc = "") 29 | { 30 | this.type1 = type1; 31 | this.name1 = name1; 32 | this.id1 = id1; 33 | this.type2 = type2; 34 | this.name2 = name2; 35 | this.id2 = id2; 36 | this.relation = relation; 37 | this.relationDesc = relationDesc; 38 | 39 | if (relationDesc == "") 40 | hasRelationDesc = false; 41 | else 42 | hasRelationDesc = true; 43 | } 44 | 45 | public FbxConnectionObj ( string connectionStr ) { 46 | string pattern = "\\t;([^:]*)::([^,]*),\\s([^:]*)::([^\\n]*)\\n\\tC:\\s\"([^\"]*)\",([0-9]*),([0-9]*)([^\n]*\n)"; 47 | Match regMatch = Regex.Match (connectionStr, pattern); 48 | 49 | if (regMatch.Success) { 50 | //regMatch.Groups[0].Value : all text 51 | type1 = regMatch.Groups [1].Value; 52 | name1 = regMatch.Groups [2].Value; 53 | type2 = regMatch.Groups [3].Value; 54 | name2 = regMatch.Groups [4].Value; 55 | relation = regMatch.Groups [5].Value; 56 | id1 = regMatch.Groups [6].Value; 57 | id2 = regMatch.Groups [7].Value; 58 | string relationDescText = regMatch.Groups [8].Value; 59 | 60 | // get relation desc 61 | string relationDescPattern = ",\\s\"([^\"]*)\""; 62 | Match relationDescMatch = Regex.Match (relationDescText, relationDescPattern); 63 | 64 | if (relationDescMatch.Success) { 65 | hasRelationDesc = true; 66 | relationDesc = relationDescMatch.Groups [1].Value; 67 | } else { 68 | hasRelationDesc = false; 69 | relationDesc = ""; 70 | } 71 | 72 | // got data 73 | isSucceed = true; 74 | } else 75 | isSucceed = false; 76 | } 77 | 78 | public string getOutputData () { 79 | if( hasRelationDesc ) 80 | return "\t;"+type1+"::"+name1+", "+type2+"::"+name2+"\n\tC: \""+relation+"\","+id1+","+id2+", \""+relationDesc+"\"\n"; 81 | else 82 | return "\t;"+type1+"::"+name1+", "+type2+"::"+name2+"\n\tC: \""+relation+"\","+id1+","+id2+"\n"; 83 | } 84 | 85 | public void Log () { 86 | Debug.Log (type1 + " " + name1 + " " + type2 + " " + name2 + " " + relation + " " + id1 + " " + id2 + " " + relationDesc); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts/General/ExportHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | public class ExportHelper { 6 | 7 | // convert unity translation to maya translation 8 | public static Vector3 UnityToMayaPosition (Vector3 t) 9 | { 10 | return new Vector3(-t.x, t.y, t.z); 11 | } 12 | 13 | // convert unity rotation to maya rotation 14 | // Vector3 Export2MayaRotation (Vector3 r) 15 | // { 16 | // 17 | // //return new Vector3 (r.z, r.y, r.x); 18 | // // return new Vector3(r.z, r.x, r.y); 19 | // //return new Vector3(r.x, -r.y, -r.z); 20 | // 21 | // Vector3 flippedRot = new Vector3 (r.x, -r.y, -r.z); 22 | // Quaternion qx = Quaternion.AngleAxis (flippedRot.x, Vector3.right); 23 | // Quaternion qy = Quaternion.AngleAxis (flippedRot.y, Vector3.up); 24 | // Quaternion qz = Quaternion.AngleAxis (flippedRot.z, Vector3.forward); 25 | // Quaternion unityRotationQ = qx * qy * qz; 26 | // 27 | // return WikiQuaternionToRotation (unityRotationQ); 28 | // } 29 | 30 | public static Vector3 UnityToMayaRotation (Quaternion q) { 31 | // x,y,z is Maya's rotation order 32 | // and due to right hand / left hand coordinate, y & z should *-1 33 | return WikiQuaternionToRotation(q, new Vector3(1,-1,-1)); 34 | } 35 | 36 | public static Vector3 WikiQuaternionToRotation (Quaternion q, Vector3 axisMultiplier) { 37 | 38 | /* 39 | * This function is a convertion of python sample code in a wiki page 40 | * 41 | * https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles 42 | * 43 | * Thanks to the GREAT INTERNET 44 | * 45 | */ 46 | 47 | float x = 0.0f; 48 | float y = 0.0f; 49 | float z = 0.0f; 50 | 51 | // roll (x-axis rotation) 52 | float ysqr = q.y * q.y; 53 | 54 | float t0 = 2.0f * (q.w * q.x + q.y * q.z); 55 | float t1 = 1.0f - 2.0f * (q.x * q.x + ysqr); 56 | x = Mathf.Atan2 (t0, t1) * Mathf.Rad2Deg; 57 | 58 | float t2 = 2.0f * (q.w * q.y - q.z * q.x); 59 | if (t2 > 1.0f) 60 | t2 = 1.0f; 61 | else if (t2 < -1.0f) 62 | t2 = -1.0f; 63 | y = Mathf.Asin (t2) * Mathf.Rad2Deg; 64 | 65 | float t3 = 2.0f * (q.w * q.z + q.x * q.y); 66 | float t4 = 1.0f - 2.0f * (ysqr + q.z * q.z); 67 | z = Mathf.Atan2 (t3, t4) * Mathf.Rad2Deg; 68 | 69 | return new Vector3(x * axisMultiplier.x, y * axisMultiplier.y, z * axisMultiplier.z); 70 | } 71 | 72 | // not used 73 | // Vector3 UnityRot2Maya(Quaternion q) 74 | // { 75 | // float x = 180f / Mathf.PI *Mathf.Atan2(2f * q.x * q.w + 2f * q.y * q.z, 1 - 2f * (q.z*q.z + q.w*q.w)); // Yaw 76 | // float y = 180f / Mathf.PI *Mathf.Asin(2f * ( q.x * q.z - q.w * q.y ) ); // Pitch 77 | // float z = 180f / Mathf.PI *Mathf.Atan2(2f * q.x * q.y + 2f * q.z * q.w, 1 - 2f * (q.y*q.y + q.z*q.z)); // Roll 78 | // return new Vector3( (180f-x), y , -z); 79 | // } 80 | } 81 | -------------------------------------------------------------------------------- /DemoAssets/Models/triangles.ma.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 92b48d5049b5643d1bfea8a073ed85d6 3 | timeCreated: 1457806805 4 | licenseType: Pro 5 | ModelImporter: 6 | serializedVersion: 19 7 | fileIDToRecycleName: 8 | 100000: pPyramid1 9 | 100002: pPyramid2 10 | 100004: pPyramid3 11 | 100006: pPyramid4 12 | 100008: pPyramid5 13 | 100010: pPyramid6 14 | 100012: pPyramid7 15 | 100014: pPyramid8 16 | 100016: pPyramid9 17 | 100018: //RootNode 18 | 400000: pPyramid1 19 | 400002: pPyramid2 20 | 400004: pPyramid3 21 | 400006: pPyramid4 22 | 400008: pPyramid5 23 | 400010: pPyramid6 24 | 400012: pPyramid7 25 | 400014: pPyramid8 26 | 400016: pPyramid9 27 | 400018: //RootNode 28 | 2300000: pPyramid1 29 | 2300002: pPyramid2 30 | 2300004: pPyramid3 31 | 2300006: pPyramid4 32 | 2300008: pPyramid5 33 | 2300010: pPyramid6 34 | 2300012: pPyramid7 35 | 2300014: pPyramid8 36 | 2300016: pPyramid9 37 | 3300000: pPyramid1 38 | 3300002: pPyramid2 39 | 3300004: pPyramid3 40 | 3300006: pPyramid4 41 | 3300008: pPyramid5 42 | 3300010: pPyramid6 43 | 3300012: pPyramid7 44 | 3300014: pPyramid8 45 | 3300016: pPyramid9 46 | 4300000: pPyramid1 47 | 4300002: pPyramid2 48 | 4300004: pPyramid3 49 | 4300006: pPyramid4 50 | 4300008: pPyramid5 51 | 4300010: pPyramid6 52 | 4300012: pPyramid7 53 | 4300014: pPyramid8 54 | 4300016: pPyramid9 55 | 9500000: //RootNode 56 | materials: 57 | importMaterials: 1 58 | materialName: 0 59 | materialSearch: 1 60 | animations: 61 | legacyGenerateAnimations: 4 62 | bakeSimulation: 0 63 | resampleRotations: 1 64 | optimizeGameObjects: 0 65 | motionNodeName: 66 | animationImportErrors: 67 | animationImportWarnings: 68 | animationRetargetingWarnings: 69 | animationDoRetargetingWarnings: 0 70 | animationCompression: 1 71 | animationRotationError: 0.5 72 | animationPositionError: 0.5 73 | animationScaleError: 0.5 74 | animationWrapMode: 0 75 | extraExposedTransformPaths: [] 76 | clipAnimations: [] 77 | isReadable: 1 78 | meshes: 79 | lODScreenPercentages: [] 80 | globalScale: 1 81 | meshCompression: 0 82 | addColliders: 0 83 | importBlendShapes: 1 84 | swapUVChannels: 0 85 | generateSecondaryUV: 0 86 | useFileUnits: 1 87 | optimizeMeshForGPU: 1 88 | keepQuads: 0 89 | weldVertices: 1 90 | secondaryUVAngleDistortion: 8 91 | secondaryUVAreaDistortion: 15.000001 92 | secondaryUVHardAngle: 88 93 | secondaryUVPackMargin: 4 94 | useFileScale: 1 95 | tangentSpace: 96 | normalSmoothAngle: 60 97 | normalImportMode: 0 98 | tangentImportMode: 3 99 | importAnimation: 1 100 | copyAvatar: 0 101 | humanDescription: 102 | human: [] 103 | skeleton: [] 104 | armTwist: 0.5 105 | foreArmTwist: 0.5 106 | upperLegTwist: 0.5 107 | legTwist: 0.5 108 | armStretch: 0.05 109 | legStretch: 0.05 110 | feetSpacing: 0 111 | rootMotionBoneName: 112 | hasTranslationDoF: 0 113 | lastHumanDescriptionAvatarSource: {instanceID: 0} 114 | animationType: 2 115 | humanoidOversampling: 1 116 | additionalBone: 0 117 | userData: 118 | assetBundleName: 119 | assetBundleVariant: 120 | -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts/UnityAnimSaver/Editor/UnityAnimationRecorderEditor.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEditor; 3 | using System.Collections; 4 | 5 | [CustomEditor(typeof(UnityAnimationRecorder))] 6 | public class UnityAnimationRecorderEditor : Editor { 7 | 8 | // save file path 9 | SerializedProperty savePath; 10 | SerializedProperty fileName; 11 | 12 | SerializedProperty startRecordKey; 13 | SerializedProperty stopRecordKey; 14 | 15 | // options 16 | SerializedProperty showLogGUI; 17 | SerializedProperty recordLimitedFrames; 18 | SerializedProperty recordFrames; 19 | SerializedProperty recordBlendShape; 20 | 21 | SerializedProperty changeTimeScale; 22 | SerializedProperty timeScaleOnStart; 23 | SerializedProperty timeScaleOnRecord; 24 | 25 | 26 | void OnEnable () { 27 | 28 | savePath = serializedObject.FindProperty ("savePath"); 29 | fileName = serializedObject.FindProperty ("fileName"); 30 | 31 | startRecordKey = serializedObject.FindProperty ("startRecordKey"); 32 | stopRecordKey = serializedObject.FindProperty ("stopRecordKey"); 33 | 34 | showLogGUI = serializedObject.FindProperty ("showLogGUI"); 35 | recordLimitedFrames = serializedObject.FindProperty ("recordLimitedFrames"); 36 | recordFrames = serializedObject.FindProperty ("recordFrames"); 37 | recordBlendShape = serializedObject.FindProperty ("recordBlendShape"); 38 | 39 | changeTimeScale = serializedObject.FindProperty ("changeTimeScale"); 40 | timeScaleOnStart = serializedObject.FindProperty ("timeScaleOnStart"); 41 | timeScaleOnRecord = serializedObject.FindProperty ("timeScaleOnRecord"); 42 | 43 | } 44 | 45 | public override void OnInspectorGUI () { 46 | serializedObject.Update (); 47 | 48 | EditorGUILayout.LabelField ("== Path Settings =="); 49 | 50 | if (GUILayout.Button ("Set Save Path")) { 51 | string defaultName = serializedObject.targetObject.name + "-Animation"; 52 | string targetPath = EditorUtility.SaveFilePanelInProject ("Save Anim File To ..", defaultName, "", "please select a folder and enter the file name"); 53 | 54 | int lastIndex = targetPath.LastIndexOf ("/"); 55 | savePath.stringValue = targetPath.Substring (0, lastIndex + 1); 56 | string toFileName = targetPath.Substring (lastIndex + 1); 57 | 58 | fileName.stringValue = toFileName; 59 | } 60 | EditorGUILayout.PropertyField (savePath); 61 | EditorGUILayout.PropertyField (fileName); 62 | 63 | 64 | EditorGUILayout.Space (); 65 | 66 | // keys setting 67 | EditorGUILayout.LabelField( "== Control Keys ==" ); 68 | EditorGUILayout.PropertyField (startRecordKey); 69 | EditorGUILayout.PropertyField (stopRecordKey); 70 | 71 | EditorGUILayout.Space (); 72 | 73 | // Other Settings 74 | EditorGUILayout.LabelField( "== Other Settings ==" ); 75 | recordBlendShape.boolValue = EditorGUILayout.Toggle ("Record BlendShapes", recordBlendShape.boolValue); 76 | bool timeScaleOption = EditorGUILayout.Toggle ( "Change Time Scale", changeTimeScale.boolValue); 77 | changeTimeScale.boolValue = timeScaleOption; 78 | 79 | if (timeScaleOption) { 80 | timeScaleOnStart.floatValue = EditorGUILayout.FloatField ("TimeScaleOnStart", timeScaleOnStart.floatValue); 81 | timeScaleOnRecord.floatValue = EditorGUILayout.FloatField ("TimeScaleOnRecord", timeScaleOnRecord.floatValue); 82 | } 83 | 84 | // gui log message 85 | showLogGUI.boolValue = EditorGUILayout.Toggle ("Show Debug On GUI", showLogGUI.boolValue); 86 | 87 | // recording frames setting 88 | recordLimitedFrames.boolValue = EditorGUILayout.Toggle( "Record Limited Frames", recordLimitedFrames.boolValue ); 89 | 90 | if (recordLimitedFrames.boolValue) 91 | EditorGUILayout.PropertyField (recordFrames); 92 | 93 | serializedObject.ApplyModifiedProperties (); 94 | 95 | //DrawDefaultInspector (); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Unity-Runtime-Animation-Recorder 2 | 3 | This project can make you recording animations in runtime with Unity, and can save into .anim or Maya .ma format. 4 | Though Maya has its own physic simulator, but unity is much faster and can easily control detail movement through scripts. 5 | 6 | ## Installation 7 | 8 | Copy just copy Unity Runtime Recorder folder into your Asset folder and it's ready to go. 9 | If you want to see same sample you can also copy DemoAssets folder. 10 | 11 | 12 | ## How To Use 13 | 14 | Here is a short video demo. 15 | [https://youtu.be/RAjU5KodE1w](https://youtu.be/RAjU5KodE1w) 16 | 17 | ## Unity Anim Saver 18 | ※ this function needs UnityEditor to work, so can only work in the Editor. 19 | 20 | 1. Drag the UnityAnimationRecorder.cs script on any GameObject, and it will record all transforms in children. 21 | 2. Press "Set Save Path" button in the inspector, choose pick a folder and enter file name. 22 | 3. Play the scene, and start/end recording by press the key you set in the inspector. 23 | 4. When End Recording pressed, the .anim file will be generated. 24 | 25 | ## Maya Exporter 26 | 27 | Pretty much the same as Unity Anim Saver. 28 | Additionally, you have to select an .ma file which contains all model information. 29 | 30 | My script doesn't generate model informations for maya, it only record animation data and append them at the end of .ma file. 31 | If you want to export the meshes you make in Unity, you can try [Export2Maya](https://www.assetstore.unity3d.com/en/#!/content/17079) which is a nice plugin I use before. 32 | 33 | ### Export Humanoid Animations to Maya 34 | 35 | ※ This step is no longer needed, the script will solve this problem automatically. But since this section explains the problem and the solution, so not remove it. 36 | 37 | Unity and Maya treat spines differently, which sometimes cause issues when you exporting animation with SkinnedMesh. 38 | 39 | In Maya, there is an additional "Joint Orient". The actual spine rotation is the sum of transform rotation and joint orient. But since Unity doesn't have this attribute, the transform rotation values in Unity is alreay the sum value. While this plugin is recording the values in Unity, the joint orient values will add once more in Maya, cause the recorded result weird. 40 | 41 | In order to record animation correct, we have to make every spines' "joint orient" values to (0,0,0). And here is a tutorial video if you not sure how to do it. 42 | 43 | [Export Humanoid Animation from Unity to Maya - Unity Runtime Animation Recorder](https://youtu.be/Ooxg-rFPTcM) 44 | ※ Now the Maya Exporter script will set all spines' joint orient to (0,0,0), which solves this problem automatically. 45 | 46 | ## FBX Exporter 47 | 48 | 2017-10-10 Implemented FBX exporter, works similar as Maya Exporter. 49 | But for now, there is some memory issue, can't export too complex objects. 50 | 51 |  [Export to FBX Demo Video](https://www.youtube.com/watch?v=Hy2U0UYp6cA) 52 | 53 | Here are a few things to notice: 54 | 55 | 1. The "source FBX file" has to be in ASCII format (you can choose ASCII or Binary while exporting FBX file) 56 | 2. Make sure every nodes' name are exactly the same as the source file 57 | (sometimes nodes' name got changed by Unity or 3D software) 58 |   59 | 60 | ## Dealing with Lag 61 | 62 | If you want to simulate with a big amount of objects, you might ecountered lag. 63 | You just need to adjust the Time.timeScale value in the Project Setting (or by using ChangeTimeScale option in my script). 64 | 65 | All physics in Unity will affect by timeScale setting. 66 | And if you want to modify the object animation through your own script, please use FixedUpdate instead of Update. 67 | 68 | ## License 69 | [MIT](https://github.com/newyellow/Unity-Runtime-Animation-Recorder/blob/master/LICENSE.md) 70 | -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts/FbxExporter/FbxConnectionsManager.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using System.IO; 5 | using System.Text.RegularExpressions; 6 | 7 | public class FbxConnectionsManager { 8 | 9 | string fbxStrData = ""; 10 | string originalConnectionData = ""; 11 | List connObjs; 12 | 13 | public FbxConnectionsManager (string inputData) { 14 | fbxStrData = inputData; 15 | 16 | LoadObjectsData (); 17 | } 18 | 19 | public void EditTargetFile (string targetFilePath) { 20 | string outputData = "Connections: {\n"; 21 | for (int i = 0; i < connObjs.Count; i++) { 22 | outputData += "\t\n"; 23 | outputData += connObjs [i].getOutputData (); 24 | } 25 | outputData += "}\n"; 26 | 27 | string sourceData = File.ReadAllText (targetFilePath); 28 | sourceData = Regex.Replace (sourceData, "Connections:\\s\\s\\{[^\\}]*\\}\\n", outputData); 29 | 30 | File.WriteAllText (targetFilePath, sourceData); 31 | } 32 | 33 | void LoadObjectsData () { 34 | 35 | // find start of the Objects 36 | Match matchResult = Regex.Match(fbxStrData, "Connections:\\s\\s\\{([^\\}]*)\\}"); 37 | string connAll = matchResult.Groups [0].Value; 38 | string allConnAttributes = matchResult.Groups [1].Value; 39 | 40 | Debug.Log (connAll); 41 | Debug.Log (allConnAttributes); 42 | 43 | // load all attributes 44 | connObjs = new List(); 45 | 46 | string[] splliter = { "\t\n" }; 47 | string[] splittedData = allConnAttributes.Split (splliter, System.StringSplitOptions.RemoveEmptyEntries); 48 | 49 | for (int i = 0; i < splittedData.Length; i++) { 50 | FbxConnectionObj tempObj = new FbxConnectionObj (splittedData [i]); 51 | if (tempObj.isSucceed) 52 | connObjs.Add (tempObj); 53 | } 54 | 55 | // debug 56 | Debug.Log("found attributes: " + connObjs.Count); 57 | for (int i = 0; i < connObjs.Count; i++) { 58 | connObjs [i].Log (); 59 | } 60 | 61 | 62 | // test 63 | 64 | // 65 | // int startIndex = fbxStrData.IndexOf ("Objects: {\n"); 66 | // startIndex += ("Objects: {\n").Length; 67 | // 68 | // StringReader reader = new StringReader (fbxStrData); 69 | // 70 | // // skip to start index 71 | // for (int i = 0; i < startIndex; i++) 72 | // reader.Read (); 73 | // 74 | // 75 | // // find the end of the Objects {} 76 | // int bracketBalancer = 1; 77 | // int readCounter = 0; 78 | // 79 | // while (true) { 80 | // char temp = (char)reader.Read (); 81 | // ++readCounter; 82 | // 83 | // if (temp == '{') 84 | // bracketBalancer += 1; 85 | // else if (temp == '}') { 86 | // bracketBalancer -= 1; 87 | // if (bracketBalancer == 0) 88 | // break; 89 | // } 90 | // } 91 | // 92 | // // save other data in string 93 | // originalObjsData = fbxStrData.Substring(startIndex, readCounter-1); 94 | // fbxStrData = fbxStrData.Remove (startIndex, readCounter - 1); 95 | } 96 | 97 | // void SearchAttribute () { 98 | // string searchPattern = "\\t;[^:]*::[^,]*,\\s[^:]*::[^\\n]*\\n\\tC:\\s\"[^\"]*\",[0-9]*,[0-9]*[^\\n]*\\n"; 99 | // } 100 | 101 | public void AddConnectionItem (string type1, string name1, string id1, string type2, string name2, string id2, string relation, string relationDesc = "") { 102 | FbxConnectionObj tempConnObj = new FbxConnectionObj (type1, name1, id1, type2, name2, id2, relation, relationDesc); 103 | connObjs.Add (tempConnObj); 104 | } 105 | 106 | public string searchObjectId (string objectName) { 107 | 108 | for (int i = 0; i < connObjs.Count; i++) { 109 | if (connObjs [i].name2 == objectName) 110 | return connObjs [i].id2; 111 | } 112 | 113 | return ""; 114 | } 115 | 116 | public string getAnimBaseLayerId () { 117 | for (int i = 0; i < connObjs.Count; i++) { 118 | if (connObjs [i].type1 == "AnimLayer") { 119 | if (connObjs [i].name1 == "BaseLayer") 120 | return connObjs [i].id1; 121 | } 122 | } 123 | return ""; 124 | } 125 | 126 | 127 | // string searchPattern = ";([a-z0-9]*)::([a-z0-9]*),\\s([a-z0-9]*)::([^\\n]*)\\n\\tC:\\s\"([a-z]*)\",([0-9]*),([0-9]*),\\s\"([^\"]*)\""; 128 | // MatchCollection matches = Regex.Matches (matchData.Value, searchPattern, RegexOptions.IgnoreCase); 129 | // 130 | // for (int i = 0; i < matches.Count; i++) { 131 | // Match tempMatch = matches [i]; 132 | // Debug.Log (tempMatch.Value); 133 | // 134 | // for (int g = 0; g < tempMatch.Groups.Count; g++) 135 | // Debug.Log (tempMatch.Groups [g].Value); 136 | // } 137 | } 138 | -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts/MayaExporter/Editor/MayaAnimationRecorderEditor.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEditor; 3 | using System.Collections; 4 | 5 | [CustomEditor(typeof(MayaAnimationRecorder))] 6 | public class MayaAnimationRecorderEditor : Editor { 7 | 8 | SerializedProperty saveFolderPath; 9 | SerializedProperty saveFileName; 10 | SerializedProperty originalMaFilePath; 11 | 12 | SerializedProperty startKey; 13 | SerializedProperty endKey; 14 | 15 | SerializedProperty changeTimeScale; 16 | SerializedProperty startGameWithTimeScale; 17 | SerializedProperty startRecordWithTimeScale; 18 | 19 | SerializedProperty showDebugGUI; 20 | 21 | SerializedProperty recordPosition; 22 | SerializedProperty recordRotation; 23 | SerializedProperty recordScale; 24 | 25 | 26 | SerializedProperty recordLimitFrames; 27 | SerializedProperty recordFrames; 28 | 29 | SerializedProperty includePathName; 30 | 31 | void OnEnable () { 32 | 33 | saveFileName = serializedObject.FindProperty ("saveFileName"); 34 | saveFolderPath = serializedObject.FindProperty ("saveFolderPath"); 35 | originalMaFilePath = serializedObject.FindProperty ("originalMaFilePath"); 36 | 37 | startKey = serializedObject.FindProperty ("startKey"); 38 | endKey = serializedObject.FindProperty ("endKey"); 39 | 40 | changeTimeScale = serializedObject.FindProperty ("changeTimeScale"); 41 | startGameWithTimeScale = serializedObject.FindProperty ("startGameWithTimeScale"); 42 | startRecordWithTimeScale = serializedObject.FindProperty ("startRecordWithTimeScale"); 43 | 44 | showDebugGUI = serializedObject.FindProperty ("showLogGUI"); 45 | 46 | recordPosition = serializedObject.FindProperty ("recordPosition"); 47 | recordRotation = serializedObject.FindProperty ("recordRotation"); 48 | recordScale = serializedObject.FindProperty ("recordScale"); 49 | 50 | 51 | recordLimitFrames = serializedObject.FindProperty ("recordLimitFrames"); 52 | recordFrames = serializedObject.FindProperty ("recordFrames"); 53 | 54 | includePathName = serializedObject.FindProperty ("includePathName"); 55 | } 56 | 57 | public override void OnInspectorGUI () { 58 | serializedObject.Update (); 59 | 60 | EditorGUILayout.LabelField ("== Path Settings =="); 61 | 62 | if (GUILayout.Button ("Select MA File")) { 63 | string[] filters = { "Maya ASCII File", "ma" }; 64 | string maFilePath = EditorUtility.OpenFilePanelWithFilters("Select your original .ma file", "", filters ); 65 | originalMaFilePath.stringValue = maFilePath; 66 | } 67 | EditorGUILayout.PropertyField (originalMaFilePath); 68 | 69 | if (GUILayout.Button ("Save File To")) { 70 | string inputPath = EditorUtility.SaveFilePanel( "select temp folder", "", "someFile.ma", "" ); 71 | int lastIndex = inputPath.LastIndexOf ("/"); 72 | 73 | saveFileName.stringValue = inputPath.Substring( lastIndex+1 ); 74 | saveFolderPath.stringValue = inputPath.Substring (0, lastIndex + 1); 75 | } 76 | EditorGUILayout.PropertyField (saveFolderPath); 77 | EditorGUILayout.PropertyField (saveFileName); 78 | 79 | EditorGUILayout.Space (); 80 | 81 | // record setting 82 | EditorGUILayout.LabelField( "== Record Setting ==" ); 83 | recordPosition.boolValue = EditorGUILayout.Toggle ("Record Position", recordPosition.boolValue); 84 | recordRotation.boolValue = EditorGUILayout.Toggle ("Record Rotation", recordRotation.boolValue); 85 | recordScale.boolValue = EditorGUILayout.Toggle ("Record Scale", recordScale.boolValue); 86 | 87 | EditorGUILayout.Space (); 88 | 89 | 90 | // keys setting 91 | EditorGUILayout.LabelField( "== Control Keys ==" ); 92 | EditorGUILayout.PropertyField (startKey); 93 | EditorGUILayout.PropertyField (endKey); 94 | 95 | EditorGUILayout.Space (); 96 | 97 | // Other Settings 98 | EditorGUILayout.LabelField( "== Other Settings ==" ); 99 | bool timeScaleOption = EditorGUILayout.Toggle ( "Change Time Scale", changeTimeScale.boolValue); 100 | changeTimeScale.boolValue = timeScaleOption; 101 | 102 | if (timeScaleOption) { 103 | startGameWithTimeScale.floatValue = EditorGUILayout.FloatField ("TimeScaleOnStart", startGameWithTimeScale.floatValue); 104 | startRecordWithTimeScale.floatValue = EditorGUILayout.FloatField ("TimeScaleOnRecord", startRecordWithTimeScale.floatValue); 105 | } 106 | 107 | // gui log message 108 | showDebugGUI.boolValue = EditorGUILayout.Toggle ("Show Debug On GUI", showDebugGUI.boolValue); 109 | 110 | // recording frames setting 111 | recordLimitFrames.boolValue = EditorGUILayout.Toggle( "Record Limited Frames", recordLimitFrames.boolValue ); 112 | 113 | if (recordLimitFrames.boolValue) 114 | EditorGUILayout.PropertyField (recordFrames); 115 | 116 | includePathName.boolValue = EditorGUILayout.Toggle ("Include Path Name", includePathName.boolValue); 117 | serializedObject.ApplyModifiedProperties (); 118 | 119 | //DrawDefaultInspector (); 120 | } 121 | 122 | } 123 | -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts/FbxExporter/FbxObjectsManager.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using System.IO; 5 | using System.Text.RegularExpressions; 6 | 7 | public class FbxObjectsManager 8 | { 9 | 10 | public FbxDataNode objMainNode; 11 | string saveFileFolder; 12 | 13 | public FbxObjectsManager (FbxDataNode inputObjNode, string folder) 14 | { 15 | objMainNode = inputObjNode; 16 | saveFileFolder = folder; 17 | } 18 | 19 | // insert new objs into file 20 | public void EditTargetFile (string targetFilePath) 21 | { 22 | string sourceData = File.ReadAllText (targetFilePath); 23 | string newData = ""; 24 | 25 | // find start of the Objects 26 | int startIndex = sourceData.IndexOf ("Objects: {\n"); 27 | // copy data into new 28 | newData = sourceData.Substring (0, startIndex); 29 | 30 | 31 | startIndex += ("Objects: {\n").Length; 32 | 33 | StringReader reader = new StringReader (sourceData); 34 | 35 | // skip to start index 36 | for (int i = 0; i < startIndex; i++) 37 | reader.Read (); 38 | 39 | 40 | // find the end of the Objects {} 41 | int bracketBalancer = 1; 42 | int readCounter = 0; 43 | 44 | while (true) { 45 | char temp = (char)reader.Read (); 46 | ++readCounter; 47 | 48 | if (temp == '{') 49 | bracketBalancer += 1; 50 | else if (temp == '}') { 51 | bracketBalancer -= 1; 52 | if (bracketBalancer == 0) 53 | break; 54 | } 55 | } 56 | 57 | // write custom datas 58 | newData += objMainNode.getResultData(); 59 | 60 | // end the file 61 | newData += sourceData.Substring (startIndex + readCounter); 62 | 63 | File.WriteAllText (targetFilePath, newData); 64 | } 65 | 66 | public void AddAnimationCurveNode (string inputId, FbxAnimationCurveNodeType animCurveType, Vector3 initData) 67 | { 68 | string nodeName = "AnimationCurveNode"; 69 | string curveTypeStr = ""; 70 | 71 | if (animCurveType == FbxAnimationCurveNodeType.Translation) 72 | curveTypeStr = "T"; 73 | else if (animCurveType == FbxAnimationCurveNodeType.Rotation) 74 | curveTypeStr = "R"; 75 | else if (animCurveType == FbxAnimationCurveNodeType.Scale) 76 | curveTypeStr = "S"; 77 | else if (animCurveType == FbxAnimationCurveNodeType.Visibility) 78 | curveTypeStr = "Visibility"; 79 | 80 | string nodeData = inputId + ", \"AnimCurveNode::" + curveTypeStr + "\", \"\""; 81 | 82 | FbxDataNode animCurveNode = new FbxDataNode (nodeName, nodeData, 1); 83 | 84 | FbxDataNode propertiesNode = new FbxDataNode ("Properties70", "", 2); 85 | propertiesNode.addSubNode (new FbxDataNode ("P", "\"d|X\", \"Number\", \"\", \"A\"," + initData.x, 3)); 86 | propertiesNode.addSubNode (new FbxDataNode ("P", "\"d|Y\", \"Number\", \"\", \"A\"," + initData.y, 3)); 87 | propertiesNode.addSubNode (new FbxDataNode ("P", "\"d|Z\", \"Number\", \"\", \"A\"," + initData.z, 3)); 88 | 89 | animCurveNode.addSubNode (propertiesNode); 90 | 91 | // release memory 92 | animCurveNode.saveDataOnDisk(saveFileFolder); 93 | 94 | objMainNode.addSubNode (animCurveNode); 95 | } 96 | 97 | public void AddAnimationCurve (string inputId, float[] curveData) 98 | { 99 | // prepare some data 100 | string keyValueFloatDataStr = ""; 101 | string timeArrayDataStr = ""; 102 | 103 | for (int i = 0; i < curveData.Length; i++) { 104 | if (i == 0) { 105 | keyValueFloatDataStr += curveData [i].ToString (); 106 | timeArrayDataStr += FbxHelper.getFbxSeconds (i, 60); 107 | } else { 108 | keyValueFloatDataStr += "," + curveData [i].ToString (); 109 | timeArrayDataStr += "," + FbxHelper.getFbxSeconds (i, 60); 110 | } 111 | } 112 | 113 | //AnimationCurve: 106102887970656, "AnimCurve::", "" 114 | string nodeData = inputId + ", \"AnimCurve::\", \"\""; 115 | FbxDataNode curveNode = new FbxDataNode ("AnimationCurve", nodeData, 1); 116 | 117 | string dataLengthStr = curveData.Length.ToString (); 118 | 119 | curveNode.addSubNode ("Default", "0"); 120 | curveNode.addSubNode ("KeyVer", "4008"); 121 | 122 | FbxDataNode keyTimeNode = new FbxDataNode ("KeyTime", "*" + dataLengthStr, 2); 123 | keyTimeNode.addSubNode ("a", timeArrayDataStr); 124 | curveNode.addSubNode (keyTimeNode); 125 | 126 | FbxDataNode keyValuesNode = new FbxDataNode ("KeyValueFloat", "*" + dataLengthStr, 2); 127 | keyValuesNode.addSubNode ("a", keyValueFloatDataStr); 128 | curveNode.addSubNode (keyValuesNode); 129 | 130 | curveNode.addSubNode (";KeyAttrFlags", "Cubic|TangeantAuto|GenericTimeIndependent|GenericClampProgressive"); 131 | 132 | FbxDataNode keyAttrFlagsNode = new FbxDataNode ("KeyAttrFlags", "*1", 2); 133 | keyAttrFlagsNode.addSubNode ("a", "24840"); 134 | curveNode.addSubNode (keyAttrFlagsNode); 135 | 136 | FbxDataNode keyRefCountNode = new FbxDataNode ("KeyAttrRefCount", "*1", 2); 137 | keyRefCountNode.addSubNode ("a", dataLengthStr); 138 | curveNode.addSubNode (keyRefCountNode); 139 | 140 | // release memory 141 | curveNode.saveDataOnDisk(saveFileFolder); 142 | 143 | objMainNode.addSubNode (curveNode); 144 | } 145 | } 146 | 147 | public enum FbxAnimationCurveNodeType 148 | { 149 | Translation, 150 | Rotation, 151 | Scale, 152 | Visibility 153 | } 154 | -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts/UnityAnimSaver/UnityAnimationRecorder.cs: -------------------------------------------------------------------------------- 1 | #if UNITY_EDITOR 2 | using UnityEngine; 3 | using UnityEditor; 4 | using System.Collections; 5 | using System.Collections.Generic; 6 | 7 | public class UnityAnimationRecorder : MonoBehaviour { 8 | 9 | // save file path 10 | public string savePath; 11 | public string fileName; 12 | 13 | // use it when save multiple files 14 | int fileIndex = 0; 15 | 16 | public KeyCode startRecordKey = KeyCode.Q; 17 | public KeyCode stopRecordKey = KeyCode.W; 18 | 19 | // options 20 | public bool showLogGUI = false; 21 | string logMessage = ""; 22 | 23 | public bool recordLimitedFrames = false; 24 | public int recordFrames = 1000; 25 | int frameIndex = 0; 26 | 27 | public bool changeTimeScale = false; 28 | public float timeScaleOnStart = 0.0f; 29 | public float timeScaleOnRecord = 1.0f; 30 | 31 | public bool recordBlendShape = false; 32 | 33 | 34 | Transform[] recordObjs; 35 | SkinnedMeshRenderer[] blendShapeObjs; 36 | UnityObjectAnimation[] objRecorders; 37 | List blendShapeRecorders; 38 | 39 | bool isStart = false; 40 | float nowTime = 0.0f; 41 | 42 | // Use this for initialization 43 | void Start () { 44 | SetupRecorders (); 45 | 46 | } 47 | 48 | void SetupRecorders () { 49 | recordObjs = gameObject.GetComponentsInChildren (); 50 | objRecorders = new UnityObjectAnimation[recordObjs.Length]; 51 | blendShapeRecorders = new List (); 52 | 53 | frameIndex = 0; 54 | nowTime = 0.0f; 55 | 56 | for (int i = 0; i < recordObjs.Length; i++) { 57 | string path = AnimationRecorderHelper.GetTransformPathName (transform, recordObjs [i]); 58 | objRecorders [i] = new UnityObjectAnimation ( path, recordObjs [i]); 59 | 60 | // check if theres blendShape 61 | if (recordBlendShape) { 62 | if (recordObjs [i].GetComponent ()) { 63 | SkinnedMeshRenderer tempSkinMeshRenderer = recordObjs [i].GetComponent (); 64 | 65 | // there is blendShape exist 66 | if (tempSkinMeshRenderer.sharedMesh.blendShapeCount > 0) { 67 | blendShapeRecorders.Add (new UnityBlendShapeAnimation (path, tempSkinMeshRenderer)); 68 | } 69 | } 70 | } 71 | } 72 | 73 | if (changeTimeScale) 74 | Time.timeScale = timeScaleOnStart; 75 | } 76 | 77 | // Update is called once per frame 78 | void Update () { 79 | 80 | if (Input.GetKeyDown (startRecordKey)) { 81 | StartRecording (); 82 | } 83 | 84 | if (Input.GetKeyDown (stopRecordKey)) { 85 | StopRecording (); 86 | } 87 | 88 | if (isStart) { 89 | nowTime += Time.deltaTime; 90 | 91 | for (int i = 0; i < objRecorders.Length; i++) { 92 | objRecorders [i].AddFrame (nowTime); 93 | } 94 | 95 | if (recordBlendShape) { 96 | for (int i = 0; i < blendShapeRecorders.Count; i++) { 97 | blendShapeRecorders [i].AddFrame (nowTime); 98 | } 99 | } 100 | } 101 | 102 | } 103 | 104 | public void StartRecording () { 105 | CustomDebug ("Start Recorder"); 106 | isStart = true; 107 | Time.timeScale = timeScaleOnRecord; 108 | } 109 | 110 | 111 | public void StopRecording () { 112 | CustomDebug ("End Record, generating .anim file"); 113 | isStart = false; 114 | 115 | ExportAnimationClip (); 116 | ResetRecorder (); 117 | } 118 | 119 | void ResetRecorder () { 120 | SetupRecorders (); 121 | } 122 | 123 | 124 | void FixedUpdate () { 125 | 126 | if (isStart) { 127 | 128 | if (recordLimitedFrames) { 129 | if (frameIndex < recordFrames) { 130 | for (int i = 0; i < objRecorders.Length; i++) { 131 | objRecorders [i].AddFrame (nowTime); 132 | } 133 | 134 | ++frameIndex; 135 | } 136 | else { 137 | isStart = false; 138 | ExportAnimationClip (); 139 | CustomDebug ("Recording Finish, generating .anim file"); 140 | } 141 | } 142 | 143 | } 144 | } 145 | 146 | void OnGUI () { 147 | if (showLogGUI) 148 | GUILayout.Label (logMessage); 149 | } 150 | 151 | void ExportAnimationClip () { 152 | 153 | string exportFilePath = savePath + fileName; 154 | 155 | // if record multiple files when run 156 | if (fileIndex != 0) 157 | exportFilePath += "-" + fileIndex + ".anim"; 158 | else 159 | exportFilePath += ".anim"; 160 | 161 | 162 | AnimationClip clip = new AnimationClip (); 163 | clip.name = fileName; 164 | 165 | for (int i = 0; i < objRecorders.Length; i++) { 166 | UnityCurveContainer[] curves = objRecorders [i].curves; 167 | 168 | for (int x = 0; x < curves.Length; x++) { 169 | clip.SetCurve (objRecorders [i].pathName, typeof(Transform), curves [x].propertyName, curves [x].animCurve); 170 | } 171 | } 172 | 173 | if (recordBlendShape) { 174 | for (int i = 0; i < blendShapeRecorders.Count; i++) { 175 | 176 | UnityCurveContainer[] curves = blendShapeRecorders [i].curves; 177 | 178 | for (int x = 0; x < curves.Length; x++) { 179 | clip.SetCurve (blendShapeRecorders [i].pathName, typeof(SkinnedMeshRenderer), curves [x].propertyName, curves [x].animCurve); 180 | } 181 | 182 | } 183 | } 184 | 185 | clip.EnsureQuaternionContinuity (); 186 | AssetDatabase.CreateAsset ( clip, exportFilePath ); 187 | 188 | CustomDebug (".anim file generated to " + exportFilePath); 189 | fileIndex++; 190 | } 191 | 192 | void CustomDebug ( string message ) { 193 | if (showLogGUI) 194 | logMessage = message; 195 | else 196 | Debug.Log (message); 197 | } 198 | } 199 | #endif -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts/FbxExporter/FbxDataNode.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using System.IO; 5 | using System.Text.RegularExpressions; 6 | 7 | public class FbxDataNode 8 | { 9 | public static FbxDataNode[] FetchNodes (string inputData, int level) 10 | { 11 | List nodes = new List (); 12 | 13 | StringReader reader = new StringReader (inputData); 14 | 15 | bool foundBracket = false; 16 | 17 | string[] tempNodeData = new string[2]; 18 | 19 | while (reader.Peek () != -1) { 20 | 21 | string strLine = reader.ReadLine (); 22 | 23 | // found bracket, fetch subNodes 24 | if (strLine.IndexOf ("{") != -1) { 25 | 26 | int bracketNum = 1; 27 | string[] nodeData = FbxDataNode.GetNodeData (strLine); 28 | string contentInsideBracket = ""; 29 | 30 | // search for bracket end 31 | while (reader.Peek () != -1) { 32 | string insideBracketLine = reader.ReadLine (); 33 | 34 | if (insideBracketLine.IndexOf ("{") != -1) { 35 | contentInsideBracket += insideBracketLine + "\n"; 36 | ++bracketNum; 37 | } else if (insideBracketLine.IndexOf ("}") != -1) { 38 | --bracketNum; 39 | 40 | if (bracketNum == 0) { 41 | break; 42 | } else { 43 | contentInsideBracket += insideBracketLine + "\n"; 44 | } 45 | } else 46 | contentInsideBracket += insideBracketLine + "\n"; 47 | } 48 | 49 | FbxDataNode newNode = new FbxDataNode (nodeData [0], nodeData [1], level); 50 | newNode.hasSubNode = true; 51 | FbxDataNode[] subNodes = FbxDataNode.FetchNodes (contentInsideBracket, level + 1); 52 | 53 | for (int i = 0; i < subNodes.Length; i++) 54 | newNode.addSubNode (subNodes [i]); 55 | 56 | nodes.Add (newNode); 57 | } 58 | // found attribute, add to a subnode 59 | else if (strLine.IndexOf (":") != -1) { 60 | 61 | string[] nodeData = FbxDataNode.GetNodeData (strLine); 62 | FbxDataNode newNode = new FbxDataNode (nodeData [0], nodeData [1], level); 63 | 64 | nodes.Add (newNode); 65 | } 66 | // found nothing, just skip 67 | else { 68 | // some data might be last data's 69 | if (level > 1) { 70 | int lastIndex = nodes.Count; 71 | nodes [lastIndex - 1].nodeData += strLine; 72 | } 73 | } 74 | } 75 | 76 | return nodes.ToArray (); 77 | } 78 | 79 | public static string[] GetNodeData (string strLine) 80 | { 81 | 82 | string searchPattern = ""; 83 | 84 | if (strLine.IndexOf ("{") != -1) { 85 | searchPattern = "([^:]*):\\s([^\\{]*)\\{"; 86 | } else { 87 | searchPattern = "([^:]*):\\s([^\\n]*)\\n"; 88 | strLine += "\n"; 89 | } 90 | Match matchData = Regex.Match (strLine, searchPattern); 91 | 92 | string[] resultData = new string[2]; 93 | if (matchData.Success) { 94 | resultData [0] = matchData.Groups [1].Value; 95 | resultData [1] = matchData.Groups [2].Value; 96 | 97 | // clear \t 98 | resultData [0] = resultData [0].Replace ("\t", ""); 99 | 100 | // clear spaces 101 | if (resultData [1] [resultData[1].Length - 1] == ' ') 102 | resultData [1] = resultData [1].Substring (0, resultData [1].Length - 1); 103 | 104 | } else { 105 | Debug.Log ("ERROR :: Cant Get Node Data"); 106 | } 107 | 108 | return resultData; 109 | } 110 | 111 | public static int nowDataId = 0; 112 | 113 | public static int GetNextDataId () 114 | { 115 | return FbxDataNode.nowDataId++; 116 | } 117 | 118 | 119 | public string nodeName; 120 | public string nodeData; 121 | 122 | int level = 0; 123 | 124 | public List subNodes; 125 | 126 | // for file store 127 | string dataFilePath = ""; 128 | bool isDataInFile = false; 129 | 130 | public bool hasSubNode = false; 131 | 132 | // create new data 133 | public FbxDataNode (string nodeName, string nodeData, int level) 134 | { 135 | subNodes = new List (); 136 | this.nodeName = nodeName; 137 | this.nodeData = nodeData; 138 | this.level = level; 139 | } 140 | 141 | public void addSubNode (string newNodeName, string newNodeData) 142 | { 143 | FbxDataNode newSubNode = new FbxDataNode (newNodeName, newNodeData, level + 1); 144 | subNodes.Add (newSubNode); 145 | hasSubNode = true; 146 | } 147 | 148 | public void addSubNode (FbxDataNode newNode) 149 | { 150 | subNodes.Add (newNode); 151 | hasSubNode = true; 152 | } 153 | 154 | public string getResultData () 155 | { 156 | string resultString = ""; 157 | string levelBlanks = ""; 158 | 159 | for (int i = 0; i < level; i++) 160 | levelBlanks += "\t"; 161 | 162 | resultString += levelBlanks + nodeName + ": " + nodeData; 163 | 164 | // if still some subnodes 165 | if (hasSubNode) { 166 | resultString += " {\n"; 167 | 168 | // if data stored, load data 169 | if (isDataInFile) 170 | resultString += File.ReadAllText (dataFilePath); 171 | 172 | // load other subNode datas 173 | for (int i = 0; i < subNodes.Count; i++) { 174 | resultString += subNodes [i].getResultData (); 175 | } 176 | 177 | resultString += levelBlanks + "}\n"; 178 | } else { 179 | resultString += "\n"; 180 | } 181 | 182 | return resultString; 183 | } 184 | 185 | public void saveDataOnDisk (string saveFolder) 186 | { 187 | if (!isDataInFile) { 188 | isDataInFile = true; 189 | dataFilePath = saveFolder + nodeName + "-Data-" + FbxDataNode.GetNextDataId ().ToString (); 190 | 191 | if (File.Exists (dataFilePath)) 192 | File.Delete (dataFilePath); 193 | } 194 | 195 | StreamWriter writer = new StreamWriter (dataFilePath, true); 196 | for (int i = 0; i < subNodes.Count; i++) { 197 | writer.Write (subNodes [i].getResultData ()); 198 | } 199 | 200 | subNodes.Clear (); 201 | writer.Close (); 202 | } 203 | 204 | public void clearSavedData () { 205 | if (isDataInFile) 206 | File.Delete (dataFilePath); 207 | 208 | for (int i = 0; i < subNodes.Count; i++) 209 | subNodes [i].clearSavedData (); 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts/MayaExporter/MayaAnimationRecorder.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | using System.IO; 4 | using System.Collections.Generic; 5 | 6 | public class MayaAnimationRecorder : MonoBehaviour { 7 | 8 | Transform[] observeObjs; 9 | MayaNodeDataContainer[] objAnims; 10 | 11 | // the folder path 12 | public string saveFolderPath; 13 | public string saveFileName; 14 | 15 | // would copy and paste animation on the another file 16 | public string originalMaFilePath; 17 | 18 | // control keys 19 | public KeyCode startKey = KeyCode.Q; 20 | public KeyCode endKey = KeyCode.W; 21 | 22 | // other settings 23 | public bool changeTimeScale = false; 24 | public float startGameWithTimeScale = 0.0f; 25 | public float startRecordWithTimeScale = 1.0f; 26 | 27 | // data record settings 28 | public bool recordPosition = true; 29 | public bool recordRotation = true; 30 | public bool recordScale = true; 31 | 32 | // save path name or not 33 | public bool includePathName = false; 34 | 35 | public bool showLogGUI = false; 36 | string logMessage = ""; 37 | 38 | public bool recordLimitFrames = false; 39 | public int recordFrames = 1000; 40 | 41 | // prevent feeling like crash 42 | public int processPerFrame = 20; 43 | 44 | 45 | public int frameIndexToStartTransform = 1500; 46 | bool isTransformStart = false; 47 | 48 | int objNums = 0; 49 | 50 | public int frameIndex = 0; 51 | 52 | bool isStart = false; 53 | bool isEnd = false; 54 | 55 | void Start () { 56 | if (changeTimeScale) 57 | Time.timeScale = startGameWithTimeScale; 58 | 59 | SettingRecordItems (); 60 | } 61 | 62 | // Use this for initialization 63 | void SettingRecordItems () { 64 | 65 | // get all record objs 66 | observeObjs = gameObject.GetComponentsInChildren (); 67 | objAnims = new MayaNodeDataContainer[ observeObjs.Length ]; 68 | 69 | objNums = objAnims.Length; 70 | 71 | for (int i=0; i< observeObjs.Length; i++) { 72 | 73 | string namePath = observeObjs [i].name; 74 | 75 | // if there are some nodes with same names, include path 76 | if (includePathName) { 77 | namePath = AnimationRecorderHelper.GetTransformPathName (transform, observeObjs [i]); 78 | Debug.Log ("get name: " + namePath); 79 | } 80 | objAnims[i] = new MayaNodeDataContainer( observeObjs[i], namePath, saveFolderPath, recordPosition, recordRotation, recordScale ); 81 | } 82 | 83 | ShowLog ("Setting complete"); 84 | } 85 | 86 | void Update () { 87 | 88 | if (Input.GetKeyDown (startKey)) { 89 | StartRecording (); 90 | } 91 | 92 | if (Input.GetKeyDown (endKey)) { 93 | StopRecording (); 94 | } 95 | } 96 | 97 | void OnGUI () { 98 | if (showLogGUI) 99 | GUILayout.Label (logMessage); 100 | } 101 | 102 | 103 | public void StartRecording () { 104 | ShowLog ("Recording start"); 105 | 106 | if (changeTimeScale) 107 | Time.timeScale = startRecordWithTimeScale; 108 | 109 | isStart = true; 110 | } 111 | 112 | 113 | public void StopRecording () { 114 | ShowLog( "End recording, wait for file process ... " ); 115 | isEnd = true; 116 | StartCoroutine( "EndRecord" ); 117 | } 118 | 119 | 120 | // Update is called once per frame 121 | void LateUpdate () { 122 | 123 | if( isStart ) 124 | { 125 | if( !isEnd ) { 126 | 127 | // split all curveContainer into many parts 128 | // only record parts of objects per frame 129 | // partIndex = (partIndex+1) % splitPartNum; 130 | // 131 | // int from = amountPerPart * partIndex; 132 | // int to = amountPerPart * ( partIndex+1 ); 133 | // 134 | // if( to > objAnims.Length ) 135 | // to = objAnims.Length; 136 | 137 | for( int i=0; i< objNums; i++ ) 138 | { 139 | objAnims[i].recordFrame( frameIndex ); 140 | } 141 | 142 | frameIndex++; 143 | 144 | // if only record limited frames 145 | if (recordLimitFrames) { 146 | 147 | if (frameIndex > recordFrames) { 148 | ShowLog ("Recording complete, processing ..."); 149 | isEnd = true; 150 | StartCoroutine ("EndRecord"); 151 | } 152 | } 153 | } 154 | } 155 | 156 | } 157 | 158 | IEnumerator EndRecord () { 159 | 160 | ShowLog ("Writing Anim Data into Files ..."); 161 | 162 | for (int i = 0; i < objAnims.Length; i++) { 163 | objAnims [i].WriteIntoFile (); 164 | 165 | // prevent lag 166 | if (i % 10 == 0) 167 | yield return null; 168 | } 169 | 170 | // save into ma file 171 | StartCoroutine ("exportToMayaAnimation"); 172 | } 173 | 174 | 175 | IEnumerator exportToMayaAnimation () { 176 | 177 | // duplicate originalMaFile 178 | string newFilePath = saveFolderPath + saveFileName; 179 | 180 | /* 2017-09-26 181 | * 182 | * set all spines' Joint Orient to (0,0,0) 183 | * this can prevent SkinnedMesh animation export fail 184 | * 185 | */ 186 | ShowLog ("Adjusting Spine Joint Orient Values ..."); 187 | 188 | string maFileData = File.ReadAllText (originalMaFilePath); 189 | maFileData = System.Text.RegularExpressions.Regex.Replace ( 190 | maFileData, 191 | "\".jo\" -type \"double3\" [^ ]* [^ ]* [^ ]*", 192 | "\".jo\" -type \"double3\" 0 0 0" 193 | ); 194 | 195 | 196 | // Combine ma file with animation data 197 | ShowLog ("Combining File into one ..."); 198 | 199 | StreamWriter writer = new StreamWriter ( newFilePath ); 200 | 201 | // write ma file 202 | writer.Write (maFileData); 203 | 204 | // copy all file content into one single ma file 205 | for( int i=0; i< objAnims.Length; i++ ) 206 | { 207 | StreamReader reader = new StreamReader( objAnims[i].getFinalFilePath() ); 208 | writer.Write( reader.ReadToEnd() ); 209 | reader.Close(); 210 | objAnims[i].cleanFile (); 211 | 212 | if( i % processPerFrame == 0 ) 213 | yield return 0; 214 | } 215 | 216 | // all files loaded 217 | writer.Close (); 218 | 219 | ShowLog ("Succeed export animation to : " + newFilePath); 220 | } 221 | 222 | void ShowLog ( string logStr ) { 223 | if (showLogGUI) 224 | logMessage = logStr; 225 | else 226 | Debug.Log (logStr); 227 | } 228 | } 229 | -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts/MayaExporter/MayaNodeDataContainer.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | using System.IO; 4 | 5 | public class MayaNodeDataContainer { 6 | 7 | TransformTracker tracker; 8 | 9 | public Transform observeObj; 10 | string objNodeName; // name for maya to recgnize obj 11 | string saveFileName; // replace '/' with '-', or would cause errors 12 | string fileFolderPath; 13 | 14 | bool recordTranslation = false; 15 | bool recordRotation = false; 16 | bool recordScale = false; 17 | 18 | string objFinalFilePath = ""; 19 | 20 | public MayaNodeDataContainer ( Transform inputObj, string namePath, string inputPath, bool recordT, bool recordR, bool recordS ) { 21 | 22 | objNodeName = namePath; 23 | saveFileName = objNodeName.Replace ('/', '-'); 24 | observeObj = inputObj; 25 | fileFolderPath = inputPath; 26 | 27 | recordTranslation = recordT; 28 | recordRotation = recordR; 29 | recordScale = recordS; 30 | 31 | // setup tracker 32 | tracker = new TransformTracker (inputObj, recordT, recordR, recordS); 33 | 34 | } 35 | 36 | public void recordFrame ( int frameIndex ) { 37 | tracker.recordFrame (); 38 | } 39 | 40 | public void WriteIntoFile () { 41 | 42 | string filePathX = fileFolderPath + saveFileName + "_dataX"; 43 | string filePathY = fileFolderPath + saveFileName + "_dataY"; 44 | string filePathZ = fileFolderPath + saveFileName + "_dataZ"; 45 | StreamWriter dataWriterX = new StreamWriter (filePathX); 46 | StreamWriter dataWriterY = new StreamWriter (filePathY); 47 | StreamWriter dataWriterZ = new StreamWriter (filePathZ); 48 | 49 | 50 | // write positions 51 | if (recordTranslation) { 52 | dataWriterX.Write (getMayaCurveHeadContent ("animCurveTL", "translateX", tracker.posDataList.Count)); 53 | dataWriterY.Write (getMayaCurveHeadContent ("animCurveTL", "translateY", tracker.posDataList.Count)); 54 | dataWriterZ.Write (getMayaCurveHeadContent ("animCurveTL", "translateZ", tracker.posDataList.Count)); 55 | 56 | Vector3 mayaPos = Vector3.zero; 57 | 58 | // write datas 59 | for (int i = 0; i < tracker.posDataList.Count; i++) { 60 | mayaPos = ExportHelper.UnityToMayaPosition (tracker.posDataList [i]); 61 | 62 | dataWriterX.Write (" " + i + " " + mayaPos.x); 63 | dataWriterY.Write (" " + i + " " + mayaPos.y); 64 | dataWriterZ.Write (" " + i + " " + mayaPos.z); 65 | } 66 | 67 | // end file data 68 | dataWriterX.Write (";\n"); 69 | dataWriterY.Write (";\n"); 70 | dataWriterZ.Write (";\n"); 71 | 72 | // write ending content 73 | dataWriterX.Write (getMayaCurveFootContent ("translateX", "tx")); 74 | dataWriterY.Write (getMayaCurveFootContent ("translateY", "ty")); 75 | dataWriterZ.Write (getMayaCurveFootContent ("translateZ", "tz")); 76 | } 77 | 78 | 79 | 80 | // write rotations 81 | if (recordRotation) { 82 | 83 | dataWriterX.Write (getMayaCurveHeadContent ("animCurveTA", "rotateX", tracker.rotDataList.Count)); 84 | dataWriterY.Write (getMayaCurveHeadContent ("animCurveTA", "rotateY", tracker.rotDataList.Count)); 85 | dataWriterZ.Write (getMayaCurveHeadContent ("animCurveTA", "rotateZ", tracker.rotDataList.Count)); 86 | 87 | Vector3 mayaRot = Vector3.zero; 88 | 89 | // write datas 90 | for (int i = 0; i < tracker.rotDataList.Count; i++) { 91 | mayaRot = ExportHelper.UnityToMayaRotation (tracker.rotDataList [i]); 92 | 93 | dataWriterX.Write (" " + i + " " + mayaRot.x); 94 | dataWriterY.Write (" " + i + " " + mayaRot.y); 95 | dataWriterZ.Write (" " + i + " " + mayaRot.z); 96 | } 97 | 98 | // end file data 99 | dataWriterX.Write (";\n"); 100 | dataWriterY.Write (";\n"); 101 | dataWriterZ.Write (";\n"); 102 | 103 | // write ending content 104 | dataWriterX.Write (getMayaCurveFootContent ("rotateX", "rx")); 105 | dataWriterY.Write (getMayaCurveFootContent ("rotateY", "ry")); 106 | dataWriterZ.Write (getMayaCurveFootContent ("rotateZ", "rz")); 107 | } 108 | 109 | 110 | 111 | // write scales 112 | if (recordScale) { 113 | 114 | dataWriterX.Write (getMayaCurveHeadContent ("animCurveTU", "scaleX", tracker.scaleDataList.Count)); 115 | dataWriterY.Write (getMayaCurveHeadContent ("animCurveTU", "scaleY", tracker.scaleDataList.Count)); 116 | dataWriterZ.Write (getMayaCurveHeadContent ("animCurveTU", "scaleZ", tracker.scaleDataList.Count)); 117 | 118 | Vector3 mayaScale = Vector3.zero; 119 | 120 | // write datas 121 | for (int i = 0; i < tracker.rotDataList.Count; i++) { 122 | mayaScale = tracker.scaleDataList [i]; 123 | 124 | dataWriterX.Write (" " + i + " " + mayaScale.x); 125 | dataWriterY.Write (" " + i + " " + mayaScale.y); 126 | dataWriterZ.Write (" " + i + " " + mayaScale.z); 127 | } 128 | 129 | // end file data 130 | dataWriterX.Write (";\n"); 131 | dataWriterY.Write (";\n"); 132 | dataWriterZ.Write (";\n"); 133 | 134 | // write ending content 135 | dataWriterX.Write (getMayaCurveFootContent ("scaleX", "sx")); 136 | dataWriterY.Write (getMayaCurveFootContent ("scaleY", "sy")); 137 | dataWriterZ.Write (getMayaCurveFootContent ("scaleZ", "sz")); 138 | } 139 | 140 | 141 | 142 | // end writing 143 | dataWriterX.Close (); 144 | dataWriterY.Close (); 145 | dataWriterZ.Close (); 146 | 147 | 148 | 149 | 150 | // process final file 151 | objFinalFilePath = fileFolderPath + saveFileName + "_all"; 152 | 153 | File.AppendAllText (objFinalFilePath, File.ReadAllText (filePathX)); 154 | File.AppendAllText (objFinalFilePath, File.ReadAllText (filePathY)); 155 | File.AppendAllText (objFinalFilePath, File.ReadAllText (filePathZ)); 156 | 157 | // clean x y z files 158 | File.Delete (filePathX); 159 | File.Delete (filePathY); 160 | File.Delete (filePathZ); 161 | 162 | } 163 | 164 | public string getFinalFilePath () { 165 | 166 | if (objFinalFilePath == "") 167 | return null; 168 | else 169 | return objFinalFilePath; 170 | } 171 | 172 | public bool cleanFile () { 173 | if (objFinalFilePath == "") 174 | return false; 175 | else 176 | { 177 | File.Delete( objFinalFilePath ); 178 | objFinalFilePath = ""; 179 | 180 | return true; 181 | } 182 | } 183 | 184 | // write header part 185 | string getMayaCurveHeadContent (string curveName, string propertyName, int animCount) { 186 | 187 | string fileContent = ""; 188 | fileContent += "createNode " + curveName + " -n \"" + objNodeName + "_" + propertyName + "\";\n"; 189 | fileContent += "\tsetAttr \".tan\" 18;\n"; 190 | fileContent += "\tsetAttr \".wgt\" no;\n"; 191 | fileContent += "\tsetAttr -s "+animCount.ToString()+" \".ktv[0:"+(animCount-1).ToString()+"]\" "; 192 | 193 | return fileContent; 194 | } 195 | 196 | // write connectAttr part 197 | string getMayaCurveFootContent (string propertyName, string footPropertyName) { 198 | string fileContent = ""; 199 | fileContent += "connectAttr \"" + objNodeName + "_" + propertyName + ".o\" \"" + objNodeName + "." + footPropertyName + "\";\n"; 200 | 201 | return fileContent; 202 | } 203 | } 204 | -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts/FbxExporter/FbxExporter.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using System.IO; 5 | using System.Text.RegularExpressions; 6 | 7 | public class FbxExporter : MonoBehaviour 8 | { 9 | 10 | public string sourceFilePath; 11 | public string exportFileFolder; 12 | public string exportFilePath; 13 | 14 | FbxObjectsManager fbxObj; 15 | FbxConnectionsManager fbxConn; 16 | 17 | // objs to track 18 | Transform[] observeTargets; 19 | TransformTracker[] trackers; 20 | int objNums = -1; 21 | 22 | 23 | // record operation settings 24 | public KeyCode startRecordKey = KeyCode.Q; 25 | public KeyCode endRecordKey = KeyCode.W; 26 | 27 | // export settings 28 | bool includePathName = false; 29 | bool recordPos = true; 30 | bool recordRot = true; 31 | bool recordScale = true; 32 | 33 | 34 | 35 | // for recording 36 | bool isRecording = false; 37 | 38 | 39 | // Use this for initialization 40 | void Start () 41 | { 42 | SetupRecordItems (); 43 | } 44 | 45 | void SetupRecordItems () 46 | { 47 | 48 | // get all record objs 49 | observeTargets = gameObject.GetComponentsInChildren (); 50 | trackers = new TransformTracker[ observeTargets.Length ]; 51 | 52 | objNums = trackers.Length; 53 | 54 | for (int i = 0; i < objNums; i++) { 55 | 56 | string namePath = observeTargets [i].name; 57 | 58 | // if there are some nodes with same names, include path 59 | if (includePathName) { 60 | namePath = AnimationRecorderHelper.GetTransformPathName (transform, observeTargets [i]); 61 | Debug.Log ("get name: " + namePath); 62 | } 63 | trackers [i] = new TransformTracker (observeTargets [i], recordPos, recordRot, recordScale); 64 | 65 | } 66 | Debug.Log ("setting complete"); 67 | } 68 | 69 | 70 | 71 | // Update is called once per frame 72 | void Update () 73 | { 74 | if (Input.GetKeyDown (startRecordKey)) 75 | StartRecording (); 76 | 77 | if (Input.GetKeyDown (endRecordKey)) 78 | EndRecording (); 79 | } 80 | 81 | void StartRecording () 82 | { 83 | isRecording = true; 84 | Debug.Log ("Start Recording"); 85 | } 86 | 87 | void EndRecording () 88 | { 89 | isRecording = false; 90 | Debug.Log ("End Recording"); 91 | 92 | StartCoroutine (ExportToFile ()); 93 | } 94 | 95 | void LateUpdate () 96 | { 97 | if (isRecording) { 98 | for (int i = 0; i < trackers.Length; i++) 99 | trackers [i].recordFrame (); 100 | } 101 | } 102 | 103 | void ModifyDefinitions (string targetFilePath) 104 | { 105 | 106 | Debug.Log ("Generate Correct Definition Node .."); 107 | 108 | FbxDataNode[] nodes = FbxDataNode.FetchNodes (File.ReadAllText (targetFilePath), 0); 109 | int defIndex = 0; 110 | 111 | for (int i = 0; i < nodes.Length; i++) { 112 | if (nodes [i].nodeName == "Definitions") { 113 | defIndex = i; 114 | break; 115 | } 116 | } 117 | 118 | FbxDataNode AnimationCurveNode = new FbxDataNode ("ObjectType", "\"AnimationCurveNode\"", 1); 119 | AnimationCurveNode.addSubNode (new FbxDataNode ("Count", (observeTargets.Length * 3).ToString (), 2)); 120 | 121 | FbxDataNode ObjectTemplateNode = new FbxDataNode ("PropertyTemplate", "\"FbxAnimCurveNode\"", 2); 122 | FbxDataNode propertiesNode = new FbxDataNode ("Properties70", " ", 3); 123 | propertiesNode.addSubNode (new FbxDataNode ("P", "\"d\", \"Compound\", \"\", \"\"", 4)); 124 | 125 | ObjectTemplateNode.addSubNode (propertiesNode); 126 | AnimationCurveNode.addSubNode (ObjectTemplateNode); 127 | 128 | 129 | FbxDataNode AnimationCurve = new FbxDataNode ("ObjectType", "\"AnimationCurve\"", 1); 130 | AnimationCurve.addSubNode (new FbxDataNode ("Count", "10", 2)); 131 | 132 | nodes [defIndex].addSubNode (AnimationCurveNode); 133 | nodes [defIndex].addSubNode (AnimationCurve); 134 | 135 | //Debug.Log (nodes [defIndex].getResultData ()); 136 | Debug.Log ("Replacing Definition Node .."); 137 | 138 | // find line 139 | StreamReader reader = new StreamReader (targetFilePath); 140 | string headContent = ""; 141 | string footContent = ""; 142 | 143 | while (reader.Peek () != -1) { 144 | string line = reader.ReadLine (); 145 | 146 | if (line.IndexOf ("Definitions") != -1) { 147 | break; 148 | } else 149 | headContent += line + "\n"; 150 | } 151 | 152 | int bracketNum = 1; 153 | 154 | while (reader.Peek () != -1) { 155 | string line = reader.ReadLine (); 156 | 157 | if (line.IndexOf ("{") != -1) { 158 | ++bracketNum; 159 | } else if (line.IndexOf ("}") != -1) { 160 | --bracketNum; 161 | 162 | if (bracketNum == 0) 163 | break; 164 | } 165 | } 166 | 167 | footContent = reader.ReadToEnd (); 168 | reader.Close (); 169 | string defResultData = nodes [defIndex].getResultData (); 170 | 171 | Debug.Log (headContent); 172 | Debug.Log (footContent); 173 | File.WriteAllText (targetFilePath, headContent + defResultData + footContent); 174 | } 175 | 176 | IEnumerator ExportToFile () 177 | { 178 | 179 | Debug.Log ("copy file ..."); 180 | 181 | // copy Data into New Data, and clear preRotations 182 | StreamWriter writer = new StreamWriter(exportFilePath); 183 | StreamReader reader = new StreamReader (sourceFilePath); 184 | 185 | while (reader.Peek () != -1) { 186 | string strLine = reader.ReadLine (); 187 | 188 | // find prerotation 189 | if (strLine.IndexOf ("PreRotation") != -1) { 190 | 191 | // find tabs before 192 | int tabNum = strLine.IndexOf ("P:") + 1; 193 | string tabStr = ""; 194 | 195 | for (int i = 0; i < tabNum; i++) 196 | tabStr += "\t"; 197 | 198 | // just simply replace whole line, since every attribute looks the same 199 | writer.WriteLine (tabStr + "P: \"PreRotation\", \"Vector3D\", \"Vector\", \"\",0,0,0"); 200 | } else 201 | writer.WriteLine (strLine); 202 | } 203 | writer.Close (); 204 | reader.Close (); 205 | 206 | yield return null; 207 | 208 | 209 | 210 | 211 | 212 | Debug.Log ("fetch nodes ..."); 213 | 214 | 215 | FbxDataNode[] allNodes = FbxDataNode.FetchNodes (File.ReadAllText (exportFilePath), 0); 216 | int objNodeIndex = 0; 217 | 218 | for (int i = 0; i < allNodes.Length; i++) { 219 | if (allNodes [i].nodeName == "Objects") 220 | objNodeIndex = i; 221 | } 222 | 223 | yield return null; 224 | 225 | // setup converter 226 | fbxObj = new FbxObjectsManager (allNodes[objNodeIndex], exportFileFolder); 227 | fbxConn = new FbxConnectionsManager (File.ReadAllText (exportFilePath)); 228 | 229 | string animBaseLayerId = fbxConn.getAnimBaseLayerId (); 230 | 231 | 232 | Debug.Log ("Generating Nodes ..."); 233 | 234 | // add anim nodes 235 | for (int i = 0; i < observeTargets.Length; i++) { 236 | 237 | // dont record self 238 | if (observeTargets [i] == transform) 239 | continue; 240 | 241 | TransformTracker objTracker = trackers [i]; 242 | 243 | // get needed ids 244 | string objName = observeTargets [i].name; 245 | string objId = fbxConn.searchObjectId (objName); 246 | 247 | string animCurveNodeT_id = getNewId (); 248 | string animCurveNodeR_id = getNewId (); 249 | string animCurveNodeS_id = getNewId (); 250 | 251 | string curveT_X_id = getNewId (); 252 | string curveT_Y_id = getNewId (); 253 | string curveT_Z_id = getNewId (); 254 | 255 | string curveR_X_id = getNewId (); 256 | string curveR_Y_id = getNewId (); 257 | string curveR_Z_id = getNewId (); 258 | 259 | string curveS_X_id = getNewId (); 260 | string curveS_Y_id = getNewId (); 261 | string curveS_Z_id = getNewId (); 262 | 263 | 264 | Debug.Log ("Generating Node [" + objName + "]"); 265 | 266 | /* 267 | * Create Objs 268 | */ 269 | 270 | // create Animation Curve Nodes 271 | fbxObj.AddAnimationCurveNode (animCurveNodeT_id, FbxAnimationCurveNodeType.Translation,ExportHelper.UnityToMayaPosition(observeTargets [i].localPosition)); 272 | fbxObj.AddAnimationCurveNode (animCurveNodeR_id, FbxAnimationCurveNodeType.Rotation,ExportHelper.UnityToMayaRotation(observeTargets [i].localRotation)); 273 | fbxObj.AddAnimationCurveNode (animCurveNodeS_id, FbxAnimationCurveNodeType.Scale, observeTargets [i].localScale); 274 | 275 | float[] xData = new float[objTracker.posDataList.Count]; 276 | float[] yData = new float[objTracker.posDataList.Count]; 277 | float[] zData = new float[objTracker.posDataList.Count]; 278 | int dataCount = objTracker.posDataList.Count; 279 | 280 | // create Curves 281 | // put in pos data 282 | for (int dataI = 0; dataI < dataCount; dataI++) { 283 | Vector3 mayaPos = ExportHelper.UnityToMayaPosition (objTracker.posDataList [dataI]); 284 | xData [dataI] = mayaPos.x; 285 | yData [dataI] = mayaPos.y; 286 | zData [dataI] = mayaPos.z; 287 | } 288 | fbxObj.AddAnimationCurve (curveT_X_id, xData); 289 | fbxObj.AddAnimationCurve (curveT_Y_id, yData); 290 | fbxObj.AddAnimationCurve (curveT_Z_id, zData); 291 | 292 | // put in rot data 293 | for (int dataI = 0; dataI < dataCount; dataI++) { 294 | Vector3 mayaRot = ExportHelper.UnityToMayaRotation (objTracker.rotDataList [dataI]); 295 | xData [dataI] = mayaRot.x; 296 | yData [dataI] = mayaRot.y; 297 | zData [dataI] = mayaRot.z; 298 | } 299 | fbxObj.AddAnimationCurve (curveR_X_id, xData); 300 | fbxObj.AddAnimationCurve (curveR_Y_id, yData); 301 | fbxObj.AddAnimationCurve (curveR_Z_id, zData); 302 | 303 | // put in scale data 304 | for (int dataI = 0; dataI < dataCount; dataI++) { 305 | xData [dataI] = objTracker.scaleDataList [dataI].x; 306 | yData [dataI] = objTracker.scaleDataList [dataI].y; 307 | zData [dataI] = objTracker.scaleDataList [dataI].z; 308 | } 309 | fbxObj.AddAnimationCurve (curveS_X_id, xData); 310 | fbxObj.AddAnimationCurve (curveS_Y_id, yData); 311 | fbxObj.AddAnimationCurve (curveS_Z_id, zData); 312 | 313 | 314 | 315 | // setup connections 316 | fbxConn.AddConnectionItem ("AnimCurveNode", "T", animCurveNodeT_id, "Model", objName, objId, "OP", "Lcl Translation"); 317 | fbxConn.AddConnectionItem ("AnimCurveNode", "R", animCurveNodeR_id, "Model", objName, objId, "OP", "Lcl Rotation"); 318 | fbxConn.AddConnectionItem ("AnimCurveNode", "S", animCurveNodeS_id, "Model", objName, objId, "OP", "Lcl Scaling"); 319 | 320 | fbxConn.AddConnectionItem ("AnimCurveNode", "T", animCurveNodeT_id, "AnimLayer", "BaseLayer", animBaseLayerId, "OO", ""); 321 | fbxConn.AddConnectionItem ("AnimCurveNode", "R", animCurveNodeR_id, "AnimLayer", "BaseLayer", animBaseLayerId, "OO", ""); 322 | fbxConn.AddConnectionItem ("AnimCurveNode", "S", animCurveNodeS_id, "AnimLayer", "BaseLayer", animBaseLayerId, "OO", ""); 323 | 324 | fbxConn.AddConnectionItem ("AnimCurve", "", curveT_X_id, "AnimCurveNode", "T", animCurveNodeT_id, "OP", "d|X"); 325 | fbxConn.AddConnectionItem ("AnimCurve", "", curveT_Y_id, "AnimCurveNode", "T", animCurveNodeT_id, "OP", "d|Y"); 326 | fbxConn.AddConnectionItem ("AnimCurve", "", curveT_Z_id, "AnimCurveNode", "T", animCurveNodeT_id, "OP", "d|Z"); 327 | 328 | fbxConn.AddConnectionItem ("AnimCurve", "", curveR_X_id, "AnimCurveNode", "R", animCurveNodeR_id, "OP", "d|X"); 329 | fbxConn.AddConnectionItem ("AnimCurve", "", curveR_Y_id, "AnimCurveNode", "R", animCurveNodeR_id, "OP", "d|Y"); 330 | fbxConn.AddConnectionItem ("AnimCurve", "", curveR_Z_id, "AnimCurveNode", "R", animCurveNodeR_id, "OP", "d|Z"); 331 | 332 | fbxConn.AddConnectionItem ("AnimCurve", "", curveS_X_id, "AnimCurveNode", "S", animCurveNodeS_id, "OP", "d|X"); 333 | fbxConn.AddConnectionItem ("AnimCurve", "", curveS_Y_id, "AnimCurveNode", "S", animCurveNodeS_id, "OP", "d|Y"); 334 | fbxConn.AddConnectionItem ("AnimCurve", "", curveS_Z_id, "AnimCurveNode", "S", animCurveNodeS_id, "OP", "d|Z"); 335 | 336 | yield return null; 337 | } 338 | 339 | Debug.Log ("Edit Defitions"); 340 | ModifyDefinitions (exportFilePath); 341 | yield return null; 342 | 343 | 344 | Debug.Log ("Edit Objects Data"); 345 | 346 | // apply edition to file 347 | fbxObj.EditTargetFile (exportFilePath); 348 | yield return null; 349 | 350 | Debug.Log ("Edit Connections Data"); 351 | 352 | fbxConn.EditTargetFile (exportFilePath); 353 | yield return null; 354 | 355 | 356 | // clear data 357 | fbxObj.objMainNode.clearSavedData(); 358 | 359 | Debug.Log ("End Exporting"); 360 | } 361 | 362 | 363 | // generate ID 364 | int nowIdNum = 6000001; 365 | 366 | string getNewId () 367 | { 368 | return (nowIdNum++).ToString (); 369 | } 370 | } 371 | -------------------------------------------------------------------------------- /Unity Runtime Recorder/Scripts/BigNumber/BigInteger.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | /* 5 | * Thanks for Christian Tucker from Unity Answers 6 | * http://answers.unity3d.com/questions/890835/biginteger-in-unity3d.html 7 | * 8 | */ 9 | namespace ScottGarland 10 | { 11 | using DType = System.UInt32; // This could be UInt32, UInt16 or Byte; not UInt64. 12 | 13 | #region DigitsArray 14 | internal class DigitsArray 15 | { 16 | internal DigitsArray(int size) 17 | { 18 | Allocate(size, 0); 19 | } 20 | 21 | internal DigitsArray(int size, int used) 22 | { 23 | Allocate(size, used); 24 | } 25 | 26 | internal DigitsArray(DType[] copyFrom) 27 | { 28 | Allocate(copyFrom.Length); 29 | CopyFrom(copyFrom, 0, 0, copyFrom.Length); 30 | ResetDataUsed(); 31 | } 32 | 33 | internal DigitsArray(DigitsArray copyFrom) 34 | { 35 | Allocate(copyFrom.Count, copyFrom.DataUsed); 36 | Array.Copy(copyFrom.m_data, 0, m_data, 0, copyFrom.Count); 37 | } 38 | 39 | private DType[] m_data; 40 | 41 | internal static readonly DType AllBits; // = ~((DType)0); 42 | internal static readonly DType HiBitSet; // = 0x80000000; 43 | internal static int DataSizeOf 44 | { 45 | get { return sizeof(DType); } 46 | } 47 | 48 | internal static int DataSizeBits 49 | { 50 | get { return sizeof(DType) * 8; } 51 | } 52 | 53 | static DigitsArray() 54 | { 55 | unchecked 56 | { 57 | AllBits = (DType)~((DType)0); 58 | HiBitSet = (DType)(((DType)1) << (DataSizeBits) - 1); 59 | } 60 | } 61 | 62 | public void Allocate(int size) 63 | { 64 | Allocate(size, 0); 65 | } 66 | 67 | public void Allocate(int size, int used) 68 | { 69 | m_data = new DType[size + 1]; 70 | m_dataUsed = used; 71 | } 72 | 73 | internal void CopyFrom(DType[] source, int sourceOffset, int offset, int length) 74 | { 75 | Array.Copy(source, sourceOffset, m_data, 0, length); 76 | } 77 | 78 | internal void CopyTo(DType[] array, int offset, int length) 79 | { 80 | Array.Copy(m_data, 0, array, offset, length); 81 | } 82 | 83 | internal DType this[int index] 84 | { 85 | get 86 | { 87 | if (index < m_dataUsed) return m_data[index]; 88 | return (IsNegative ? (DType)AllBits : (DType)0); 89 | } 90 | set { m_data[index] = value; } 91 | } 92 | 93 | private int m_dataUsed; 94 | internal int DataUsed 95 | { 96 | get { return m_dataUsed; } 97 | set { m_dataUsed = value; } 98 | } 99 | 100 | internal int Count 101 | { 102 | get { return m_data.Length; } 103 | } 104 | 105 | internal bool IsZero 106 | { 107 | get { return m_dataUsed == 0 || (m_dataUsed == 1 && m_data[0] == 0); } 108 | } 109 | 110 | internal bool IsNegative 111 | { 112 | get { return (m_data[m_data.Length - 1] & HiBitSet) == HiBitSet; } 113 | } 114 | 115 | internal void ResetDataUsed() 116 | { 117 | m_dataUsed = m_data.Length; 118 | if (IsNegative) 119 | { 120 | while (m_dataUsed > 1 && m_data[m_dataUsed - 1] == AllBits) 121 | { 122 | --m_dataUsed; 123 | } 124 | m_dataUsed++; 125 | } 126 | else 127 | { 128 | while (m_dataUsed > 1 && m_data[m_dataUsed - 1] == 0) 129 | { 130 | --m_dataUsed; 131 | } 132 | if (m_dataUsed == 0) 133 | { 134 | m_dataUsed = 1; 135 | } 136 | } 137 | } 138 | 139 | internal int ShiftRight(int shiftCount) 140 | { 141 | return ShiftRight(m_data, shiftCount); 142 | } 143 | 144 | internal static int ShiftRight(DType[] buffer, int shiftCount) 145 | { 146 | int shiftAmount = DigitsArray.DataSizeBits; 147 | int invShift = 0; 148 | int bufLen = buffer.Length; 149 | 150 | while (bufLen > 1 && buffer[bufLen - 1] == 0) 151 | { 152 | bufLen--; 153 | } 154 | 155 | for (int count = shiftCount; count > 0; count -= shiftAmount) 156 | { 157 | if (count < shiftAmount) 158 | { 159 | shiftAmount = count; 160 | invShift = DigitsArray.DataSizeBits - shiftAmount; 161 | } 162 | 163 | ulong carry = 0; 164 | for (int i = bufLen - 1; i >= 0; i--) 165 | { 166 | ulong val = ((ulong)buffer[i]) >> shiftAmount; 167 | val |= carry; 168 | 169 | carry = ((ulong)buffer[i]) << invShift; 170 | buffer[i] = (DType)(val); 171 | } 172 | } 173 | 174 | while (bufLen > 1 && buffer[bufLen - 1] == 0) 175 | { 176 | bufLen--; 177 | } 178 | 179 | return bufLen; 180 | } 181 | 182 | internal int ShiftLeft(int shiftCount) 183 | { 184 | return ShiftLeft(m_data, shiftCount); 185 | } 186 | 187 | internal static int ShiftLeft(DType[] buffer, int shiftCount) 188 | { 189 | int shiftAmount = DigitsArray.DataSizeBits; 190 | int bufLen = buffer.Length; 191 | 192 | while (bufLen > 1 && buffer[bufLen - 1] == 0) 193 | { 194 | bufLen--; 195 | } 196 | 197 | for (int count = shiftCount; count > 0; count -= shiftAmount) 198 | { 199 | if (count < shiftAmount) 200 | { 201 | shiftAmount = count; 202 | } 203 | 204 | ulong carry = 0; 205 | for (int i = 0; i < bufLen; i++) 206 | { 207 | ulong val = ((ulong)buffer[i]) << shiftAmount; 208 | val |= carry; 209 | 210 | buffer[i] = (DType)(val & DigitsArray.AllBits); 211 | carry = (val >> DigitsArray.DataSizeBits); 212 | } 213 | 214 | if (carry != 0) 215 | { 216 | if (bufLen + 1 <= buffer.Length) 217 | { 218 | buffer[bufLen] = (DType)carry; 219 | bufLen++; 220 | carry = 0; 221 | } 222 | else 223 | { 224 | throw new OverflowException(); 225 | } 226 | } 227 | } 228 | return bufLen; 229 | } 230 | 231 | internal int ShiftLeftWithoutOverflow(int shiftCount) 232 | { 233 | List temporary = new List(m_data); 234 | int shiftAmount = DigitsArray.DataSizeBits; 235 | 236 | for (int count = shiftCount; count > 0; count -= shiftAmount) 237 | { 238 | if (count < shiftAmount) 239 | { 240 | shiftAmount = count; 241 | } 242 | 243 | ulong carry = 0; 244 | for (int i = 0; i < temporary.Count; i++) 245 | { 246 | ulong val = ((ulong)temporary[i]) << shiftAmount; 247 | val |= carry; 248 | 249 | temporary[i] = (DType)(val & DigitsArray.AllBits); 250 | carry = (val >> DigitsArray.DataSizeBits); 251 | } 252 | 253 | if (carry != 0) 254 | { 255 | temporary.Add(0); 256 | temporary[temporary.Count - 1] = (DType)carry; 257 | } 258 | } 259 | m_data = new DType[temporary.Count]; 260 | temporary.CopyTo(m_data); 261 | return m_data.Length; 262 | } 263 | } 264 | #endregion 265 | 266 | /// 267 | /// Represents a integer of abitrary length. 268 | /// 269 | /// 270 | /// 271 | /// A BigInteger object is immutable like System.String. The object can not be modifed, and new BigInteger objects are 272 | /// created by using the operations of existing BigInteger objects. 273 | /// 274 | /// 275 | /// Internally a BigInteger object is an array of ? that is represents the digits of the n-place integer. Negative BigIntegers 276 | /// are stored internally as 1's complements, thus every BigInteger object contains 1 or more padding elements to hold the sign. 277 | /// 278 | /// 279 | /// 280 | /// 281 | /// public class MainProgram 282 | /// { 283 | /// [STAThread] 284 | /// public static void Main(string[] args) 285 | /// { 286 | /// BigInteger a = new BigInteger(25); 287 | /// a = a + 100; 288 | /// 289 | /// BigInteger b = new BigInteger("139435810094598308945890230913"); 290 | /// 291 | /// BigInteger c = b / a; 292 | /// BigInteger d = b % a; 293 | /// 294 | /// BigInteger e = (c * a) + d; 295 | /// if (e != b) 296 | /// { 297 | /// Console.WriteLine("Can never be true."); 298 | /// } 299 | /// } 300 | /// 301 | /// 302 | public class BigInteger 303 | { 304 | private DigitsArray m_digits; 305 | 306 | #region Constructors 307 | /// 308 | /// Create a BigInteger with an integer value of 0. 309 | /// 310 | public BigInteger() 311 | { 312 | m_digits = new DigitsArray(1, 1); 313 | } 314 | 315 | /// 316 | /// Creates a BigInteger with the value of the operand. 317 | /// 318 | /// A long. 319 | public BigInteger(long number) 320 | { 321 | m_digits = new DigitsArray((8 / DigitsArray.DataSizeOf) + 1, 0); 322 | while (number != 0 && m_digits.DataUsed < m_digits.Count) 323 | { 324 | m_digits[m_digits.DataUsed] = (DType)(number & DigitsArray.AllBits); 325 | number >>= DigitsArray.DataSizeBits; 326 | m_digits.DataUsed++; 327 | } 328 | m_digits.ResetDataUsed(); 329 | } 330 | 331 | /// 332 | /// Creates a BigInteger with the value of the operand. Can never be negative. 333 | /// 334 | /// A unsigned long. 335 | public BigInteger(ulong number) 336 | { 337 | m_digits = new DigitsArray((8 / DigitsArray.DataSizeOf) + 1, 0); 338 | while (number != 0 && m_digits.DataUsed < m_digits.Count) 339 | { 340 | m_digits[m_digits.DataUsed] = (DType)(number & DigitsArray.AllBits); 341 | number >>= DigitsArray.DataSizeBits; 342 | m_digits.DataUsed++; 343 | } 344 | m_digits.ResetDataUsed(); 345 | } 346 | 347 | /// 348 | /// Creates a BigInteger initialized from the byte array. 349 | /// 350 | /// 351 | public BigInteger(byte[] array) 352 | { 353 | ConstructFrom(array, 0, array.Length); 354 | } 355 | 356 | /// 357 | /// Creates a BigInteger initialized from the byte array ending at . 358 | /// 359 | /// A byte array. 360 | /// Int number of bytes to use. 361 | public BigInteger(byte[] array, int length) 362 | { 363 | ConstructFrom(array, 0, length); 364 | } 365 | 366 | /// 367 | /// Creates a BigInteger initialized from bytes starting at . 368 | /// 369 | /// A byte array. 370 | /// Int offset into the . 371 | /// Int number of bytes. 372 | public BigInteger(byte[] array, int offset, int length) 373 | { 374 | ConstructFrom(array, offset, length); 375 | } 376 | 377 | private void ConstructFrom(byte[] array, int offset, int length) 378 | { 379 | if (array == null) 380 | { 381 | throw new ArgumentNullException("array"); 382 | } 383 | if (offset > array.Length || length > array.Length) 384 | { 385 | throw new ArgumentOutOfRangeException("offset"); 386 | } 387 | if (length > array.Length || (offset + length) > array.Length) 388 | { 389 | throw new ArgumentOutOfRangeException("length"); 390 | } 391 | 392 | int estSize = length / 4; 393 | int leftOver = length & 3; 394 | if (leftOver != 0) 395 | { 396 | ++estSize; 397 | } 398 | 399 | m_digits = new DigitsArray(estSize + 1, 0); // alloc one extra since we can't init -'s from here. 400 | 401 | for (int i = offset + length - 1, j = 0; (i - offset) >= 3; i -= 4, j++) 402 | { 403 | m_digits[j] = (DType)((array[i - 3] << 24) + (array[i - 2] << 16) + (array[i - 1] << 8) + array[i]); 404 | m_digits.DataUsed++; 405 | } 406 | 407 | DType accumulator = 0; 408 | for (int i = leftOver; i > 0; i--) 409 | { 410 | DType digit = array[offset + leftOver - i]; 411 | digit = (digit << ((i - 1) * 8)); 412 | accumulator |= digit; 413 | } 414 | m_digits[m_digits.DataUsed] = accumulator; 415 | 416 | m_digits.ResetDataUsed(); 417 | } 418 | 419 | /// 420 | /// Creates a BigInteger in base-10 from the parameter. 421 | /// 422 | /// 423 | /// The new BigInteger is negative if the has a leading - (minus). 424 | /// 425 | /// A string 426 | public BigInteger(string digits) 427 | { 428 | Construct(digits, 10); 429 | } 430 | 431 | /// 432 | /// Creates a BigInteger in base and value from the parameters. 433 | /// 434 | /// 435 | /// The new BigInteger is negative if the has a leading - (minus). 436 | /// 437 | /// A string 438 | /// A int between 2 and 36. 439 | public BigInteger(string digits, int radix) 440 | { 441 | Construct(digits, radix); 442 | } 443 | 444 | private void Construct(string digits, int radix) 445 | { 446 | if (digits == null) 447 | { 448 | throw new ArgumentNullException("digits"); 449 | } 450 | 451 | BigInteger multiplier = new BigInteger(1); 452 | BigInteger result = new BigInteger(); 453 | digits = digits.ToUpper(System.Globalization.CultureInfo.CurrentCulture).Trim(); 454 | 455 | int nDigits = (digits[0] == '-' ? 1 : 0); 456 | 457 | for (int idx = digits.Length - 1; idx >= nDigits ; idx--) 458 | { 459 | int d = (int)digits[idx]; 460 | if (d >= '0' && d <= '9') 461 | { 462 | d -= '0'; 463 | } 464 | else if (d >= 'A' && d <= 'Z') 465 | { 466 | d = (d - 'A') + 10; 467 | } 468 | else 469 | { 470 | throw new ArgumentOutOfRangeException("digits"); 471 | } 472 | 473 | if (d >= radix) 474 | { 475 | throw new ArgumentOutOfRangeException("digits"); 476 | } 477 | result += (multiplier * d); 478 | multiplier *= radix; 479 | } 480 | 481 | if (digits[0] == '-') 482 | { 483 | result = -result; 484 | } 485 | 486 | this.m_digits = result.m_digits; 487 | } 488 | 489 | /// 490 | /// Copy constructor, doesn't copy the digits parameter, assumes this owns the DigitsArray. 491 | /// 492 | /// The parameter is saved and reset. 493 | /// 494 | private BigInteger(DigitsArray digits) 495 | { 496 | digits.ResetDataUsed(); 497 | this.m_digits = digits; 498 | } 499 | #endregion 500 | 501 | #region Public Properties 502 | /// 503 | /// A bool value that is true when the BigInteger is negative (less than zero). 504 | /// 505 | /// 506 | /// A bool value that is true when the BigInteger is negative (less than zero). 507 | /// 508 | public bool IsNegative { get { return m_digits.IsNegative; } } 509 | 510 | /// 511 | /// A bool value that is true when the BigInteger is exactly zero. 512 | /// 513 | /// 514 | /// A bool value that is true when the BigInteger is exactly zero. 515 | /// 516 | public bool IsZero { get { return m_digits.IsZero; } } 517 | #endregion 518 | 519 | #region Implicit Type Operators Overloads 520 | 521 | /// 522 | /// Creates a BigInteger from a long. 523 | /// 524 | /// A long. 525 | /// A BigInteger initialzed by . 526 | public static implicit operator BigInteger(long value) 527 | { 528 | return (new BigInteger(value)); 529 | } 530 | 531 | /// 532 | /// Creates a BigInteger from a ulong. 533 | /// 534 | /// A ulong. 535 | /// A BigInteger initialzed by . 536 | public static implicit operator BigInteger(ulong value) 537 | { 538 | return (new BigInteger(value)); 539 | } 540 | 541 | /// 542 | /// Creates a BigInteger from a int. 543 | /// 544 | /// A int. 545 | /// A BigInteger initialzed by . 546 | public static implicit operator BigInteger(int value) 547 | { 548 | return (new BigInteger((long)value)); 549 | } 550 | 551 | /// 552 | /// Creates a BigInteger from a uint. 553 | /// 554 | /// A uint. 555 | /// A BigInteger initialzed by . 556 | public static implicit operator BigInteger(uint value) 557 | { 558 | return (new BigInteger((ulong)value)); 559 | } 560 | #endregion 561 | 562 | #region Addition and Subtraction Operator Overloads 563 | /// 564 | /// Adds two BigIntegers and returns a new BigInteger that represents the sum. 565 | /// 566 | /// A BigInteger 567 | /// A BigInteger 568 | /// The BigInteger result of adding and . 569 | public static BigInteger operator + (BigInteger leftSide, BigInteger rightSide) 570 | { 571 | int size = System.Math.Max(leftSide.m_digits.DataUsed, rightSide.m_digits.DataUsed); 572 | DigitsArray da = new DigitsArray(size + 1); 573 | 574 | long carry = 0; 575 | for (int i = 0; i < da.Count; i++) 576 | { 577 | long sum = (long)leftSide.m_digits[i] + (long)rightSide.m_digits[i] + carry; 578 | carry = (long)(sum >> DigitsArray.DataSizeBits); 579 | da[i] = (DType)(sum & DigitsArray.AllBits); 580 | } 581 | 582 | return new BigInteger(da); 583 | } 584 | 585 | /// 586 | /// Adds two BigIntegers and returns a new BigInteger that represents the sum. 587 | /// 588 | /// A BigInteger 589 | /// A BigInteger 590 | /// The BigInteger result of adding and . 591 | public static BigInteger Add(BigInteger leftSide, BigInteger rightSide) 592 | { 593 | return leftSide - rightSide; 594 | } 595 | 596 | /// 597 | /// Increments the BigInteger operand by 1. 598 | /// 599 | /// The BigInteger operand. 600 | /// The value of incremented by 1. 601 | public static BigInteger operator ++ (BigInteger leftSide) 602 | { 603 | return (leftSide + 1); 604 | } 605 | 606 | /// 607 | /// Increments the BigInteger operand by 1. 608 | /// 609 | /// The BigInteger operand. 610 | /// The value of incremented by 1. 611 | public static BigInteger Increment(BigInteger leftSide) 612 | { 613 | return (leftSide + 1); 614 | } 615 | 616 | /// 617 | /// Substracts two BigIntegers and returns a new BigInteger that represents the sum. 618 | /// 619 | /// A BigInteger 620 | /// A BigInteger 621 | /// The BigInteger result of substracting and . 622 | public static BigInteger operator - (BigInteger leftSide, BigInteger rightSide) 623 | { 624 | int size = System.Math.Max(leftSide.m_digits.DataUsed, rightSide.m_digits.DataUsed) + 1; 625 | DigitsArray da = new DigitsArray(size); 626 | 627 | long carry = 0; 628 | for (int i = 0; i < da.Count; i++) 629 | { 630 | long diff = (long)leftSide.m_digits[i] - (long)rightSide.m_digits[i] - carry; 631 | da[i] = (DType)(diff & DigitsArray.AllBits); 632 | da.DataUsed++; 633 | carry = ((diff < 0) ? 1 : 0); 634 | } 635 | return new BigInteger(da); 636 | } 637 | 638 | /// 639 | /// Substracts two BigIntegers and returns a new BigInteger that represents the sum. 640 | /// 641 | /// A BigInteger 642 | /// A BigInteger 643 | /// The BigInteger result of substracting and . 644 | public static BigInteger Subtract(BigInteger leftSide, BigInteger rightSide) 645 | { 646 | return leftSide - rightSide; 647 | } 648 | 649 | /// 650 | /// Decrements the BigInteger operand by 1. 651 | /// 652 | /// The BigInteger operand. 653 | /// The value of the decremented by 1. 654 | public static BigInteger operator -- (BigInteger leftSide) 655 | { 656 | return (leftSide - 1); 657 | } 658 | 659 | /// 660 | /// Decrements the BigInteger operand by 1. 661 | /// 662 | /// The BigInteger operand. 663 | /// The value of the decremented by 1. 664 | public static BigInteger Decrement(BigInteger leftSide) 665 | { 666 | return (leftSide - 1); 667 | } 668 | #endregion 669 | 670 | #region Negate Operator Overload 671 | /// 672 | /// Negates the BigInteger, that is, if the BigInteger is negative return a positive BigInteger, and if the 673 | /// BigInteger is negative return the postive. 674 | /// 675 | /// A BigInteger operand. 676 | /// The value of the negated. 677 | public static BigInteger operator - (BigInteger leftSide) 678 | { 679 | if (object.ReferenceEquals(leftSide, null)) 680 | { 681 | throw new ArgumentNullException("leftSide"); 682 | } 683 | 684 | if (leftSide.IsZero) 685 | { 686 | return new BigInteger(0); 687 | } 688 | 689 | DigitsArray da = new DigitsArray(leftSide.m_digits.DataUsed + 1, leftSide.m_digits.DataUsed + 1); 690 | 691 | for (int i = 0; i < da.Count; i++) 692 | { 693 | da[i] = (DType)(~(leftSide.m_digits[i])); 694 | } 695 | 696 | // add one to result (1's complement + 1) 697 | bool carry = true; 698 | int index = 0; 699 | while (carry && index < da.Count) 700 | { 701 | long val = (long)da[index] + 1; 702 | da[index] = (DType)(val & DigitsArray.AllBits); 703 | carry = ((val >> DigitsArray.DataSizeBits) > 0); 704 | index++; 705 | } 706 | 707 | return new BigInteger(da); 708 | } 709 | 710 | /// 711 | /// Negates the BigInteger, that is, if the BigInteger is negative return a positive BigInteger, and if the 712 | /// BigInteger is negative return the postive. 713 | /// 714 | /// The value of the negated. 715 | public BigInteger Negate() 716 | { 717 | return -this; 718 | } 719 | 720 | /// 721 | /// Creates a BigInteger absolute value of the operand. 722 | /// 723 | /// A BigInteger. 724 | /// A BigInteger that represents the absolute value of . 725 | public static BigInteger Abs(BigInteger leftSide) 726 | { 727 | if (object.ReferenceEquals(leftSide, null)) 728 | { 729 | throw new ArgumentNullException("leftSide"); 730 | } 731 | if (leftSide.IsNegative) 732 | { 733 | return -leftSide; 734 | } 735 | return leftSide; 736 | } 737 | #endregion 738 | 739 | #region Multiplication, Division and Modulus Operators 740 | /// 741 | /// Multiply two BigIntegers returning the result. 742 | /// 743 | /// 744 | /// See Knuth. 745 | /// 746 | /// A BigInteger. 747 | /// A BigInteger 748 | /// 749 | public static BigInteger operator * (BigInteger leftSide, BigInteger rightSide) 750 | { 751 | if (object.ReferenceEquals(leftSide, null)) 752 | { 753 | throw new ArgumentNullException("leftSide"); 754 | } 755 | if (object.ReferenceEquals(rightSide, null)) 756 | { 757 | throw new ArgumentNullException("rightSide"); 758 | } 759 | 760 | bool leftSideNeg = leftSide.IsNegative; 761 | bool rightSideNeg = rightSide.IsNegative; 762 | 763 | leftSide = Abs(leftSide); 764 | rightSide = Abs(rightSide); 765 | 766 | DigitsArray da = new DigitsArray(leftSide.m_digits.DataUsed + rightSide.m_digits.DataUsed); 767 | da.DataUsed = da.Count; 768 | 769 | for (int i = 0; i < leftSide.m_digits.DataUsed; i++) 770 | { 771 | ulong carry = 0; 772 | for (int j = 0, k = i; j < rightSide.m_digits.DataUsed; j++, k++) 773 | { 774 | ulong val = ((ulong)leftSide.m_digits[i] * (ulong)rightSide.m_digits[j]) + (ulong)da[k] + carry; 775 | 776 | da[k] = (DType)(val & DigitsArray.AllBits); 777 | carry = (val >> DigitsArray.DataSizeBits); 778 | } 779 | 780 | if (carry != 0) 781 | { 782 | da[i + rightSide.m_digits.DataUsed] = (DType)carry; 783 | } 784 | } 785 | 786 | //da.ResetDataUsed(); 787 | BigInteger result = new BigInteger(da); 788 | return (leftSideNeg != rightSideNeg ? -result : result); 789 | } 790 | 791 | /// 792 | /// Multiply two BigIntegers returning the result. 793 | /// 794 | /// A BigInteger. 795 | /// A BigInteger 796 | /// 797 | public static BigInteger Multiply(BigInteger leftSide, BigInteger rightSide) 798 | { 799 | return leftSide * rightSide; 800 | } 801 | 802 | /// 803 | /// Divide a BigInteger by another BigInteger and returning the result. 804 | /// 805 | /// A BigInteger divisor. 806 | /// A BigInteger dividend. 807 | /// The BigInteger result. 808 | public static BigInteger operator / (BigInteger leftSide, BigInteger rightSide) 809 | { 810 | if (leftSide == null) 811 | { 812 | throw new ArgumentNullException("leftSide"); 813 | } 814 | if (rightSide == null) 815 | { 816 | throw new ArgumentNullException("rightSide"); 817 | } 818 | 819 | if (rightSide.IsZero) 820 | { 821 | throw new DivideByZeroException(); 822 | } 823 | 824 | bool divisorNeg = rightSide.IsNegative; 825 | bool dividendNeg = leftSide.IsNegative; 826 | 827 | leftSide = Abs(leftSide); 828 | rightSide = Abs(rightSide); 829 | 830 | if (leftSide < rightSide) 831 | { 832 | return new BigInteger(0); 833 | } 834 | 835 | BigInteger quotient; 836 | BigInteger remainder; 837 | Divide(leftSide, rightSide, out quotient, out remainder); 838 | 839 | return (dividendNeg != divisorNeg ? -quotient : quotient); 840 | } 841 | 842 | /// 843 | /// Divide a BigInteger by another BigInteger and returning the result. 844 | /// 845 | /// A BigInteger divisor. 846 | /// A BigInteger dividend. 847 | /// The BigInteger result. 848 | public static BigInteger Divide(BigInteger leftSide, BigInteger rightSide) 849 | { 850 | return leftSide / rightSide; 851 | } 852 | 853 | public static void Divide(BigInteger leftSide, BigInteger rightSide, out BigInteger quotient, out BigInteger remainder) 854 | { 855 | if (leftSide.IsZero) 856 | { 857 | quotient = new BigInteger(); 858 | remainder = new BigInteger(); 859 | return; 860 | } 861 | 862 | if (rightSide.m_digits.DataUsed == 1) 863 | { 864 | SingleDivide(leftSide, rightSide, out quotient, out remainder); 865 | } 866 | else 867 | { 868 | MultiDivide(leftSide, rightSide, out quotient, out remainder); 869 | } 870 | } 871 | 872 | private static void MultiDivide(BigInteger leftSide, BigInteger rightSide, out BigInteger quotient, out BigInteger remainder) 873 | { 874 | if (rightSide.IsZero) 875 | { 876 | throw new DivideByZeroException(); 877 | } 878 | 879 | DType val = rightSide.m_digits[rightSide.m_digits.DataUsed - 1]; 880 | int d = 0; 881 | for (uint mask = DigitsArray.HiBitSet; mask != 0 && (val & mask) == 0; mask >>= 1) 882 | { 883 | d++; 884 | } 885 | 886 | int remainderLen = leftSide.m_digits.DataUsed + 1; 887 | DType[] remainderDat = new DType[remainderLen]; 888 | leftSide.m_digits.CopyTo(remainderDat, 0, leftSide.m_digits.DataUsed); 889 | 890 | DigitsArray.ShiftLeft(remainderDat, d); 891 | rightSide = rightSide << d; 892 | 893 | ulong firstDivisor = rightSide.m_digits[rightSide.m_digits.DataUsed - 1]; 894 | ulong secondDivisor = (rightSide.m_digits.DataUsed < 2 ? (DType)0 : rightSide.m_digits[rightSide.m_digits.DataUsed - 2]); 895 | 896 | int divisorLen = rightSide.m_digits.DataUsed + 1; 897 | DigitsArray dividendPart = new DigitsArray(divisorLen, divisorLen); 898 | DType[] result = new DType[leftSide.m_digits.Count + 1]; 899 | int resultPos = 0; 900 | 901 | ulong carryBit = (ulong)0x1 << DigitsArray.DataSizeBits; // 0x100000000 902 | for (int j = remainderLen - rightSide.m_digits.DataUsed, pos = remainderLen - 1; j > 0; j--, pos--) 903 | { 904 | ulong dividend = ((ulong)remainderDat[pos] << DigitsArray.DataSizeBits) + (ulong)remainderDat[pos - 1]; 905 | ulong qHat = (dividend / firstDivisor); 906 | ulong rHat = (dividend % firstDivisor); 907 | 908 | while (pos >= 2) 909 | { 910 | if (qHat == carryBit || (qHat * secondDivisor) > ((rHat << DigitsArray.DataSizeBits) + remainderDat[pos - 2])) 911 | { 912 | qHat--; 913 | rHat += firstDivisor; 914 | if (rHat < carryBit) 915 | { 916 | continue; 917 | } 918 | } 919 | break; 920 | } 921 | 922 | for (int h = 0; h < divisorLen; h++) 923 | { 924 | dividendPart[divisorLen - h - 1] = remainderDat[pos - h]; 925 | } 926 | 927 | BigInteger dTemp = new BigInteger(dividendPart); 928 | BigInteger rTemp = rightSide * (long)qHat; 929 | while (rTemp > dTemp) 930 | { 931 | qHat--; 932 | rTemp -= rightSide; 933 | } 934 | 935 | rTemp = dTemp - rTemp; 936 | for (int h = 0; h < divisorLen; h++) 937 | { 938 | remainderDat[pos - h] = rTemp.m_digits[rightSide.m_digits.DataUsed - h]; 939 | } 940 | 941 | result[resultPos++] = (DType)qHat; 942 | } 943 | 944 | Array.Reverse(result, 0, resultPos); 945 | quotient = new BigInteger(new DigitsArray(result)); 946 | 947 | int n = DigitsArray.ShiftRight(remainderDat, d); 948 | DigitsArray rDA = new DigitsArray(n, n); 949 | rDA.CopyFrom(remainderDat, 0, 0, rDA.DataUsed); 950 | remainder = new BigInteger(rDA); 951 | } 952 | 953 | private static void SingleDivide(BigInteger leftSide, BigInteger rightSide, out BigInteger quotient, out BigInteger remainder) 954 | { 955 | if (rightSide.IsZero) 956 | { 957 | throw new DivideByZeroException(); 958 | } 959 | 960 | DigitsArray remainderDigits = new DigitsArray(leftSide.m_digits); 961 | remainderDigits.ResetDataUsed(); 962 | 963 | int pos = remainderDigits.DataUsed - 1; 964 | ulong divisor = (ulong)rightSide.m_digits[0]; 965 | ulong dividend = (ulong)remainderDigits[pos]; 966 | 967 | DType[] result = new DType[leftSide.m_digits.Count]; 968 | leftSide.m_digits.CopyTo(result, 0, result.Length); 969 | int resultPos = 0; 970 | 971 | if (dividend >= divisor) 972 | { 973 | result[resultPos++] = (DType)(dividend / divisor); 974 | remainderDigits[pos] = (DType)(dividend % divisor); 975 | } 976 | pos--; 977 | 978 | while (pos >= 0) 979 | { 980 | dividend = ((ulong)(remainderDigits[pos + 1]) << DigitsArray.DataSizeBits) + (ulong)remainderDigits[pos]; 981 | result[resultPos++] = (DType)(dividend / divisor); 982 | remainderDigits[pos + 1] = 0; 983 | remainderDigits[pos--] = (DType)(dividend % divisor); 984 | } 985 | remainder = new BigInteger(remainderDigits); 986 | 987 | DigitsArray quotientDigits = new DigitsArray(resultPos + 1, resultPos); 988 | int j = 0; 989 | for (int i = quotientDigits.DataUsed - 1; i >= 0; i--, j++) 990 | { 991 | quotientDigits[j] = result[i]; 992 | } 993 | quotient = new BigInteger(quotientDigits); 994 | } 995 | 996 | /// 997 | /// Perform the modulus of a BigInteger with another BigInteger and return the result. 998 | /// 999 | /// A BigInteger divisor. 1000 | /// A BigInteger dividend. 1001 | /// The BigInteger result. 1002 | public static BigInteger operator % (BigInteger leftSide, BigInteger rightSide) 1003 | { 1004 | if (leftSide == null) 1005 | { 1006 | throw new ArgumentNullException("leftSide"); 1007 | } 1008 | 1009 | if (rightSide == null) 1010 | { 1011 | throw new ArgumentNullException("rightSide"); 1012 | } 1013 | 1014 | if (rightSide.IsZero) 1015 | { 1016 | throw new DivideByZeroException(); 1017 | } 1018 | 1019 | BigInteger quotient; 1020 | BigInteger remainder; 1021 | 1022 | bool dividendNeg = leftSide.IsNegative; 1023 | leftSide = Abs(leftSide); 1024 | rightSide = Abs(rightSide); 1025 | 1026 | if (leftSide < rightSide) 1027 | { 1028 | return leftSide; 1029 | } 1030 | 1031 | Divide(leftSide, rightSide, out quotient, out remainder); 1032 | 1033 | return (dividendNeg ? -remainder : remainder); 1034 | } 1035 | 1036 | /// 1037 | /// Perform the modulus of a BigInteger with another BigInteger and return the result. 1038 | /// 1039 | /// A BigInteger divisor. 1040 | /// A BigInteger dividend. 1041 | /// The BigInteger result. 1042 | public static BigInteger Modulus(BigInteger leftSide, BigInteger rightSide) 1043 | { 1044 | return leftSide % rightSide; 1045 | } 1046 | #endregion 1047 | 1048 | #region Bitwise Operator Overloads 1049 | 1050 | public static BigInteger operator & (BigInteger leftSide, BigInteger rightSide) 1051 | { 1052 | int len = System.Math.Max(leftSide.m_digits.DataUsed, rightSide.m_digits.DataUsed); 1053 | DigitsArray da = new DigitsArray(len, len); 1054 | for (int idx = 0; idx < len; idx++) 1055 | { 1056 | da[idx] = (DType)(leftSide.m_digits[idx] & rightSide.m_digits[idx]); 1057 | } 1058 | return new BigInteger(da); 1059 | } 1060 | 1061 | public static BigInteger BitwiseAnd(BigInteger leftSide, BigInteger rightSide) 1062 | { 1063 | return leftSide & rightSide; 1064 | } 1065 | 1066 | public static BigInteger operator | (BigInteger leftSide, BigInteger rightSide) 1067 | { 1068 | int len = System.Math.Max(leftSide.m_digits.DataUsed, rightSide.m_digits.DataUsed); 1069 | DigitsArray da = new DigitsArray(len, len); 1070 | for (int idx = 0; idx < len; idx++) 1071 | { 1072 | da[idx] = (DType)(leftSide.m_digits[idx] | rightSide.m_digits[idx]); 1073 | } 1074 | return new BigInteger(da); 1075 | } 1076 | 1077 | public static BigInteger BitwiseOr(BigInteger leftSide, BigInteger rightSide) 1078 | { 1079 | return leftSide | rightSide; 1080 | } 1081 | 1082 | public static BigInteger operator ^ (BigInteger leftSide, BigInteger rightSide) 1083 | { 1084 | int len = System.Math.Max(leftSide.m_digits.DataUsed, rightSide.m_digits.DataUsed); 1085 | DigitsArray da = new DigitsArray(len, len); 1086 | for (int idx = 0; idx < len; idx++) 1087 | { 1088 | da[idx] = (DType)(leftSide.m_digits[idx] ^ rightSide.m_digits[idx]); 1089 | } 1090 | return new BigInteger(da); 1091 | } 1092 | 1093 | public static BigInteger Xor(BigInteger leftSide, BigInteger rightSide) 1094 | { 1095 | return leftSide ^ rightSide; 1096 | } 1097 | 1098 | public static BigInteger operator ~ (BigInteger leftSide) 1099 | { 1100 | DigitsArray da = new DigitsArray(leftSide.m_digits.Count); 1101 | for(int idx = 0; idx < da.Count; idx++) 1102 | { 1103 | da[idx] = (DType)(~(leftSide.m_digits[idx])); 1104 | } 1105 | 1106 | return new BigInteger(da); 1107 | } 1108 | 1109 | public static BigInteger OnesComplement(BigInteger leftSide) 1110 | { 1111 | return ~leftSide; 1112 | } 1113 | 1114 | #endregion 1115 | 1116 | #region Left and Right Shift Operator Overloads 1117 | public static BigInteger operator << (BigInteger leftSide, int shiftCount) 1118 | { 1119 | if (leftSide == null) 1120 | { 1121 | throw new ArgumentNullException("leftSide"); 1122 | } 1123 | 1124 | DigitsArray da = new DigitsArray(leftSide.m_digits); 1125 | da.DataUsed = da.ShiftLeftWithoutOverflow(shiftCount); 1126 | 1127 | return new BigInteger(da); 1128 | } 1129 | 1130 | public static BigInteger LeftShift(BigInteger leftSide, int shiftCount) 1131 | { 1132 | return leftSide << shiftCount; 1133 | } 1134 | 1135 | public static BigInteger operator >> (BigInteger leftSide, int shiftCount) 1136 | { 1137 | if (leftSide == null) 1138 | { 1139 | throw new ArgumentNullException("leftSide"); 1140 | } 1141 | 1142 | DigitsArray da = new DigitsArray(leftSide.m_digits); 1143 | da.DataUsed = da.ShiftRight(shiftCount); 1144 | 1145 | if (leftSide.IsNegative) 1146 | { 1147 | for (int i = da.Count - 1; i >= da.DataUsed; i--) 1148 | { 1149 | da[i] = DigitsArray.AllBits; 1150 | } 1151 | 1152 | DType mask = DigitsArray.HiBitSet; 1153 | for (int i = 0; i < DigitsArray.DataSizeBits; i++) 1154 | { 1155 | if ((da[da.DataUsed - 1] & mask) == DigitsArray.HiBitSet) 1156 | { 1157 | break; 1158 | } 1159 | da[da.DataUsed - 1] |= mask; 1160 | mask >>= 1; 1161 | } 1162 | da.DataUsed = da.Count; 1163 | } 1164 | 1165 | return new BigInteger(da); 1166 | } 1167 | 1168 | public static BigInteger RightShift(BigInteger leftSide, int shiftCount) 1169 | { 1170 | if (leftSide == null) 1171 | { 1172 | throw new ArgumentNullException("leftSide"); 1173 | } 1174 | 1175 | return leftSide >> shiftCount; 1176 | } 1177 | #endregion 1178 | 1179 | #region Relational Operator Overloads 1180 | 1181 | /// 1182 | /// Compare this instance to a specified object and returns indication of their relative value. 1183 | /// 1184 | /// An object to compare, or a null reference (Nothing in Visual Basic). 1185 | /// A signed number indicating the relative value of this instance and value. 1186 | /// 1187 | /// 1188 | /// Return Value 1189 | /// Description 1190 | /// 1191 | /// 1192 | /// Less than zero 1193 | /// This instance is less than value. 1194 | /// 1195 | /// 1196 | /// Zero 1197 | /// This instance is equal to value. 1198 | /// 1199 | /// 1200 | /// Greater than zero 1201 | /// 1202 | /// This instance is greater than value. 1203 | /// -or- 1204 | /// value is a null reference (Nothing in Visual Basic). 1205 | /// 1206 | /// 1207 | /// 1208 | /// 1209 | public int CompareTo(BigInteger value) 1210 | { 1211 | return Compare(this, value); 1212 | } 1213 | 1214 | /// 1215 | /// Compare two objects and return an indication of their relative value. 1216 | /// 1217 | /// An object to compare, or a null reference (Nothing in Visual Basic). 1218 | /// An object to compare, or a null reference (Nothing in Visual Basic). 1219 | /// A signed number indicating the relative value of this instance and value. 1220 | /// 1221 | /// 1222 | /// Return Value 1223 | /// Description 1224 | /// 1225 | /// 1226 | /// Less than zero 1227 | /// This instance is less than value. 1228 | /// 1229 | /// 1230 | /// Zero 1231 | /// This instance is equal to value. 1232 | /// 1233 | /// 1234 | /// Greater than zero 1235 | /// 1236 | /// This instance is greater than value. 1237 | /// -or- 1238 | /// value is a null reference (Nothing in Visual Basic). 1239 | /// 1240 | /// 1241 | /// 1242 | /// 1243 | public static int Compare(BigInteger leftSide, BigInteger rightSide) 1244 | { 1245 | if (object.ReferenceEquals(leftSide, rightSide)) 1246 | { 1247 | return 0; 1248 | } 1249 | 1250 | if (object.ReferenceEquals(leftSide, null)) 1251 | { 1252 | throw new ArgumentNullException("leftSide"); 1253 | } 1254 | 1255 | if (object.ReferenceEquals(rightSide, null)) 1256 | { 1257 | throw new ArgumentNullException("rightSide"); 1258 | } 1259 | 1260 | if (leftSide > rightSide) return 1; 1261 | if (leftSide == rightSide) return 0; 1262 | return -1; 1263 | } 1264 | 1265 | public static bool operator == (BigInteger leftSide, BigInteger rightSide) 1266 | { 1267 | if (object.ReferenceEquals(leftSide, rightSide)) 1268 | { 1269 | return true; 1270 | } 1271 | 1272 | if (object.ReferenceEquals(leftSide, null ) || object.ReferenceEquals(rightSide, null )) 1273 | { 1274 | return false; 1275 | } 1276 | 1277 | if (leftSide.IsNegative != rightSide.IsNegative) 1278 | { 1279 | return false; 1280 | } 1281 | 1282 | return leftSide.Equals(rightSide); 1283 | } 1284 | 1285 | public static bool operator != (BigInteger leftSide, BigInteger rightSide) 1286 | { 1287 | return !(leftSide == rightSide); 1288 | } 1289 | 1290 | public static bool operator > (BigInteger leftSide, BigInteger rightSide) 1291 | { 1292 | if (object.ReferenceEquals(leftSide, null)) 1293 | { 1294 | throw new ArgumentNullException("leftSide"); 1295 | } 1296 | 1297 | if (object.ReferenceEquals(rightSide, null)) 1298 | { 1299 | throw new ArgumentNullException("rightSide"); 1300 | } 1301 | 1302 | if (leftSide.IsNegative != rightSide.IsNegative) 1303 | { 1304 | return rightSide.IsNegative; 1305 | } 1306 | 1307 | if (leftSide.m_digits.DataUsed != rightSide.m_digits.DataUsed) 1308 | { 1309 | return leftSide.m_digits.DataUsed > rightSide.m_digits.DataUsed; 1310 | } 1311 | 1312 | for (int idx = leftSide.m_digits.DataUsed - 1; idx >= 0; idx--) 1313 | { 1314 | if (leftSide.m_digits[idx] != rightSide.m_digits[idx]) 1315 | { 1316 | return (leftSide.m_digits[idx] > rightSide.m_digits[idx]); 1317 | } 1318 | } 1319 | return false; 1320 | } 1321 | 1322 | public static bool operator < (BigInteger leftSide, BigInteger rightSide) 1323 | { 1324 | if (object.ReferenceEquals(leftSide, null)) 1325 | { 1326 | throw new ArgumentNullException("leftSide"); 1327 | } 1328 | 1329 | if (object.ReferenceEquals(rightSide, null)) 1330 | { 1331 | throw new ArgumentNullException("rightSide"); 1332 | } 1333 | 1334 | if (leftSide.IsNegative != rightSide.IsNegative) 1335 | { 1336 | return leftSide.IsNegative; 1337 | } 1338 | 1339 | if (leftSide.m_digits.DataUsed != rightSide.m_digits.DataUsed) 1340 | { 1341 | return leftSide.m_digits.DataUsed < rightSide.m_digits.DataUsed; 1342 | } 1343 | 1344 | for (int idx = leftSide.m_digits.DataUsed - 1; idx >= 0; idx--) 1345 | { 1346 | if (leftSide.m_digits[idx] != rightSide.m_digits[idx]) 1347 | { 1348 | return (leftSide.m_digits[idx] < rightSide.m_digits[idx]); 1349 | } 1350 | } 1351 | return false; 1352 | } 1353 | 1354 | public static bool operator >= (BigInteger leftSide, BigInteger rightSide) 1355 | { 1356 | return Compare(leftSide, rightSide) >= 0; 1357 | } 1358 | 1359 | public static bool operator <= (BigInteger leftSide, BigInteger rightSide) 1360 | { 1361 | return Compare(leftSide, rightSide) <= 0; 1362 | } 1363 | #endregion 1364 | 1365 | #region Object Overrides 1366 | /// 1367 | /// Determines whether two Object instances are equal. 1368 | /// 1369 | /// An Object to compare with this instance. 1370 | /// 1371 | /// System.Object 1372 | public override bool Equals(object obj) 1373 | { 1374 | if (object.ReferenceEquals(obj, null)) 1375 | { 1376 | return false; 1377 | } 1378 | 1379 | if (object.ReferenceEquals(this, obj)) 1380 | { 1381 | return true; 1382 | } 1383 | 1384 | BigInteger c = (BigInteger)obj; 1385 | if (this.m_digits.DataUsed != c.m_digits.DataUsed) 1386 | { 1387 | return false; 1388 | } 1389 | 1390 | for (int idx = 0; idx < this.m_digits.DataUsed; idx++) 1391 | { 1392 | if (this.m_digits[idx] != c.m_digits[idx]) 1393 | { 1394 | return false; 1395 | } 1396 | } 1397 | return true; 1398 | } 1399 | 1400 | /// 1401 | /// Returns the hash code for this instance. 1402 | /// 1403 | /// A 32-bit signed integer has code. 1404 | /// System.Object 1405 | public override int GetHashCode() 1406 | { 1407 | return this.m_digits.GetHashCode(); 1408 | } 1409 | 1410 | /// 1411 | /// Converts the numeric value of this instance to its equivalent base 10 string representation. 1412 | /// 1413 | /// A String in base 10. 1414 | /// System.Object 1415 | public override string ToString() 1416 | { 1417 | return ToString(10); 1418 | } 1419 | #endregion 1420 | 1421 | #region Type Conversion Methods 1422 | /// 1423 | /// Converts the numeric value of this instance to its equivalent string representation in specified base. 1424 | /// 1425 | /// Int radix between 2 and 36 1426 | /// A string. 1427 | public string ToString(int radix) 1428 | { 1429 | if (radix < 2 || radix > 36) 1430 | { 1431 | throw new ArgumentOutOfRangeException("radix"); 1432 | } 1433 | 1434 | if (IsZero) 1435 | { 1436 | return "0"; 1437 | } 1438 | 1439 | BigInteger a = this; 1440 | bool negative = a.IsNegative; 1441 | a = Abs(this); 1442 | 1443 | BigInteger quotient; 1444 | BigInteger remainder; 1445 | BigInteger biRadix = new BigInteger(radix); 1446 | 1447 | const string charSet = "0123456789abcdefghijklmnopqrstuvwxyz"; 1448 | System.Collections.ArrayList al = new System.Collections.ArrayList(); 1449 | while (a.m_digits.DataUsed > 1 || (a.m_digits.DataUsed == 1 && a.m_digits[0] != 0)) 1450 | { 1451 | Divide(a, biRadix, out quotient, out remainder); 1452 | al.Insert(0, charSet[(int)remainder.m_digits[0]]); 1453 | a = quotient; 1454 | } 1455 | 1456 | string result = new String((char[])al.ToArray(typeof(char))); 1457 | if (radix == 10 && negative) 1458 | { 1459 | return "-" + result; 1460 | } 1461 | 1462 | return result; 1463 | } 1464 | 1465 | /// 1466 | /// Returns string in hexidecimal of the internal digit representation. 1467 | /// 1468 | /// 1469 | /// This is not the same as ToString(16). This method does not return the sign, but instead 1470 | /// dumps the digits array into a string representation in base 16. 1471 | /// 1472 | /// A string in base 16. 1473 | public string ToHexString() 1474 | { 1475 | System.Text.StringBuilder sb = new System.Text.StringBuilder(); 1476 | sb.AppendFormat("{0:X}", m_digits[m_digits.DataUsed - 1]); 1477 | 1478 | string f = "{0:X" + (2 * DigitsArray.DataSizeOf) + "}"; 1479 | for (int i = m_digits.DataUsed - 2; i >= 0; i--) 1480 | { 1481 | sb.AppendFormat(f, m_digits[i]); 1482 | } 1483 | 1484 | return sb.ToString(); 1485 | } 1486 | 1487 | /// 1488 | /// Returns BigInteger as System.Int16 if possible. 1489 | /// 1490 | /// 1491 | /// Int value of BigInteger 1492 | /// When BigInteger is too large to fit into System.Int16 1493 | public static int ToInt16(BigInteger value) 1494 | { 1495 | if (object.ReferenceEquals(value, null)) 1496 | { 1497 | throw new ArgumentNullException("value"); 1498 | } 1499 | return System.Int16.Parse(value.ToString(), System.Globalization.NumberStyles.Integer, System.Globalization.CultureInfo.CurrentCulture); 1500 | } 1501 | 1502 | /// 1503 | /// Returns BigInteger as System.UInt16 if possible. 1504 | /// 1505 | /// 1506 | /// 1507 | /// When BigInteger is too large to fit into System.UInt16 1508 | public static uint ToUInt16(BigInteger value) 1509 | { 1510 | if (object.ReferenceEquals(value, null)) 1511 | { 1512 | throw new ArgumentNullException("value"); 1513 | } 1514 | return System.UInt16.Parse(value.ToString(), System.Globalization.NumberStyles.Integer, System.Globalization.CultureInfo.CurrentCulture); 1515 | } 1516 | 1517 | /// 1518 | /// Returns BigInteger as System.Int32 if possible. 1519 | /// 1520 | /// 1521 | /// 1522 | /// When BigInteger is too large to fit into System.Int32 1523 | public static int ToInt32(BigInteger value) 1524 | { 1525 | if (object.ReferenceEquals(value, null)) 1526 | { 1527 | throw new ArgumentNullException("value"); 1528 | } 1529 | return System.Int32.Parse(value.ToString(), System.Globalization.NumberStyles.Integer, System.Globalization.CultureInfo.CurrentCulture); 1530 | } 1531 | 1532 | /// 1533 | /// Returns BigInteger as System.UInt32 if possible. 1534 | /// 1535 | /// 1536 | /// 1537 | /// When BigInteger is too large to fit into System.UInt32 1538 | public static uint ToUInt32(BigInteger value) 1539 | { 1540 | if (object.ReferenceEquals(value, null)) 1541 | { 1542 | throw new ArgumentNullException("value"); 1543 | } 1544 | return System.UInt32.Parse(value.ToString(), System.Globalization.NumberStyles.Integer, System.Globalization.CultureInfo.CurrentCulture); 1545 | } 1546 | 1547 | /// 1548 | /// Returns BigInteger as System.Int64 if possible. 1549 | /// 1550 | /// 1551 | /// 1552 | /// When BigInteger is too large to fit into System.Int64 1553 | public static long ToInt64(BigInteger value) 1554 | { 1555 | if (object.ReferenceEquals(value, null)) 1556 | { 1557 | throw new ArgumentNullException("value"); 1558 | } 1559 | return System.Int64.Parse(value.ToString(), System.Globalization.NumberStyles.Integer, System.Globalization.CultureInfo.CurrentCulture); 1560 | } 1561 | 1562 | /// 1563 | /// Returns BigInteger as System.UInt64 if possible. 1564 | /// 1565 | /// 1566 | /// 1567 | /// When BigInteger is too large to fit into System.UInt64 1568 | public static ulong ToUInt64(BigInteger value) 1569 | { 1570 | if (object.ReferenceEquals(value, null)) 1571 | { 1572 | throw new ArgumentNullException("value"); 1573 | } 1574 | return System.UInt64.Parse(value.ToString(), System.Globalization.NumberStyles.Integer, System.Globalization.CultureInfo.CurrentCulture); 1575 | } 1576 | #endregion 1577 | } 1578 | } --------------------------------------------------------------------------------