Пример #1
0
    public void ClearCurrentPoints()
    {
        List <CustomList.MyClass> myClass = gameObject.GetComponent <CustomList>().MyList;

        myClass.Clear();
        keyList = new KeyFrameList();
    }
Пример #2
0
    public void ExportKeyFrames()
    {
        keyList.frameList = new List <WeldonKeyFrame>();

        foreach (MyClass thing in MyList)
        {
            WeldonKeyFrame frame = new WeldonKeyFrame();
            frame.time  = thing.time;
            frame.posX  = thing.position.x;
            frame.posY  = thing.position.y;
            frame.posZ  = thing.position.z;
            frame.rotX  = thing.rotation.x;
            frame.rotY  = thing.rotation.y;
            frame.rotZ  = thing.rotation.z;
            frame.scalX = thing.scale.x;
            frame.scalY = thing.scale.y;
            frame.scalZ = thing.scale.z;
            keyList.frameList.Add(frame);
        }

        string filePath = Application.dataPath + "/Animations/JsonExports/" + SceneManager.GetActiveScene().name + "/";

        if (!Directory.Exists(filePath))
        {
            Directory.CreateDirectory(filePath);
        }

        string stringToWrite = JsonUtility.ToJson(keyList);

        File.WriteAllText(filePath + gameObject.name + "_" + gameObject.transform.GetSiblingIndex() + ".txt", stringToWrite);
        //fileExported = true;
        keyList = new KeyFrameList();
        AssetDatabase.Refresh();
    }
Пример #3
0
    public override string getKeyFramesString(KeyFrameList keyList)
    {
        StringBuilder sb = new StringBuilder();

        foreach (WeldonKeyFrame frame in keyList.frameList)
        {
            int            index = keyList.frameList.FindIndex(obj => obj == frame);
            string         loopTrueString = "";
            string         animTrigger = "";
            string         posFrom = "", rotFrom = "", scaleFrom = "";
            WeldonKeyFrame prevFrame = new WeldonKeyFrame();
            if (index > 0)
            {
                prevFrame = keyList.frameList[index - 1];
                posFrom   = $"from: {prevFrame.posX*z_pos_offset} {prevFrame.posY*y_pos_offset} {prevFrame.posZ*z_pos_offset};";
                rotFrom   = $"from: {prevFrame.rotX*x_rot_offset} {prevFrame.rotY*y_rot_offset} {prevFrame.rotZ*z_rot_offset};";
                scaleFrom = $"from: {prevFrame.scalX*x_scale_offset} {prevFrame.scalY*y_scale_offset} {prevFrame.scalZ*y_scale_offset};";

                animTrigger = $"startEvents: animationcomplete__{objectId}_f{index-1}" + ((index == 1 && childToAdd.GetComponent <AnimationHelper>().loop)? $", animationcomplete__{objectId}_f{keyList.frameList.Count-1};" : ";");
            }
            else
            {
                if (childToAdd.GetComponent <AnimationHelper>().onClick)
                {
                    animTrigger = $"startEvents: mousedown;";
                }
            }

            string posTo   = $"to: {frame.posX*x_pos_offset} {frame.posY*y_pos_offset} {frame.posZ*z_pos_offset};",
                   rotTo   = $"to: {frame.rotX*x_rot_offset} {frame.rotY*y_rot_offset} {frame.rotZ*z_rot_offset};",
                   scaleTo = $"to: {frame.scalX*x_scale_offset} {frame.scalY*y_scale_offset} {frame.scalZ*y_scale_offset};";

            //if (childToAdd.GetComponent<AnimationHelper>().loop) loopTrueString = $"repeat = \"indefinite\"";
            bool isFirstFrame = prevFrame.time.Equals(-1) ? true : false;
            if (isFirstFrame)
            {
                prevFrame.time = 0;
            }
            if (frame.IsDifferentPosition(prevFrame) || isFirstFrame)
            {
                sb.AppendLine($"animation__{objectId}_f{index}=\" property: position; {posFrom} {posTo} dur: {(frame.time - prevFrame.time) * 1000}; easing: linear; {animTrigger}\"");
            }
            if (frame.IsDifferentRotation(prevFrame) || isFirstFrame)
            {
                sb.AppendLine($"animation__{objectId}_f{index}=\" property: rotation; {rotFrom} {rotTo} dur: {(frame.time - prevFrame.time) * 1000}; easing: linear; {animTrigger}\"");
            }
            if ((frame.IsDifferentWidth(prevFrame) || isFirstFrame))
            {
                sb.AppendLine($"animation__{objectId}_f{index}=\" property: scale; {scaleFrom} {scaleTo} dur: {(frame.time - prevFrame.time) * 1000}; easing: linear; {animTrigger}\"");
            }
        }
        return(sb.ToString());
    }
Пример #4
0
    public string getHtmlString(KeyFrameList keyList)
    {
        StringBuilder sb = new StringBuilder();

        sb.AppendLine($"<{HtmlTag} {getObjectPropertiesString()}");
        if (keyList != null)
        {
            sb.AppendLine($"{getKeyFramesString(keyList)}");
        }
        sb.Append($"></{HtmlTag}>");
        return(sb.ToString());
    }
Пример #5
0
    public void RecordPoint()
    {
        if (keyList == null)
        {
            keyList = new KeyFrameList();
        }

        transformToRecord = gameObject.transform;
        WeldonKeyFrame            frame   = new WeldonKeyFrame(timeOfPosition, transformToRecord);
        List <CustomList.MyClass> myClass = gameObject.GetComponent <CustomList>().MyList;

        myClass.Add(new CustomList.MyClass(frame));
        keyList.frameList.Add(frame);
        Debug.Log("Frame Added: " + frame.InformationString());
    }
Пример #6
0
    public void ExportPoints()
    {
        string filePath = Application.dataPath + "/Animations/JsonExports/" + SceneManager.GetActiveScene().name + "/";

        if (!Directory.Exists(filePath))
        {
            Directory.CreateDirectory(filePath);
        }

        string stringToWrite = JsonUtility.ToJson(keyList);

        File.WriteAllText(filePath + gameObject.name + "_" + gameObject.transform.GetSiblingIndex() + ".txt", stringToWrite);
        //fileExported = true;
        keyList = new KeyFrameList();
        AssetDatabase.Refresh();
    }
Пример #7
0
    private void Start()
    {
        keyList = new KeyFrameList();
        string filePath = Application.dataPath + "/Animations/JsonExports/" + SceneManager.GetActiveScene().name + "/" + gameObject.name + "_" + gameObject.transform.GetSiblingIndex() + ".txt";

        if (File.Exists(filePath))
        {
            string textFile = File.ReadAllText(filePath);
            keyList = JsonUtility.FromJson <KeyFrameList>(textFile);
        }
        else
        {
            keyList = null;
        }
        startTime = Time.time;
        oFrame    = new WeldonKeyFrame(0, transform);
    }
Пример #8
0
    static void CompileFileHTML()
    {
        var ci = new CultureInfo("en-US");

        Thread.CurrentThread.CurrentCulture   = ci;
        Thread.CurrentThread.CurrentUICulture = ci;

        string folderPath = GameObject.FindWithTag("ImageTarget").GetComponent <ImageTarget>().destination;

        if (!Directory.Exists(folderPath))
        {
            Directory.CreateDirectory(folderPath);
        }
        if (!File.Exists("Assets/AR.js-master/aframe/fullscreen.png"))
        {
            File.Copy("Assets/ARjs_Unity/Icons/fullscreen.png", "Assets/AR.js-master/aframe/fullscreen.png");
        }
        if (!File.Exists("Assets/AR.js-master/aframe/exit_fullscreen.png"))
        {
            File.Copy("Assets/ARjs_Unity/Icons/exit_fullscreen.png", "Assets/AR.js-master/aframe/exit_fullscreen.png");
        }
        string fileName = "index.html";
        bool   hasVideo = false;

        bool isNft = GameObject.FindWithTag("ImageTarget").GetComponent <ImageTarget>().isNftImage;

        StringBuilder sb = new StringBuilder();

        #region Top HTML
        sb.AppendLine("<!-- BEGIN: Top HTML -->");
        sb.Append(HtmlStrings.getTopHtml(isNft));
        sb.AppendLine("<!-- END: Top HTML -->");
        #endregion Top HTML

        Transform imageTarget = GameObject.FindGameObjectWithTag("ImageTarget").transform;
        if (imageTarget == null)
        {
            Debug.Log("AR.js error: There is no Image Target to Compile");
            return;
        }

        #region Unity Compiled Events
        //Adds in the actions of the children to javascript.
        sb.AppendLine("<!-- BEGIN: Unity Compiled Events -->");
        sb.AppendLine("<script>");

        //GLOBALS FOR ANIMATION UPDATE
        sb.AppendLine("var markerFound = 0;");
        bool hasBezier = false;
        for (int i = 0; i < imageTarget.childCount; i++)
        {
            GameObject childToAdd = imageTarget.GetChild(i).gameObject;
            for (int j = 0; j < childToAdd.transform.childCount; j++)
            {
                if (childToAdd.transform.GetChild(j).name.ToLower().Contains("bezier"))
                {
                    hasBezier = true;
                }
            }
        }
        if (hasBezier)
        {
            //sb.AppendLine("var subtractTime = 0;");
            for (int i = 0; i < imageTarget.childCount; i++)
            {
                GameObject childToAdd = imageTarget.GetChild(i).gameObject;
                string     childID    = childToAdd.name + "_" + i;
                Bezier     bez        = childToAdd.GetComponentInChildren <Bezier>();
                if (bez != null)
                {
                    sb.AppendLine("var " + childID + "_CurrentPoint = 0;");
                    sb.AppendLine("var " + childID + "_SubtractTime = 0;");
                    sb.AppendLine("var " + childID + "_PointsArray = " + bez.PointsListString() + ";");
                }
            }
        }
        //END GLOBALS FOR ANIMATION UPDATE

        sb.AppendLine("AFRAME.registerComponent('button', {");
        sb.AppendLine("init: function () {");
        sb.AppendLine($"var elem = document.documentElement;");
        sb.AppendLine($"var marker = document.querySelector(\"#marker\");");
        sb.AppendLine($"var fullbutton = document.querySelector(\"#fullscreen\");");
        for (int i = 0; i < imageTarget.childCount; i++)
        {
            GameObject childToAdd = imageTarget.GetChild(i).gameObject;
            if (childToAdd.tag == "Video")
            {
                hasVideo = true;
            }
        }
        if (hasVideo)
        {
            sb.AppendLine($"var button = document.querySelector(\"#mutebutton\");");
        }

        for (int i = 0; i < imageTarget.childCount; i++)
        {
            GameObject childToAdd = imageTarget.GetChild(i).gameObject;
            string     id         = childToAdd.name + "_" + i;
            if (childToAdd.GetComponent <ButtonHelper>() != null)
            {
                sb.AppendLine($"var {id} = document.querySelector(\"#{id}\");");
            }

            if (childToAdd.tag == "Video")
            {
                hasVideo = true;
                sb.AppendLine($"var {id} = document.querySelector(\"#{childToAdd.name + "_Asset_" + i}\");");
            }
        }
        //marker event listeners
        sb.AppendLine("marker.addEventListener(\"markerFound\", function (evt) {");
        sb.AppendLine("markerFound = 1;");
        for (int i = 0; i < imageTarget.childCount; i++)
        {
            GameObject childToAdd = imageTarget.GetChild(i).gameObject;
            string     id         = childToAdd.name + "_" + i;

            if (childToAdd.tag == "Video")
            {
                string lineToAppend = id + ".play();";
                sb.AppendLine(lineToAppend);
            }
        }
        sb.AppendLine("});");
        sb.AppendLine("marker.addEventListener(\"markerLost\", function (evt) {");
        sb.AppendLine("markerFound = 0;");
        for (int i = 0; i < imageTarget.childCount; i++)
        {
            GameObject childToAdd = imageTarget.GetChild(i).gameObject;
            string     id         = childToAdd.name + "_" + i;

            if (childToAdd.tag == "Video")
            {
                string lineToAppend = id + ".pause();";
                sb.AppendLine(lineToAppend);
            }
        }
        sb.AppendLine("});");
        //end marker event listeners
        for (int i = 0; i < imageTarget.childCount; i++)
        {
            GameObject childToAdd = imageTarget.GetChild(i).gameObject;
            string     id         = childToAdd.name + "_" + i;

            if (childToAdd.GetComponent <ButtonHelper>() != null)
            {
                sb.AppendLine(id + @".addEventListener(""mousedown"", function(evt){");
                sb.AppendLine(@"open(""" + childToAdd.GetComponent <ButtonHelper>().URL + @""");");
                sb.AppendLine("});");
            }
            if (childToAdd.tag == "Video")
            {
                //string lineToAppend = "marker.addEventListener(\"markerFound\", function (evt) {\n" +
                //id + ".play();\n" +
                //"});\n" +
                //"marker.addEventListener(\"markerLost\", function (evt) {\n" +
                //id + ".pause();\n" +
                //"});";

                string secondLine = "button.addEventListener(\"click\", function(evt){\n" +
                                    "console.log(\"button clicked\")\n" +
                                    "if(" + id + ".muted==true){\n" +
                                    "button.innerHTML=\"Mute\";\n" +
                                    id + ".muted=false;\n" +
                                    "}else{\n" +
                                    "button.innerHTML=\"Unmute\";\n" +
                                    id + ".muted=true;\n" +
                                    "}\n" +
                                    "});";


                //sb.AppendLine(lineToAppend);
                sb.AppendLine(secondLine);
            }
        }
        //end marker event listeners

        sb.AppendLine(HtmlStrings.fullscreenButtonActionHTML);
        sb.AppendLine("},");
        //BEGIN: Tick function for bezier animations
        sb.AppendLine("tick: function (totalTime, deltaTime) {");
        for (int i = 0; i < imageTarget.childCount; i++)
        {
            GameObject childToAdd = imageTarget.GetChild(i).gameObject;
            string     id         = childToAdd.name + "_" + i;
            Bezier     bez        = childToAdd.GetComponentInChildren <Bezier>();
            if (bez != null)
            {
                sb.AppendLine($"var {id} = document.querySelector(\"#{id}\");");
                sb.AppendLine($"var {id}_Speed = {bez.speed/60};");
                sb.AppendLine($"var {id}_Time = (totalTime - {id}_SubtractTime) / 1000;");
            }
        }
        //sb.AppendLine("var time = (totalTime - subtractTime) / 1000;");
        sb.AppendLine("var dTime = deltaTime / 1000;");
        sb.AppendLine("");
        sb.AppendLine("if (markerFound == 1) {");
        for (int i = 0; i < imageTarget.childCount; i++)
        {
            GameObject childToAdd = imageTarget.GetChild(i).gameObject;
            string     id         = childToAdd.name + "_" + i;
            Bezier     bez        = childToAdd.GetComponentInChildren <Bezier>();
            if (bez != null)
            {
                sb.AppendLine($"{id}_Update();");
            }
        }
        sb.AppendLine("}");
        sb.AppendLine();
        for (int i = 0; i < imageTarget.childCount; i++)
        {
            GameObject childToAdd = imageTarget.GetChild(i).gameObject;
            string     id         = childToAdd.name + "_" + i;
            Bezier     bez        = childToAdd.GetComponentInChildren <Bezier>();
            if (bez != null)
            {
                sb.AppendLine(HtmlStrings.getBezierPathWithId(id));
            }
        }

        sb.AppendLine(HtmlStrings.bezierCurveFunctions);
        //END: Tick function for bezier animations
        sb.AppendLine("});");
        sb.AppendLine("</script>");
        sb.AppendLine("<!-- END: Unity Compiled Events -->");
        sb.AppendLine("");
        #endregion Unity Compiled Events

        //MiddleHTML
        sb.AppendLine("<!-- BEGIN: Middle HTML -->");
        sb.AppendLine(HtmlStrings.bodyHtml);
        if (hasVideo)
        {
            sb.AppendLine(HtmlStrings.buttonHTML);
        }
        sb.AppendLine(HtmlStrings.fullscreenButtonHTML);
        sb.AppendLine(HtmlStrings.middleHTML);
        sb.AppendLine("<!-- END: Middle HTML -->");
        sb.AppendLine("");

        #region Unity Compiled Assets
        sb.AppendLine("<!-- BEGIN: Unity Compiled Assets -->");
        sb.AppendLine("<a-assets>");
        for (int i = 0; i < imageTarget.childCount; i++)
        {
            GameObject childToAdd = imageTarget.GetChild(i).gameObject;
            if (childToAdd.tag == "Video")
            {
                VideoPlayer player      = childToAdd.GetComponentInChildren <VideoPlayer>();
                string      location    = player.clip.originalPath;
                string[]    splitName   = location.Split('/');
                string      videoName   = splitName[splitName.Length - 1];
                string      destination = folderPath + "videos/" + videoName;
                if (!Directory.Exists(folderPath + "videos/"))
                {
                    Directory.CreateDirectory(folderPath + "videos/");
                }
                if (File.Exists(destination))
                {
                    File.Delete(destination);
                }
                File.Copy(location, destination);
                sb.AppendLine($"<video id=\"{childToAdd.name + "_Asset_" + i}\" autoplay=\"false\" loop crossorigin=\"anonymous\" src=\"videos/{videoName}\" webkit-playsinline playsinline controls muted></video>");
            }

            if (childToAdd.tag == "Model")
            {
                string modelID     = childToAdd.name.ToLower() + "_" + i;
                string textureName = childToAdd.GetComponentInChildren <MeshRenderer>().sharedMaterial.mainTexture.name;
                Model  newModel    = new Model();
                newModel.initialize();
                newModel.setPropertyValues(childToAdd, textureName, modelID);
                newModel.setObjectModelString(i);
                sb.AppendLine(newModel.getAssetString(folderPath, i));
            }
        }
        sb.AppendLine("</a-assets>");
        sb.AppendLine("<!-- END: Unity Compiled Assets -->");
        #endregion Unity Compiled Assets

        sb.AppendLine("<!-- BEGIN: Add Image Target (marker) -->");
        sb.AppendLine(HtmlStrings.getTopMarkerHtml(isNft));
        sb.AppendLine("<!-- END: Add Image Target (marker) -->");
        sb.AppendLine("");

        #region Unity Compiled Objects
        sb.AppendLine("<!-- BEGIN: Unity Compiled Objects -->");
        //Adds in the physical object for each child of the ImageTarget
        for (int i = 0; i < imageTarget.childCount; i++)
        {
            GameObject childToAdd    = imageTarget.GetChild(i).gameObject;
            Texture2D  objectTexture = (Texture2D)childToAdd.GetComponentInChildren <MeshRenderer>().sharedMaterial.mainTexture;
            string     textureName   = null;
            string     transparency  = "false";
            if (objectTexture != null && childToAdd.tag != "Model")
            {
                textureName = objectTexture.name;
                byte[] bytes = objectTexture.EncodeToPNG();
                if (!Directory.Exists(folderPath + "textures/"))
                {
                    Directory.CreateDirectory(folderPath + "textures/");
                }
                File.WriteAllBytes(folderPath + "textures/" + textureName + ".png", bytes);
                transparency = "true";
            }


            switch (childToAdd.tag)
            {
            case "Plane":
                string       planeID = childToAdd.name.ToLower() + "_" + i;
                string       planeAnimationFilePath = Application.dataPath + "/Animations/JsonExports/" + SceneManager.GetActiveScene().name + "/" + planeID + ".txt";
                KeyFrameList planeKeyList           = null;
                if (Directory.Exists(planeAnimationFilePath))
                {
                    string planeAnimationFile = File.ReadAllText(planeAnimationFilePath);
                    planeKeyList = JsonUtility.FromJson <KeyFrameList>(planeAnimationFile);
                }

                Plane newPlane = new Plane();
                newPlane.initialize();
                newPlane.setPropertyValues(childToAdd, textureName, planeID);
                sb.AppendLine(newPlane.getHtmlString(planeKeyList));
                break;

            case "Video":
                string       videoID = childToAdd.name.ToLower() + "_" + i;
                string       videoAnimationFilePath = Application.dataPath + "/Animations/JsonExports/" + SceneManager.GetActiveScene().name + "/" + videoID + ".txt";
                KeyFrameList videoKeyList           = null;
                if (Directory.Exists(videoAnimationFilePath))
                {
                    string videoAnimationFile = File.ReadAllText(videoAnimationFilePath);
                    videoKeyList = JsonUtility.FromJson <KeyFrameList>(videoAnimationFile);
                }

                Video newVideo = new Video();
                newVideo.initialize();
                newVideo.setPropertyValues(childToAdd, textureName, videoID);
                newVideo._src = "#" + childToAdd.name + "_Asset_" + i;
                sb.AppendLine(newVideo.getHtmlString(videoKeyList));
                break;

            case "Cube":
                string       cubeID = childToAdd.name.ToLower() + "_" + i;
                string       cubeAnimationFilePath = Application.dataPath + "/Animations/JsonExports/" + SceneManager.GetActiveScene().name + "/" + cubeID + ".txt";
                KeyFrameList cubeKeyList           = null;
                if (Directory.Exists(cubeAnimationFilePath))
                {
                    string cubeAnimationFile = File.ReadAllText(cubeAnimationFilePath);
                    cubeKeyList = JsonUtility.FromJson <KeyFrameList>(cubeAnimationFile);
                }

                Cube newCube = new Cube();
                newCube.initialize();
                newCube.setPropertyValues(childToAdd, textureName, cubeID);
                sb.AppendLine(newCube.getHtmlString(cubeKeyList));
                break;

            case "Model":
                string       modelID = childToAdd.name.ToLower() + "_" + i;
                string       modelAnimationFilePath = Application.dataPath + "/Animations/JsonExports/" + SceneManager.GetActiveScene().name + "/" + modelID + ".txt";
                KeyFrameList modelKeyList           = null;
                if (Directory.Exists(modelAnimationFilePath))
                {
                    string modelAnimationFile = File.ReadAllText(modelAnimationFilePath);
                    modelKeyList = JsonUtility.FromJson <KeyFrameList>(modelAnimationFile);
                }

                Model newModel = new Model();
                newModel.initialize();
                newModel.setPropertyValues(childToAdd, textureName, modelID);
                newModel.setObjectModelString(i);
                string modelLineToAppend = newModel.getHtmlString(modelKeyList);
                Debug.Log(modelLineToAppend);
                sb.AppendLine(modelLineToAppend);

                break;

            case "Sphere":
                string       shpereID = childToAdd.name.ToLower() + "_" + i;
                string       sphereAnimationFilePath = Application.dataPath + "/Animations/JsonExports/" + SceneManager.GetActiveScene().name + "/" + shpereID + ".txt";
                KeyFrameList sphereKeyList           = null;
                if (Directory.Exists(sphereAnimationFilePath))
                {
                    string sphereAnimationFile = File.ReadAllText(sphereAnimationFilePath);
                    sphereKeyList = JsonUtility.FromJson <KeyFrameList>(sphereAnimationFile);
                }

                Sphere newSphere = new Sphere();
                newSphere.initialize();
                newSphere.setPropertyValues(childToAdd, textureName, shpereID);
                sb.AppendLine(newSphere.getHtmlString(sphereKeyList));
                break;

            case "Cylinder":
                string       cylinderID = childToAdd.name.ToLower() + "_" + i;
                string       cylinderAnimationFilePath = Application.dataPath + "/Animations/JsonExports/" + SceneManager.GetActiveScene().name + "/" + cylinderID + ".txt";
                KeyFrameList cylinderKeyList           = null;
                if (Directory.Exists(cylinderAnimationFilePath))
                {
                    string cylinderAnimationFile = File.ReadAllText(cylinderAnimationFilePath);
                    cylinderKeyList = JsonUtility.FromJson <KeyFrameList>(cylinderAnimationFile);
                }

                Cylinder newCylinder = new Cylinder();
                newCylinder.initialize();
                newCylinder.setPropertyValues(childToAdd, textureName, cylinderID);
                sb.AppendLine(newCylinder.getHtmlString(cylinderKeyList));
                break;

            default:

                break;
            }
        }

        sb.AppendLine("<!-- END: Unity Compiled Objects -->");
        #endregion Unity Compiled Objects

        sb.AppendLine("");
        sb.AppendLine("<!-- BEGIN: Bottom HTML -->");
        sb.Append(HtmlStrings.getBottomMarkerHtml(isNft));
        sb.AppendLine("<!-- END: Bottom HTML -->");

        File.WriteAllText(folderPath + fileName, sb.ToString());
        Debug.Log("index file successfully created");
        AssetDatabase.Refresh();
    }
Пример #9
0
    static void CompileFileHTML()
    {
        string folderPath = GameObject.FindWithTag("ImageTarget").GetComponent <ImageTarget>().destination;

        if (!Directory.Exists(folderPath))
        {
            Directory.CreateDirectory(folderPath);
        }
        if (!File.Exists("Assets/AR.js-master/aframe/fullscreen.png"))
        {
            File.Copy("Assets/ARjs_Unity/Icons/fullscreen.png", "Assets/AR.js-master/aframe/fullscreen.png");
        }
        if (!File.Exists("Assets/AR.js-master/aframe/exit_fullscreen.png"))
        {
            File.Copy("Assets/ARjs_Unity/Icons/exit_fullscreen.png", "Assets/AR.js-master/aframe/exit_fullscreen.png");
        }
        string fileName = "index.html";
        bool   hasVideo = false;

        #region HTML Strings
        string aframeString               = "<script src=\"https://aframe.io/releases/0.9.2/aframe.min.js\"></script>";
        string topHTML                    = $"<!DOCTYPE html>\n<!-- include aframe -->\n{aframeString}\n<!-- include ar.js -->\n<script src=\"https://cdn.rawgit.com/jeromeetienne/AR.js/1.7.2/aframe/build/aframe-ar.js\"></script>\n\n<!-- to load .ply model -->\n<script src=\"https://rawgit.com/donmccurdy/aframe-extras/v6.0.0/dist/aframe-extras.loaders.min.js\"></script>\n\n";
        string bodyHtml                   = @"<body style='margin : 0px; overflow: hidden; font-family: Monospace;'>";
        string middleHTML                 = @"<!-- <a-scene embedded arjs='debugUIEnabled: false; sourceType: video; sourceUrl:../../data/videos/headtracking.mp4;'> -->
    <a-scene embedded arjs='debugUIEnabled: false; sourceType: webcam' vr-mode-ui='enabled: false'>
    <a-entity id=""mouseCursor"" cursor=""rayOrigin: mouse"" raycaster=""objects: .intersectable; useWorldCoordinates: true;""></a-entity>";
        string buttonHTML                 = "<div style='position: absolute; bottom: 10px; right: 30px; width:100%; text-align: center; z-index: 1;'>\n      <button id=\"mutebutton\" style='position: absolute; bottom: 10px'>\n          Unmute\n      </button>\n  </div>";
        string fullscreenButtonHTML       = "<div style='position: absolute; bottom: 5px; left: 30px; width:100%; text-align: right; z-index: 1;'>\n        <input type=\"image\" id=\"fullscreen\" src=\"../fullscreen.png\" style='position: absolute; bottom: 0px; right: 35px;'>\n        </input>\n    </div>";
        string fullscreenButtonActionHTML = "fullbutton.addEventListener(\"click\", function (evt) {\n                if (fullscreen == 0) {\n                    if (elem.requestFullscreen) {\n                        elem.requestFullscreen();\n                    } else if (elem.mozRequestFullScreen) {\n                        /* Firefox */\n                        elem.mozRequestFullScreen();\n                    } else if (elem.webkitRequestFullscreen) {\n                        /* Chrome, Safari and Opera */\n                        elem.webkitRequestFullscreen();\n                    } else if (elem.msRequestFullscreen) {\n                        /* IE/Edge */\n                        elem.msRequestFullscreen();\n                    }\n                    fullbutton.setAttribute(\"src\", \"../exit_fullscreen.png\");\n                    fullscreen = 1;\n                } else {\n                    if (document.exitFullscreen) {\n                        document.exitFullscreen();\n                    } else if (document.webkitExitFullscreen) {\n                        document.webkitExitFullscreen();\n                    } else if (document.mozCancelFullScreen) {\n                        document.mozCancelFullScreen();\n                    } else if (document.msExitFullscreen) {\n                        document.msExitFullscreen();\n                    }\n                    fullbutton.setAttribute(\"src\", \"../fullscreen.png\");\n                    fullscreen = 0;\n                }\n\n            });";
        string patternName                = GameObject.FindWithTag("ImageTarget").GetComponent <ImageTarget>().patternName;
        string presetText                 = $"preset=\"hiro\" emitevents=\"true\" button";
        if (patternName != "default")
        {
            presetText = $"type=\"pattern\" preset=\"custom\" src=\"{patternName}\" url=\"{patternName}\" emitevents=\"true\" button";
        }
        string markerHTML = "<a-marker id=\"marker\" " + presetText + ">";
        string bottomHTML = @"</a-marker>
        <a-entity camera></a-entity>
        </a-scene>
</body>
</html>";
        #endregion

        StringBuilder sb = new StringBuilder();
        #region Top HTML
        sb.AppendLine("<!-- BEGIN: Top HTML -->");
        sb.Append(topHTML);
        sb.AppendLine("<!-- END: Top HTML -->");
        #endregion Top HTML

        Transform imageTarget = GameObject.FindGameObjectWithTag("ImageTarget").transform;
        if (imageTarget == null)
        {
            Debug.Log("AR.js error: There is no Image Target to Compile");
            return;
        }

        #region Unity Compiled Events
        //Adds in the actions of the children to javascript.
        sb.AppendLine("<!-- BEGIN: Unity Compiled Events -->");
        sb.AppendLine("<script>");

        //GLOBALS FOR ANIMATION UPDATE
        sb.AppendLine("var markerFound = 0;");
        bool hasBezier = false;
        for (int i = 0; i < imageTarget.childCount; i++)
        {
            GameObject childToAdd = imageTarget.GetChild(i).gameObject;
            for (int j = 0; j < childToAdd.transform.childCount; j++)
            {
                if (childToAdd.transform.GetChild(j).name.ToLower().Contains("bezier"))
                {
                    hasBezier = true;
                }
            }
        }
        if (hasBezier)
        {
            //sb.AppendLine("var subtractTime = 0;");
            for (int i = 0; i < imageTarget.childCount; i++)
            {
                GameObject childToAdd = imageTarget.GetChild(i).gameObject;
                string     childID    = childToAdd.name + "_" + i;
                Bezier     bez        = childToAdd.GetComponentInChildren <Bezier>();
                if (bez != null)
                {
                    sb.AppendLine("var " + childID + "_CurrentPoint = 0;");
                    sb.AppendLine("var " + childID + "_SubtractTime = 0;");
                    sb.AppendLine("var " + childID + "_PointsArray = " + bez.PointsListString() + ";");
                }
            }
        }
        //END GLOBALS FOR ANIMATION UPDATE

        sb.AppendLine("AFRAME.registerComponent('button', {");
        sb.AppendLine("init: function () {");
        sb.AppendLine($"var elem = document.documentElement;");
        sb.AppendLine($"var marker = document.querySelector(\"#marker\");");
        sb.AppendLine($"var fullbutton = document.querySelector(\"#fullscreen\");");
        for (int i = 0; i < imageTarget.childCount; i++)
        {
            GameObject childToAdd = imageTarget.GetChild(i).gameObject;
            if (childToAdd.tag == "Video")
            {
                hasVideo = true;
            }
        }
        if (hasVideo)
        {
            sb.AppendLine($"var button = document.querySelector(\"#mutebutton\");");
        }

        for (int i = 0; i < imageTarget.childCount; i++)
        {
            GameObject childToAdd = imageTarget.GetChild(i).gameObject;
            string     id         = childToAdd.name + "_" + i;
            if (childToAdd.GetComponent <ButtonHelper>() != null)
            {
                sb.AppendLine($"var {id} = document.querySelector(\"#{id}\");");
            }

            if (childToAdd.tag == "Video")
            {
                hasVideo = true;
                sb.AppendLine($"var {id} = document.querySelector(\"#{childToAdd.name + "_Asset_" + i}\");");
            }
        }
        //marker event listeners
        sb.AppendLine("marker.addEventListener(\"markerFound\", function (evt) {");
        sb.AppendLine("markerFound = 1;");
        for (int i = 0; i < imageTarget.childCount; i++)
        {
            GameObject childToAdd = imageTarget.GetChild(i).gameObject;
            string     id         = childToAdd.name + "_" + i;

            if (childToAdd.tag == "Video")
            {
                string lineToAppend = id + ".play();";
                sb.AppendLine(lineToAppend);
            }
        }
        sb.AppendLine("});");
        sb.AppendLine("marker.addEventListener(\"markerLost\", function (evt) {");
        sb.AppendLine("markerFound = 0;");
        for (int i = 0; i < imageTarget.childCount; i++)
        {
            GameObject childToAdd = imageTarget.GetChild(i).gameObject;
            string     id         = childToAdd.name + "_" + i;

            if (childToAdd.tag == "Video")
            {
                string lineToAppend = id + ".pause();";
                sb.AppendLine(lineToAppend);
            }
        }
        sb.AppendLine("});");
        //end marker event listeners
        for (int i = 0; i < imageTarget.childCount; i++)
        {
            GameObject childToAdd = imageTarget.GetChild(i).gameObject;
            string     id         = childToAdd.name + "_" + i;

            if (childToAdd.GetComponent <ButtonHelper>() != null)
            {
                sb.AppendLine(@"open(""" + childToAdd.GetComponent <ButtonHelper>().URL + @""");");
                sb.AppendLine(id + @".addEventListener(""mousedown"", function(evt){");
                sb.AppendLine("});");
            }
            if (childToAdd.tag == "Video")
            {
                //string lineToAppend = "marker.addEventListener(\"markerFound\", function (evt) {\n" +
                //id + ".play();\n" +
                //"});\n" +
                //"marker.addEventListener(\"markerLost\", function (evt) {\n" +
                //id + ".pause();\n" +
                //"});";

                string secondLine = "button.addEventListener(\"click\", function(evt){\n" +
                                    "console.log(\"button clicked\")\n" +
                                    "if(" + id + ".muted==true){\n" +
                                    "button.innerHTML=\"Mute\";\n" +
                                    id + ".muted=false;\n" +
                                    "}else{\n" +
                                    "button.innerHTML=\"Unmute\";\n" +
                                    id + ".muted=true;\n" +
                                    "}\n" +
                                    "});";


                //sb.AppendLine(lineToAppend);
                sb.AppendLine(secondLine);
            }
        }
        //end marker event listeners

        sb.AppendLine(fullscreenButtonActionHTML);
        sb.AppendLine("},");
        //BEGIN: Tick function for bezier animations
        sb.AppendLine("tick: function (totalTime, deltaTime) {");
        for (int i = 0; i < imageTarget.childCount; i++)
        {
            GameObject childToAdd = imageTarget.GetChild(i).gameObject;
            string     id         = childToAdd.name + "_" + i;
            Bezier     bez        = childToAdd.GetComponentInChildren <Bezier>();
            if (bez != null)
            {
                sb.AppendLine($"var {id} = document.querySelector(\"#{id}\");");
                sb.AppendLine($"var {id}_Speed = {bez.speed/60};");
                sb.AppendLine($"var {id}_Time = (totalTime - {id}_SubtractTime) / 1000;");
            }
        }
        //sb.AppendLine("var time = (totalTime - subtractTime) / 1000;");
        sb.AppendLine("var dTime = deltaTime / 1000;");
        sb.AppendLine("");
        sb.AppendLine("if (markerFound == 1) {");
        for (int i = 0; i < imageTarget.childCount; i++)
        {
            GameObject childToAdd = imageTarget.GetChild(i).gameObject;
            string     id         = childToAdd.name + "_" + i;
            Bezier     bez        = childToAdd.GetComponentInChildren <Bezier>();
            if (bez != null)
            {
                sb.AppendLine($"{id}_Update();");
            }
        }
        sb.AppendLine("}");
        sb.AppendLine();
        for (int i = 0; i < imageTarget.childCount; i++)
        {
            GameObject childToAdd = imageTarget.GetChild(i).gameObject;
            string     id         = childToAdd.name + "_" + i;
            Bezier     bez        = childToAdd.GetComponentInChildren <Bezier>();
            if (bez != null)
            {
                sb.AppendLine($"function {id}_Update()" + " {");
                sb.AppendLine($"var newPosition = bezierPath({id}_PointsArray[{id}_CurrentPoint], {id}_PointsArray[{id}_CurrentPoint + 1], { id}_PointsArray[{ id}_CurrentPoint + 2], { id}_PointsArray[{ id}_CurrentPoint + 3], {id}_Time *{ id}_Speed);");
                sb.AppendLine();
                sb.AppendLine($"if ({id}_Time*{id}_Speed>1) " + "{");
                sb.AppendLine($"{id}_CurrentPoint += 3;");
                sb.AppendLine($"{id}_SubtractTime = totalTime;");
                sb.AppendLine($"if ({id}_CurrentPoint >= {id}_PointsArray.length - 3) " + "{");
                sb.AppendLine($"{id}_CurrentPoint = 0;");
                sb.AppendLine("}");
                sb.AppendLine("}");
                sb.AppendLine();
                sb.AppendLine($"{id}.setAttribute('position', " + "{");
                sb.AppendLine("x: newPosition.x,");
                sb.AppendLine("y: newPosition.y,");
                sb.AppendLine("z: newPosition.z,");
                sb.AppendLine("});");
                sb.AppendLine("}");
            }
        }

        sb.AppendLine("function bezierEvaluate(p0, p1, p2, p3, t) {\n                " +
                      "var u = (1 - t);\n                " +
                      "var uu = u * u;\n                " +
                      "var uuu = u * u * u;\n                " +
                      "var tt = t * t;\n                " +
                      "var ttt = t * t * t;\n                " +
                      "//B(t) = (1-t)^3*P0 + 3*(1-t)^2*t*P1 + 3*(1-t)*t^2*P2 + t^3*P3 , 0 < t < 1\n                " +
                      "return (uuu * p0 + 3 * uu * t * p1 + 3 * u * tt * p2 + ttt * p3);\n\n            " +
                      "}\n           " +
                      "function bezierPath(p0, p1, p2, p3, t) {\n                " +
                      "return new THREE.Vector3(\n                    " +
                      "bezierEvaluate(p0.x, p1.x, p2.x, p3.x, t),\n                    " +
                      "bezierEvaluate(p0.y, p1.y, p2.y, p3.y, t),\n                    " +
                      "bezierEvaluate(p0.z, p1.z, p2.z, p3.z, t)\n                " +
                      ");\n            " +
                      "}\n\n        " +
                      "}");
        //END: Tick function for bezier animations
        sb.AppendLine("});");
        sb.AppendLine("</script>");
        sb.AppendLine("<!-- END: Unity Compiled Events -->");
        sb.AppendLine("");
        #endregion Unity Compiled Events

        //MiddleHTML
        sb.AppendLine("<!-- BEGIN: Middle HTML -->");
        sb.AppendLine(bodyHtml);
        if (hasVideo)
        {
            sb.AppendLine(buttonHTML);
        }
        sb.AppendLine(fullscreenButtonHTML);
        sb.AppendLine(middleHTML);
        sb.AppendLine("<!-- END: Middle HTML -->");
        sb.AppendLine("");

        #region Unity Compiled Assets
        sb.AppendLine("<!-- BEGIN: Unity Compiled Assets -->");
        sb.AppendLine("<a-assets>");
        for (int i = 0; i < imageTarget.childCount; i++)
        {
            GameObject childToAdd = imageTarget.GetChild(i).gameObject;
            if (childToAdd.tag == "Video")
            {
                VideoPlayer player      = childToAdd.GetComponentInChildren <VideoPlayer>();
                string      location    = player.clip.originalPath;
                string[]    splitName   = location.Split('/');
                string      videoName   = splitName[splitName.Length - 1];
                string      destination = folderPath + "videos/" + videoName;
                if (!Directory.Exists(folderPath + "videos/"))
                {
                    Directory.CreateDirectory(folderPath + "videos/");
                }
                if (File.Exists(destination))
                {
                    File.Delete(destination);
                }
                File.Copy(location, destination);
                sb.AppendLine($"<video id=\"{childToAdd.name + "_Asset_" + i}\" autoplay=\"false\" loop crossorigin=\"anonymous\" src=\"videos/{videoName}\" webkit-playsinline playsinline controls muted></video>");
            }

            if (childToAdd.tag == "Model")
            {
                if (!Directory.Exists(folderPath + "models/"))
                {
                    Directory.CreateDirectory(folderPath + "models/");
                }
                CustomModelHelper modelHelper = childToAdd.GetComponent <CustomModelHelper>();
                if (File.Exists(folderPath + "models/" + modelHelper.objName))
                {
                    sb.AppendLine($"<a-asset-item id=\"{childToAdd.name + "_Asset_obj_" + i}\" src=\"models/{modelHelper.objName}\"></a-asset-item>");
                }
                else
                {
                    Debug.LogError($"The model file {modelHelper.objName} doesn't seem to exist in the proper location.");
                }
                if (File.Exists(folderPath + "models/" + modelHelper.mtlName))
                {
                    sb.AppendLine($"<a-asset-item id=\"{childToAdd.name + "_Asset_mtl_" + i}\" src=\"models/{modelHelper.mtlName}\"></a-asset-item>");
                }
                else
                {
                    Debug.LogWarning("The object doesn't have a material.");
                }
            }
        }
        sb.AppendLine("</a-assets>");
        sb.AppendLine("<!-- END: Unity Compiled Assets -->");
        #endregion Unity Compiled Assets

        sb.AppendLine("<!-- BEGIN: Add Image Target (marker) -->");
        sb.AppendLine(markerHTML);
        sb.AppendLine("<!-- END: Add Image Target (marker) -->");
        sb.AppendLine("");

        #region Unity Compiled Objects
        sb.AppendLine("<!-- BEGIN: Unity Compiled Objects -->");
        //Adds in the physical object for each child of the ImageTarget
        for (int i = 0; i < imageTarget.childCount; i++)
        {
            GameObject childToAdd    = imageTarget.GetChild(i).gameObject;
            Texture2D  objectTexture = (Texture2D)childToAdd.GetComponentInChildren <MeshRenderer>().sharedMaterial.mainTexture;
            string     textureName   = null;
            bool       transparency  = false;
            if (objectTexture != null && childToAdd.tag != "Model")
            {
                textureName = objectTexture.name;
                byte[] bytes = objectTexture.EncodeToPNG();
                if (!Directory.Exists(folderPath + "textures/"))
                {
                    Directory.CreateDirectory(folderPath + "textures/");
                }
                File.WriteAllBytes(folderPath + "textures/" + textureName + ".png", bytes);
                transparency = true;
            }
            switch (childToAdd.tag)
            {
            case "Plane":
                var Plane = (width : childToAdd.transform.localScale.x, height : childToAdd.transform.localScale.y,
                             position : -childToAdd.transform.localPosition.x / 10 + " " + childToAdd.transform.localPosition.y / 10 + " " + childToAdd.transform.localPosition.z / 10,
                             rotation : childToAdd.transform.localEulerAngles.x + " " + -childToAdd.transform.localEulerAngles.y + " " + -childToAdd.transform.localEulerAngles.z,
                             color : "#" + ColorUtility.ToHtmlStringRGB(childToAdd.GetComponentInChildren <MeshRenderer>().sharedMaterial.color),
                             src : textureName != null ? "textures/" + textureName + ".png" : "");
                sb.AppendLine($"<a-plane src=\"{Plane.src}\" id=\"{childToAdd.name + "_" + i}\" class=\"intersectable\" width=\"{Plane.width}\" height=\"{Plane.height}\" position=\"{Plane.position}\" rotation=\"{Plane.rotation}\" color=\"{Plane.color}\" transparent={transparency}");

                string planeID = childToAdd.name.ToLower() + "_" + i;
                if (childToAdd.GetComponent <AnimationHelper>() != null)
                {
                    string       animationFile = File.ReadAllText(Application.dataPath + "/Animations/JsonExports/" + SceneManager.GetActiveScene().name + "/" + planeID + ".txt");
                    KeyFrameList keyList       = JsonUtility.FromJson <KeyFrameList>(animationFile);

                    foreach (WeldonKeyFrame frame in keyList.frameList)
                    {
                        int            index = keyList.frameList.FindIndex(obj => obj == frame);
                        string         loopTrueString = "";
                        string         animTrigger = "";
                        string         posFrom = "", rotFrom = "", widthFrom = "", heightFrom = "";
                        WeldonKeyFrame prevFrame = new WeldonKeyFrame();
                        if (index > 0)
                        {
                            prevFrame  = keyList.frameList[index - 1];
                            posFrom    = $"from: {-prevFrame.posX / 10} {prevFrame.posY / 10} {prevFrame.posZ / 10};";
                            rotFrom    = $"from: {prevFrame.rotX} {-prevFrame.rotY} {-prevFrame.rotZ};";
                            widthFrom  = $"from: {prevFrame.scalX};";
                            heightFrom = $"from: {prevFrame.scalY};";

                            animTrigger = $"startEvents: animationcomplete__{planeID}_f{index-1}" + ((index == 1 && childToAdd.GetComponent <AnimationHelper>().loop)? $", animationcomplete__{planeID}_f{keyList.frameList.Count-1};" : ";");
                        }
                        else
                        {
                            if (childToAdd.GetComponent <AnimationHelper>().onClick)
                            {
                                animTrigger = $"startEvents: mousedown;";
                            }
                        }

                        string posTo    = $"to: {-frame.posX / 10} {frame.posY / 10} {frame.posZ / 10};",
                               rotTo    = $"to: {frame.rotX} {-frame.rotY} {-frame.rotZ};",
                               widthTo  = $"to: {frame.scalX};",
                               heightTo = $"to: {frame.scalY};";

                        //if (childToAdd.GetComponent<AnimationHelper>().loop) loopTrueString = $"repeat = \"indefinite\"";
                        bool isFirstFrame = prevFrame.time.Equals(-1) ? true : false;
                        if (isFirstFrame)
                        {
                            prevFrame.time = 0;
                        }
                        if (frame.IsDifferentPosition(prevFrame) || isFirstFrame)
                        {
                            sb.AppendLine($"animation__{planeID}_f{index}=\" property: position; {posFrom} {posTo} dur: {(frame.time - prevFrame.time) * 1000}; easing: linear; {animTrigger}\"");
                        }
                        if (frame.IsDifferentRotation(prevFrame) || isFirstFrame)
                        {
                            sb.AppendLine($"animation__{planeID}_f{index}=\" property: rotation; {rotFrom} {rotTo} dur: {(frame.time - prevFrame.time) * 1000}; easing: linear; {animTrigger}\"");
                        }
                        if (frame.IsDifferentWidth(prevFrame) || isFirstFrame)
                        {
                            sb.AppendLine($"animation__{planeID}_f{index}=\" property: width; {widthFrom} {widthTo} dur: {(frame.time - prevFrame.time) * 1000}; easing: linear; {animTrigger}\"");
                        }
                        if (frame.IsDifferentHeight(prevFrame) || isFirstFrame)
                        {
                            sb.AppendLine($"animation__{planeID}_f{index}=\" property: height; {heightFrom} {heightTo} dur: {(frame.time - prevFrame.time) * 1000}; easing: linear; {animTrigger}\"");
                        }
                    }
                }
                sb.AppendLine("></a-plane>");
                break;

            case "Video":
                string videoID = childToAdd.name.ToLower() + "_" + i;
                var    Video   = (width: childToAdd.transform.localScale.x, height : childToAdd.transform.localScale.y,
                                  position : -childToAdd.transform.localPosition.x / 10 + " " + childToAdd.transform.localPosition.y / 10 + " " + childToAdd.transform.localPosition.z / 10,
                                  rotation : childToAdd.transform.localEulerAngles.x + " " + -childToAdd.transform.localEulerAngles.y + " " + -childToAdd.transform.localEulerAngles.z,
                                  color : "#" + ColorUtility.ToHtmlStringRGB(childToAdd.GetComponentInChildren <MeshRenderer>().sharedMaterial.color),
                                  src : "#" + childToAdd.name + "_Asset_" + i);
                sb.AppendLine($"<a-video src=\"{Video.src}\" id=\"{childToAdd.name + "_" + i}\" class=\"intersectable\" width=\"{Video.width}\" height=\"{Video.height}\" position=\"{Video.position}\" rotation=\"{Video.rotation}\" color=\"{Video.color}\" transparent={transparency}");

                if (childToAdd.GetComponent <AnimationHelper>() != null)
                {
                    string       animationFile = File.ReadAllText(Application.dataPath + "/Animations/JsonExports/" + SceneManager.GetActiveScene().name + "/" + videoID + ".txt");
                    KeyFrameList keyList       = JsonUtility.FromJson <KeyFrameList>(animationFile);

                    foreach (WeldonKeyFrame frame in keyList.frameList)
                    {
                        int            index = keyList.frameList.FindIndex(obj => obj == frame);
                        string         loopTrueString = "";
                        string         animTrigger = "";
                        string         posFrom = "", rotFrom = "", widthFrom = "", heightFrom = "";
                        WeldonKeyFrame prevFrame = new WeldonKeyFrame();
                        if (index > 0)
                        {
                            prevFrame  = keyList.frameList[index - 1];
                            posFrom    = $"from: {-prevFrame.posX / 10} {prevFrame.posY / 10} {prevFrame.posZ / 10};";
                            rotFrom    = $"from: {prevFrame.rotX} {-prevFrame.rotY} {-prevFrame.rotZ};";
                            widthFrom  = $"from: {prevFrame.scalX};";
                            heightFrom = $"from: {prevFrame.scalY};";

                            animTrigger = $"startEvents: animationcomplete__{videoID}_f{index-1}" + ((index == 1 && childToAdd.GetComponent <AnimationHelper>().loop) ? $", animationcomplete__{videoID}_f{keyList.frameList.Count - 1};" : ";");
                        }
                        else
                        {
                            if (childToAdd.GetComponent <AnimationHelper>().onClick)
                            {
                                animTrigger = $"startEvents: mousedown;";
                            }
                        }

                        string posTo    = $"to: {-frame.posX / 10} {frame.posY / 10} {frame.posZ / 10};",
                               rotTo    = $"to: {frame.rotX} {-frame.rotY} {-frame.rotZ};",
                               widthTo  = $"to: {frame.scalX};",
                               heightTo = $"to: {frame.scalY};";

                        //if (childToAdd.GetComponent<AnimationHelper>().loop) loopTrueString = $"repeat = \"indefinite\"";
                        bool isFirstFrame = prevFrame.time.Equals(-1) ? true : false;
                        if (isFirstFrame)
                        {
                            prevFrame.time = 0;
                        }
                        if (frame.IsDifferentPosition(prevFrame) || isFirstFrame)
                        {
                            sb.AppendLine($"animation__{videoID}_f{index}=\" property: position; {posFrom} {posTo} dur: {(frame.time - prevFrame.time) * 1000}; easing: linear; {animTrigger}\"");
                        }
                        if (frame.IsDifferentRotation(prevFrame) || isFirstFrame)
                        {
                            sb.AppendLine($"animation__{videoID}_f{index}=\" property: rotation; {rotFrom} {rotTo} dur: {(frame.time - prevFrame.time) * 1000}; easing: linear; {animTrigger}\"");
                        }
                        if (frame.IsDifferentWidth(prevFrame) || isFirstFrame)
                        {
                            sb.AppendLine($"animation__{videoID}_f{index}=\" property: width; {widthFrom} {widthTo} dur: {(frame.time - prevFrame.time) * 1000}; easing: linear; {animTrigger}\"");
                        }
                        if (frame.IsDifferentHeight(prevFrame) || isFirstFrame)
                        {
                            sb.AppendLine($"animation__{videoID}_f{index}=\" property: height; {heightFrom} {heightTo} dur: {(frame.time - prevFrame.time) * 1000}; easing: linear; {animTrigger}\"");
                        }
                    }
                }
                sb.AppendLine("></a-video>");
                break;

            case "Cube":
                var Cube = (width : childToAdd.transform.localScale.x / 10, height : childToAdd.transform.localScale.y / 10, depth : childToAdd.transform.localScale.z / 10,
                            position : -childToAdd.transform.localPosition.x / 10 + " " + childToAdd.transform.localPosition.y / 10 + " " + childToAdd.transform.localPosition.z / 10,
                            rotation : childToAdd.transform.localEulerAngles.x + " " + -childToAdd.transform.localEulerAngles.y + " " + -childToAdd.transform.localEulerAngles.z,
                            color : "#" + ColorUtility.ToHtmlStringRGB(childToAdd.GetComponent <MeshRenderer>().sharedMaterial.color),
                            src : textureName != null?"textures/" + textureName + ".png" : "");
                sb.AppendLine($"<a-box src=\"{Cube.src}\" id=\"{childToAdd.name + "_" + i}\" class=\"intersectable\" width=\"{Cube.width}\" height=\"{Cube.height}\" depth=\"{Cube.depth}\" position=\"{Cube.position}\" rotation=\"{Cube.rotation}\" color=\"{Cube.color}\" transparent={transparency}");

                string cubeID = childToAdd.name.ToLower() + "_" + i;

                if (childToAdd.GetComponent <AnimationHelper>() != null)
                {
                    string       animationFile = File.ReadAllText(Application.dataPath + "/Animations/JsonExports/" + SceneManager.GetActiveScene().name + "/" + cubeID + ".txt");
                    KeyFrameList keyList       = JsonUtility.FromJson <KeyFrameList>(animationFile);

                    foreach (WeldonKeyFrame frame in keyList.frameList)
                    {
                        int            index = keyList.frameList.FindIndex(obj => obj == frame);
                        string         loopTrueString = "";
                        string         animTrigger = "";
                        string         posFrom = "", rotFrom = "", widthFrom = "", heightFrom = "", depthFrom = "";
                        WeldonKeyFrame prevFrame = new WeldonKeyFrame();
                        if (index > 0)
                        {
                            prevFrame  = keyList.frameList[index - 1];
                            posFrom    = $"from: {-prevFrame.posX / 10} {prevFrame.posY / 10} {prevFrame.posZ / 10};";
                            rotFrom    = $"from: {prevFrame.rotX} {-prevFrame.rotY} {-prevFrame.rotZ};";
                            widthFrom  = $"from: {prevFrame.scalX / 10};";
                            heightFrom = $"from: {prevFrame.scalY / 10};";
                            depthFrom  = $"from: {prevFrame.scalZ / 10};";

                            animTrigger = $"startEvents: animationcomplete__{cubeID}_f{index-1}" + ((index == 1 && childToAdd.GetComponent <AnimationHelper>().loop) ? $", animationcomplete__{cubeID}_f{keyList.frameList.Count - 1};" : ";");
                        }
                        else
                        {
                            if (childToAdd.GetComponent <AnimationHelper>().onClick)
                            {
                                animTrigger = $"startEvents: mousedown;";
                            }
                        }

                        string posTo    = $"to: {-frame.posX / 10} {frame.posY / 10} {frame.posZ / 10};",
                               rotTo    = $"to: {frame.rotX} {-frame.rotY} {-frame.rotZ};",
                               widthTo  = $"to: {frame.scalX / 10};",
                               heightTo = $"to: {frame.scalY / 10};",
                               depthTo  = $"to: {frame.scalZ / 10};";

                        //if (childToAdd.GetComponent<AnimationHelper>().loop) loopTrueString = $"repeat = \"indefinite\"";
                        bool isFirstFrame = prevFrame.time.Equals(-1) ? true : false;
                        if (isFirstFrame)
                        {
                            prevFrame.time = 0;
                        }
                        if (frame.IsDifferentPosition(prevFrame) || isFirstFrame)
                        {
                            sb.AppendLine($"animation__{cubeID}_f{index}=\"property: position; {posFrom} {posTo} dur: {(frame.time-prevFrame.time)*1000}; easing: linear; {animTrigger}\"");
                        }
                        if (frame.IsDifferentRotation(prevFrame) || isFirstFrame)
                        {
                            sb.AppendLine($"animation__{cubeID}_f{index}=\"property: rotation; {rotFrom} {rotTo} dur: {(frame.time - prevFrame.time) * 1000}; easing: linear; {animTrigger}\"");
                        }
                        if (frame.IsDifferentWidth(prevFrame) || isFirstFrame)
                        {
                            sb.AppendLine($"animation__{cubeID}_f{index}=\"property: width; {widthFrom} {widthTo} dur: {(frame.time - prevFrame.time) * 1000}; easing: linear; {animTrigger}\"");
                        }
                        if (frame.IsDifferentHeight(prevFrame) || isFirstFrame)
                        {
                            sb.AppendLine($"animation__{cubeID}_f{index}=\"property: height; {heightFrom} {heightTo} dur: {(frame.time - prevFrame.time) * 1000}; easing: linear; {animTrigger}\"");
                        }
                        if (frame.IsDifferentDepth(prevFrame) || isFirstFrame)
                        {
                            sb.AppendLine($"animation__{cubeID}_f{index}=\"property: depth; {depthFrom} {depthTo} dur: {(frame.time - prevFrame.time) * 1000}; easing: linear; {animTrigger}\"");
                        }
                    }
                }
                sb.AppendLine("></a-box>");
                break;

            case "Model":
                string modelID = childToAdd.name.ToLower() + "_" + i;

                var Model = (width: childToAdd.transform.localScale.x / 10, height : childToAdd.transform.localScale.y / 10, depth : childToAdd.transform.localScale.z / 10,
                             position : -childToAdd.transform.localPosition.x / 10 + " " + childToAdd.transform.localPosition.y / 10 + " " + childToAdd.transform.localPosition.z / 10,
                             rotation : childToAdd.transform.localEulerAngles.x + " " + -childToAdd.transform.localEulerAngles.y + " " + -childToAdd.transform.localEulerAngles.z,
                             color : "#ffffff",
                             src : textureName != null ? "textures/" + textureName + ".png" : "");
                sb.AppendLine($"<a-entity obj-model=\"obj: #{childToAdd.name + "_Asset_obj_" + i}; mtl: #{childToAdd.name + "_Asset_mtl_" + i}\" id=\"{childToAdd.name + "_" + i}\" class=\"intersectable\" scale=\"{Model.width} {Model.height} {Model.depth}\" position=\"{Model.position}\" rotation=\"{Model.rotation}\" color=\"{Model.color}\" transparent={transparency}");


                if (childToAdd.GetComponent <AnimationHelper>() != null)
                {
                    string       animationFile = File.ReadAllText(Application.dataPath + "/Animations/JsonExports/" + SceneManager.GetActiveScene().name + "/" + modelID + ".txt");
                    KeyFrameList keyList       = JsonUtility.FromJson <KeyFrameList>(animationFile);

                    foreach (WeldonKeyFrame frame in keyList.frameList)
                    {
                        int            index = keyList.frameList.FindIndex(obj => obj == frame);
                        string         loopTrueString = "";
                        string         animTrigger = "";
                        string         posFrom = "", rotFrom = "", scaleFrom = "";
                        WeldonKeyFrame prevFrame = new WeldonKeyFrame();
                        if (index > 0)
                        {
                            prevFrame = keyList.frameList[index - 1];
                            posFrom   = $"from: {-prevFrame.posX / 10} {prevFrame.posY / 10} {prevFrame.posZ / 10};";
                            rotFrom   = $"from: {prevFrame.rotX} {-prevFrame.rotY} {-prevFrame.rotZ};";
                            scaleFrom = $"from: {prevFrame.scalX / 10} {prevFrame.scalY / 10} {prevFrame.scalZ / 10};";

                            animTrigger = $"startEvents: animationcomplete__{modelID}_f{index-1}" + ((index == 1 && childToAdd.GetComponent <AnimationHelper>().loop) ? $", animationcomplete__{modelID}_f{keyList.frameList.Count - 1};" : ";");
                        }
                        else
                        {
                            if (childToAdd.GetComponent <AnimationHelper>().onClick)
                            {
                                animTrigger = $"startEvents: mousedown;";
                            }
                        }

                        string posTo   = $"to: {-frame.posX / 10} {frame.posY / 10} {frame.posZ / 10};",
                               rotTo   = $"to: {frame.rotX} {-frame.rotY} {-frame.rotZ};",
                               scaleTo = $"to: {frame.scalX / 10} {frame.scalY / 10} {frame.scalZ / 10};";

                        //if (childToAdd.GetComponent<AnimationHelper>().loop) loopTrueString = $"repeat = \"indefinite\"";
                        bool isFirstFrame = prevFrame.time.Equals(-1) ? true : false;
                        if (isFirstFrame)
                        {
                            prevFrame.time = 0;
                        }
                        if (frame.IsDifferentPosition(prevFrame) || isFirstFrame)
                        {
                            sb.AppendLine($"animation__{modelID}_f{index}=\" property: position; {posFrom} {posTo} dur: {(frame.time - prevFrame.time) * 1000}; easing: linear; {animTrigger}\"");
                        }
                        if (frame.IsDifferentRotation(prevFrame) || isFirstFrame)
                        {
                            sb.AppendLine($"animation__{modelID}_f{index}=\" property: rotation; {rotFrom} {rotTo} dur: {(frame.time - prevFrame.time) * 1000}; easing: linear; {animTrigger}\"");
                        }
                        if (frame.IsDifferentWidth(prevFrame) || isFirstFrame)
                        {
                            sb.AppendLine($"animation__{modelID}_f{index}=\" property: scale; {scaleFrom} {scaleTo} dur: {(frame.time - prevFrame.time) * 1000}; easing: linear; {animTrigger}\"");
                        }
                    }
                }
                sb.AppendLine("></a-entity>");
                break;

            case "Sphere":
                var Sphere = (radius: childToAdd.transform.localScale.x / 20,
                              position : -childToAdd.transform.localPosition.x / 10 + " " + childToAdd.transform.localPosition.y / 10 + " " + childToAdd.transform.localPosition.z / 10,
                              rotation : childToAdd.transform.localEulerAngles.x + " " + -childToAdd.transform.localEulerAngles.y + " " + -childToAdd.transform.localEulerAngles.z,
                              color : "#" + ColorUtility.ToHtmlStringRGB(childToAdd.GetComponent <MeshRenderer>().sharedMaterial.color),
                              src : textureName != null ? "textures/" + textureName + ".png" : "");
                Debug.Log(Sphere.src);
                sb.AppendLine($"<a-sphere src=\"{Sphere.src}\" id=\"{childToAdd.name + "_" + i}\" class=\"intersectable\" radius=\"{Sphere.radius}\" position=\"{Sphere.position}\" rotation=\"{Sphere.rotation}\" color=\"{Sphere.color}\" transparent={transparency}");
                string shpereID = childToAdd.name.ToLower() + "_" + i;
                if (childToAdd.GetComponent <AnimationHelper>() != null)
                {
                    string       animationFile = File.ReadAllText(Application.dataPath + "/Animations/JsonExports/" + SceneManager.GetActiveScene().name + "/" + shpereID + ".txt");
                    KeyFrameList keyList       = JsonUtility.FromJson <KeyFrameList>(animationFile);

                    foreach (WeldonKeyFrame frame in keyList.frameList)
                    {
                        int            index = keyList.frameList.FindIndex(obj => obj == frame);
                        string         loopTrueString = "";
                        string         animTrigger = "";
                        string         posFrom = "", rotFrom = "", radiusFrom = "";
                        WeldonKeyFrame prevFrame = new WeldonKeyFrame();
                        if (index > 0)
                        {
                            prevFrame  = keyList.frameList[index - 1];
                            posFrom    = $"from: {-prevFrame.posX / 10} {prevFrame.posY / 10} {prevFrame.posZ / 10};";
                            rotFrom    = $"from: {prevFrame.rotX} {-prevFrame.rotY} {-prevFrame.rotZ};";
                            radiusFrom = $"from: {prevFrame.scalX / 20};";

                            animTrigger = $"startEvents: animationcomplete__{shpereID}_f{index-1}" + ((index == 1 && childToAdd.GetComponent <AnimationHelper>().loop) ? $", animationcomplete__{shpereID}_f{keyList.frameList.Count - 1};" : ";");
                        }
                        else
                        {
                            if (childToAdd.GetComponent <AnimationHelper>().onClick)
                            {
                                animTrigger = $"startEvents: mousedown;";
                            }
                        }

                        string posTo    = $"to: {-frame.posX / 10} {frame.posY / 10} {frame.posZ / 10};",
                               rotTo    = $"to: {frame.rotX} {-frame.rotY} {-frame.rotZ};",
                               radiusTo = $"to: {frame.scalX / 20};";

                        //if (childToAdd.GetComponent<AnimationHelper>().loop) loopTrueString = $"repeat = \"indefinite\"";
                        bool isFirstFrame = prevFrame.time.Equals(-1) ? true : false;
                        if (isFirstFrame)
                        {
                            prevFrame.time = 0;
                        }
                        if (frame.IsDifferentPosition(prevFrame) || isFirstFrame)
                        {
                            sb.AppendLine($"animation__{shpereID}_f{index}= \"property: position; {posFrom} {posTo} dur: {(frame.time - prevFrame.time) * 1000}; easing: linear; {animTrigger}\"");
                        }
                        if (frame.IsDifferentRotation(prevFrame) || isFirstFrame)
                        {
                            sb.AppendLine($"animation__{shpereID}_f{index}= \"property: rotation; {rotFrom} {rotTo} dur: {(frame.time - prevFrame.time) * 1000}; easing: linear; {animTrigger}\"");
                        }
                        if (frame.IsDifferentWidth(prevFrame) || isFirstFrame)
                        {
                            sb.AppendLine($"animation__{shpereID}_f{index}= \"property: radius; {radiusFrom} {radiusTo} dur: {(frame.time - prevFrame.time) * 1000}; easing: linear; {animTrigger}\"");
                        }
                    }
                }
                sb.AppendLine("></a-sphere>");

                break;

            case "Cylinder":
                var Cylinder = (radius: (childToAdd.transform.localScale.x + childToAdd.transform.localScale.z) / 40, height : childToAdd.transform.localScale.y / 5,
                                position : -childToAdd.transform.localPosition.x / 10 + " " + childToAdd.transform.localPosition.y / 10 + " " + childToAdd.transform.localPosition.z / 10,
                                rotation : childToAdd.transform.localEulerAngles.x + " " + -childToAdd.transform.localEulerAngles.y + " " + -childToAdd.transform.localEulerAngles.z,
                                color : "#" + ColorUtility.ToHtmlStringRGB(childToAdd.GetComponent <MeshRenderer>().sharedMaterial.color),
                                src : textureName != null ? "textures/" + textureName + ".png" : "");
                Debug.Log(Cylinder.src);
                sb.AppendLine($"<a-cylinder src=\"{Cylinder.src}\" id=\"{childToAdd.name + "_" + i}\" class=\"intersectable\" radius=\"{Cylinder.radius}\" height=\"{Cylinder.height}\" position=\"{Cylinder.position}\" rotation=\"{Cylinder.rotation}\" color=\"{Cylinder.color}\" transparent={transparency}");
                string cylinderID = childToAdd.name.ToLower() + "_" + i;
                if (childToAdd.GetComponent <AnimationHelper>() != null)
                {
                    string       animationFile = File.ReadAllText(Application.dataPath + "/Animations/JsonExports/" + SceneManager.GetActiveScene().name + "/" + cylinderID + ".txt");
                    KeyFrameList keyList       = JsonUtility.FromJson <KeyFrameList>(animationFile);

                    foreach (WeldonKeyFrame frame in keyList.frameList)
                    {
                        int            index = keyList.frameList.FindIndex(obj => obj == frame);
                        string         loopTrueString = "";
                        string         animTrigger = "";
                        string         posFrom = "", rotFrom = "", radiusFrom = "", heightFrom = "";
                        WeldonKeyFrame prevFrame = new WeldonKeyFrame();
                        if (index > 0)
                        {
                            prevFrame  = keyList.frameList[index - 1];
                            posFrom    = $"from: {-prevFrame.posX / 10} {prevFrame.posY / 10} {prevFrame.posZ / 10};";
                            rotFrom    = $"from: {prevFrame.rotX} {-prevFrame.rotY} {-prevFrame.rotZ};";
                            radiusFrom = $"from: {(prevFrame.scalX + prevFrame.scalZ) / 40};";
                            heightFrom = $"from: {prevFrame.scalY / 5};";

                            animTrigger = $"startEvents: animationcomplete__{cylinderID}_f{index-1}" + ((index == 1 && childToAdd.GetComponent <AnimationHelper>().loop) ? $", animationcomplete__{cylinderID}_f{keyList.frameList.Count - 1};" : ";");
                        }
                        else
                        {
                            if (childToAdd.GetComponent <AnimationHelper>().onClick)
                            {
                                animTrigger = $"startEvents: mousedown;";
                            }
                        }

                        string posTo    = $"to: {-frame.posX / 10} {frame.posY / 10} {frame.posZ / 10};",
                               rotTo    = $"to: {frame.rotX} {-frame.rotY} {-frame.rotZ};",
                               radiusTo = $"to: {(frame.scalX + frame.scalZ) / 40};",
                               heightTo = $"to: {frame.scalY / 5};";

                        //if (childToAdd.GetComponent<AnimationHelper>().loop) loopTrueString = $"repeat = \"indefinite\"";
                        bool isFirstFrame = prevFrame.time.Equals(-1) ? true : false;
                        if (isFirstFrame)
                        {
                            prevFrame.time = 0;
                        }
                        if (frame.IsDifferentPosition(prevFrame) || isFirstFrame)
                        {
                            sb.AppendLine($"animation__{cylinderID}_f{index}=\" property: position; {posFrom} {posTo} dur: {(frame.time - prevFrame.time) * 1000}; easing: linear; {animTrigger}\"");
                        }
                        if (frame.IsDifferentRotation(prevFrame) || isFirstFrame)
                        {
                            sb.AppendLine($"animation__{cylinderID}_f{index}=\" property: rotation; {rotFrom} {rotTo} dur: {(frame.time - prevFrame.time) * 1000}; easing: linear; {animTrigger}\"");
                        }
                        if (frame.IsDifferentWidth(prevFrame) || isFirstFrame)
                        {
                            sb.AppendLine($"animation__{cylinderID}_f{index}=\" property: radius; {radiusFrom} {radiusTo} dur: {(frame.time - prevFrame.time) * 1000}; easing: linear; {animTrigger}\"");
                        }
                        if (frame.IsDifferentHeight(prevFrame) || isFirstFrame)
                        {
                            sb.AppendLine($"animation__{cylinderID}_f{index}=\" property: height; {heightFrom} {heightTo} dur: {(frame.time - prevFrame.time) * 1000}; easing: linear; {animTrigger}\"");
                        }
                    }
                }
                sb.AppendLine("></a-cylinder>");
                break;

            default:

                break;
            }
        }

        sb.AppendLine("<!-- END: Unity Compiled Objects -->");
        #endregion Unity Compiled Objects

        sb.AppendLine("");
        sb.AppendLine("<!-- BEGIN: Bottom HTML -->");
        sb.Append(bottomHTML);
        sb.AppendLine("<!-- END: Bottom HTML -->");

        File.WriteAllText(folderPath + fileName, sb.ToString());
        Debug.Log("index file successfully created");
        AssetDatabase.Refresh();
    }
 /// <summary>
 /// ウェイト値が 0 のキーフレームをまとめて追加する。
 /// </summary>
 /// <param name="keyFrames">追加先のキーフレームリスト。</param>
 /// <param name="morphNames">対象モーフ名列挙。</param>
 /// <param name="frame">フレーム位置。</param>
 /// <remarks>
 /// 既に同位置にキーフレームが存在する場合は追加しない。
 /// </remarks>
 private static void AddZeroWeightKeyFrames(
     KeyFrameList keyFrames,
     IEnumerable<string> morphNames,
     long frame)
 {
     keyFrames.AddRange(
         from name in morphNames
         where !keyFrames.Any(f => f.MorphName == name && f.Frame == frame)
         select new KeyFrame(name, frame, 0));
 }
        /// <summary>
        /// キーフレームをまとめて追加またはウェイト値修正する。
        /// </summary>
        /// <param name="keyFrames">対象キーフレームリスト。</param>
        /// <param name="morphNames">対象モーフ名列挙。</param>
        /// <param name="frame">フレーム位置。</param>
        /// <param name="morphFrameWeightGetter">
        /// 指定モーフ名&指定フレーム位置のウェイト値提供デリゲート。
        /// </param>
        private static void AddOrModifyKeyFrames(
            KeyFrameList keyFrames,
            IEnumerable<string> morphNames,
            long frame,
            Func<string, long, float> morphFrameWeightGetter)
        {
            foreach (var name in morphNames)
            {
                // ウェイト値取得
                var weight = morphFrameWeightGetter(name, frame);

                // 指定フレーム位置のキーフレーム取得
                var frames =
                    keyFrames.Where(f => f.MorphName == name && f.Frame == frame);
                if (frames.Any())
                {
                    // ウェイト値書き換え
                    foreach (var f in frames)
                    {
                        f.Weight = weight;
                    }
                }
                else
                {
                    // 存在しないので追加
                    keyFrames.Add(new KeyFrame(name, frame, weight));
                }
            }
        }
        /// <summary>
        /// キーフレームリストから、末端および末端の次のキーフレーム位置を取得する。
        /// </summary>
        /// <param name="keyFrames">キーフレームリスト。</param>
        /// <param name="frameBegin">先頭のキーフレーム位置の設定先。</param>
        /// <param name="frameEnd">終端のキーフレーム位置の設定先。</param>
        /// <param name="frameBeginNext">
        /// 先頭の次のキーフレーム位置の設定先。存在しなければ null が設定される。
        /// </param>
        /// <param name="frameEndNext">
        /// 終端の手前のキーフレーム位置の設定先。存在しなければ null が設定される。
        /// </param>
        private static void GetEdgeAndNextFrames(
            KeyFrameList keyFrames,
            out long frameBegin,
            out long frameEnd,
            out long? frameBeginNext,
            out long? frameEndNext)
        {
            frameBeginNext = null;
            frameEndNext = null;

            // 先頭と終端のキーフレーム位置設定
            var begin = frameBegin = keyFrames.Min(f => f.Frame);
            var end = frameEnd = keyFrames.Max(f => f.Frame);

            // 先頭の次のキーフレーム位置があれば設定
            var frames = keyFrames.Where(f => f.Frame > begin);
            if (frames.Any())
            {
                var beginNext = frames.Min(f => f.Frame);
                frameBeginNext = (beginNext < end) ? (long?)beginNext : null;
            }

            // 終端の手前のキーフレーム位置があれば設定
            frames = keyFrames.Where(f => f.Frame < end);
            if (frames.Any())
            {
                var endNext = frames.Max(f => f.Frame);
                frameEndNext = (endNext > begin) ? (long?)endNext : null;
            }
        }
        /// <summary>
        /// ウェイト値保持のためにキーフレームリストを修正する。
        /// </summary>
        /// <param name="keyFrames">修正対象のキーフレームリスト。</param>
        /// <param name="morphNames">対象モーフ名列挙。</param>
        /// <param name="morphFrameWeightGetter">
        /// 指定モーフ名&指定フレーム位置のウェイト値提供デリゲート。
        /// </param>
        private static void ModifyKeyFramesForEdgeWeightHeld(
            KeyFrameList keyFrames,
            IEnumerable<string> morphNames,
            Func<string, long, float> morphFrameWeightGetter)
        {
            // 先頭と終端、およびその次のキーフレーム位置取得
            long frameBegin, frameEnd;
            long? frameBeginNext, frameEndNext;
            GetEdgeAndNextFrames(
                keyFrames,
                out frameBegin,
                out frameEnd,
                out frameBeginNext,
                out frameEndNext);

            // 先頭と末尾のキーフレーム追加or修正
            AddOrModifyKeyFrames(
                keyFrames,
                morphNames,
                frameBegin,
                morphFrameWeightGetter);
            if (frameEnd != frameBegin)
            {
                AddOrModifyKeyFrames(
                    keyFrames,
                    morphNames,
                    frameEnd,
                    morphFrameWeightGetter);
            }

            // 先頭および末尾の次のフレームがあるなら
            // キーフレーム登録されていないモーフのウェイト値を 0 にする
            if (frameBeginNext.HasValue)
            {
                AddZeroWeightKeyFrames(keyFrames, morphNames, frameBeginNext.Value);
            }
            if (frameEndNext.HasValue)
            {
                AddZeroWeightKeyFrames(keyFrames, morphNames, frameEndNext.Value);
            }
        }