void OnSceneGUI()
        {
            Dice           dice           = (Dice)target;
            DiceDefinition diceDefinition = dice.definition;

            Handles.color = Color.white;
            float labelDistance = 0.5f;

            if (dice.definition == null)
            {
                return;                          // Should NEVER be null!
            }
            if (dice.definition.faces == null)
            {
                return;                                 // Should NEVER be null!
            }
            GUIStyle style = new GUIStyle();

            style.fontSize         = 20;
            style.alignment        = TextAnchor.MiddleCenter;
            style.normal.textColor = Color.white;

            for (int i = 0; i < diceDefinition.faces.Length; i++)
            {
                var face     = diceDefinition.faces[i];
                var localDir = dice.transform.rotation * face.direction;
                var to       = dice.transform.position + localDir * labelDistance;
                Handles.DrawDottedLine(dice.transform.position, to, 3f);
                Handles.Label(to, face.value.ToString(), style);
            }

            if (GUI.changed)
            {
                EditorUtility.SetDirty(target);
            }
        }
        public override void OnInspectorGUI()
        {
            serializedObject.Update();
            DiceDefinition diceDefinition = (DiceDefinition)target;

            // Update parameters
            diceDefinition.numberOfFaces      = EditorGUILayout.IntSlider("Number of Faces", diceDefinition.numberOfFaces, 2, 20);
            diceDefinition.defaultPipsSize    = EditorGUILayout.FloatField("Default Pip Size", diceDefinition.defaultPipsSize);
            diceDefinition.defaultPipsStretch = EditorGUILayout.FloatField("Default Pip Stretch", diceDefinition.defaultPipsStretch);
            diceDefinition.faceDistance       = EditorGUILayout.FloatField("Face distance from center", diceDefinition.faceDistance);

            // Special cases
            diceDefinition.zeroInsteadOfTen = EditorGUILayout.Toggle("0 instead of 10", diceDefinition.zeroInsteadOfTen);
            diceDefinition.sixAndNineBars   = EditorGUILayout.Toggle("Bars under 6 and 9", diceDefinition.sixAndNineBars);
            diceDefinition.pipsAtVertices   = EditorGUILayout.Toggle("Pips placed at vertices", diceDefinition.pipsAtVertices);
            if (diceDefinition.pipsAtVertices)
            {
                diceDefinition.verticesNumber = EditorGUILayout.IntField("Number of vertices", diceDefinition.verticesNumber);
                diceDefinition.pipsRadius     = EditorGUILayout.IntField("Radius of the vertex pips", diceDefinition.pipsRadius);
            }

            // Update number of faces
            if (diceDefinition.faces == null || diceDefinition.faces.Length != diceDefinition.numberOfFaces)
            {
                diceDefinition.faces = new FaceData[diceDefinition.numberOfFaces];
            }

            faceList.DoLayoutList();

            serializedObject.ApplyModifiedProperties();

            if (GUI.changed)
            {
                EditorUtility.SetDirty(target);
            }
        }
        void OnGUI()
        {
            // Show properties
            diceDefinition = (DiceDefinition)EditorGUILayout.ObjectField("Definition", diceDefinition, typeof(DiceDefinition), false);
            if (diceDefinition == null)
            {
                return;
            }

            scrollPos_main = EditorGUILayout.BeginScrollView(scrollPos_main, false, false);

            // Load defaults if something changed
            // or if our items got out of sync
            if (diceDefinition != lastDiceDefinition ||
                diceDefinition.numberOfFaces != facesSprite.Length)
            {
                diceName = "New D" + diceDefinition.numberOfFaces;

                // Load high poly mesh as visual mesh
                var tmpPath = DM.Config.DefaultMeshesPathComplete + "dice_d" + diceDefinition.numberOfFaces + "_high.fbx";
                var tmpMesh = AssetDatabase.LoadAssetAtPath <Mesh>(tmpPath);
                if (tmpMesh != null)
                {
                    usedMesh = tmpMesh;
                }
                else
                {
                    Debug.LogWarning("Trying to load default mesh at " + tmpPath + " but could not find it!");
                }

                // Load low poly mesh as collision mesh
                tmpPath = DM.Config.DefaultMeshesPathComplete + "dice_d" + diceDefinition.numberOfFaces + "_low.fbx";
                tmpMesh = AssetDatabase.LoadAssetAtPath <Mesh>(tmpPath);
                if (tmpMesh != null)
                {
                    collisionMesh = tmpMesh;
                }
                else
                {
                    Debug.LogWarning("Trying to load default collision mesh at " + tmpPath + " but could not find it!");
                }

                // Default material
                if (usedMaterial == null)
                {
                    tmpPath = DM.Config.DefaultMaterialsPathComplete + "default_material.mat";
                    var tmpMat = AssetDatabase.LoadAssetAtPath <Material>(tmpPath);
                    if (tmpMat != null)
                    {
                        usedMaterial = tmpMat;
                    }
                    else
                    {
                        Debug.LogWarning("Trying to load default material at " + tmpPath + " but could not find it!");
                    }
                }

                // Get all default values
                facesPipOrientation = new float[diceDefinition.numberOfFaces];
                facesPipSize        = new float[diceDefinition.numberOfFaces];
                facesPipStretch     = new float[diceDefinition.numberOfFaces];
                dynamicFacesObjects = new GameObject[diceDefinition.numberOfFaces];
                for (int i = 0; i < diceDefinition.numberOfFaces; i++)
                {
                    facesPipOrientation[i] = diceDefinition.faces[i].defaultOrientation;
                    facesPipSize[i]        = diceDefinition.faces[i].pipSize;
                    facesPipStretch[i]     = diceDefinition.faces[i].pipStretch;
                    dynamicFacesObjects[i] = Resources.Load <GameObject>("DefaultDynamicFace");
                }

                SetPipsToDefaultNumbers();
                // Reset textures and prefab
                generatedPrefab  = null;
                generatedTexture = null;

                lastDiceDefinition = diceDefinition;
            }

            diceName       = EditorGUILayout.TextField("Name", diceName);
            patternTexture = (Texture2D)EditorGUILayout.ObjectField("Pattern", patternTexture, typeof(Texture2D), false);
            usedMesh       = (Mesh)EditorGUILayout.ObjectField("Mesh", usedMesh, typeof(Mesh), false);
            collisionMesh  = (Mesh)EditorGUILayout.ObjectField("Collision", collisionMesh, typeof(Mesh), false);
            usedMaterial   = (Material)EditorGUILayout.ObjectField("Material", usedMaterial, typeof(Material), false);
            physicMaterial = (PhysicMaterial)EditorGUILayout.ObjectField("Physic Material", physicMaterial, typeof(PhysicMaterial), false);

            targetTextureSize = EditorGUILayout.IntField("Target texture size", targetTextureSize);
            if (targetTextureSize > 2048)
            {
                targetTextureSize = 2048;
            }
            if (targetTextureSize < 256)
            {
                targetTextureSize = 256;
            }

            // Actions
            if (GUILayout.Button("Generate Dice Texture"))
            {
                generatedTexture = DiceCreator.GenerateFinalTexture(
                    diceName, diceDefinition, facesSprite, patternTexture,
                    targetTextureSize,
                    facesPipOrientation,
                    facesPipSize,
                    facesPipStretch,
                    facesType);
            }

            EditorGUI.BeginDisabledGroup(generatedTexture == null);
            if (GUILayout.Button("Generate Dice Prefab"))
            {
                generatedPrefab = DiceCreator.GenerateFinalPrefab(
                    diceName,
                    diceDefinition,
                    generatedTexture,
                    usedMesh, collisionMesh,
                    usedMaterial, physicMaterial,
                    facesType,
                    dynamicFacesObjects,
                    facesSprite,
                    facesPipOrientation,
                    facesPipSize,
                    facesPipStretch);
            }
            EditorGUI.EndDisabledGroup();

            // Show number sprites
            showFacesOptions = EditorGUILayout.Toggle("Show faces options", showFacesOptions);

            if (diceDefinition != null)
            {
                if (showFacesOptions)
                {
                    GUILayout.Box("", GUILayout.ExpandWidth(true), GUILayout.Height(1));

                    this.facesType = (FacesType)EditorGUILayout.EnumPopup("Faces type", (System.Enum) this.facesType);

                    if (facesType == FacesType.Dynamic || facesType == FacesType.Texture)
                    {
                        DrawChangePipsButtons();
                    }

                    scrollPos_faces = EditorGUILayout.BeginScrollView(scrollPos_faces, false, false, GUILayout.MinHeight(facesAreaMinHeight));

                    for (int i = 0; i < diceDefinition.numberOfFaces; i++)
                    {
                        EditorGUILayout.BeginHorizontal();

                        if (facesType == FacesType.Dynamic || facesType == FacesType.Texture)
                        {
                            facesSprite[i] = (Sprite)EditorGUILayout.ObjectField(facesSprite[i], typeof(Sprite), false,
                                                                                 GUILayout.Height(facePreviewSize),
                                                                                 GUILayout.Width(facePreviewSize));
                        }
                        else if (facesType == FacesType.Custom)
                        {
                            dynamicFacesObjects[i] = (GameObject)EditorGUILayout.ObjectField(
                                dynamicFacesObjects[i], typeof(GameObject), false);
                        }

                        if (showAdditionalFaceOptions)
                        {
                            int labelWidth = 120;
                            int valueWidth = 30;

                            EditorGUILayout.BeginVertical();
                            EditorGUILayout.BeginHorizontal();
                            EditorGUILayout.LabelField("Orientation", GUILayout.MaxWidth(labelWidth));
                            facesPipOrientation[i] = EditorGUILayout.FloatField(facesPipOrientation[i], GUILayout.MaxWidth(valueWidth));
                            facesPipOrientation[i] = Mathf.Clamp(facesPipOrientation[i], -360, 360);
                            EditorGUILayout.EndHorizontal();

                            labelWidth = 50;
                            EditorGUILayout.BeginHorizontal();
                            EditorGUILayout.LabelField("Size", GUILayout.MaxWidth(labelWidth));
                            facesPipSize[i] = EditorGUILayout.FloatField(facesPipSize[i], GUILayout.MaxWidth(valueWidth));
                            facesPipSize[i] = Mathf.Clamp(facesPipSize[i], 0.1f, 3f);

                            labelWidth = 50;
                            EditorGUILayout.LabelField("Stretch", GUILayout.MaxWidth(labelWidth));
                            facesPipStretch[i] = EditorGUILayout.FloatField(facesPipStretch[i], GUILayout.MaxWidth(valueWidth));
                            facesPipStretch[i] = Mathf.Clamp(facesPipStretch[i], 0.1f, 3f);
                            EditorGUILayout.EndHorizontal();

                            EditorGUILayout.EndVertical();
                        }

                        EditorGUILayout.EndHorizontal();
                    }
                    EditorGUILayout.EndScrollView();
                }
            }

            GUILayout.Box("", GUILayout.ExpandWidth(true), GUILayout.Height(1));

            // Preview
            EditorGUILayout.BeginHorizontal();
            if (generatedPrefab != null)
            {
                GUILayout.Label(AssetPreview.GetAssetPreview(generatedPrefab));
            }
            if (generatedTexture != null)
            {
                GUILayout.Label(generatedTexture, GUILayout.Width(texturePreviewSize));
            }
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.EndScrollView();
        }
        /// <summary>
        /// Generate a prefab of the dice and save it among the assets
        /// </summary>
        /// <param name="diceName">Name of the dice (and asset) to generate.</param>
        /// <param name="diceDefinition">Definition to use.</param>
        /// <param name="finalTexture">Texture of the dice.</param>
        /// <param name="finalMesh">Mesh of the dice.</param>
        /// <param name="collisionMesh">Collision mesh of the dice.</param>
        /// <param name="finalMaterial">Material of the dice.</param>
        /// <param name="physicMaterial">Physics material of the dice.</param>
        /// <param name="facesType">The type determining how to handle faces.</param>
        /// <param name="dynamicFacesObjects">Dynamic objects to place on faces.</param>
        /// <returns>The new dice prefab GameObject.</returns>
        public static GameObject GenerateFinalPrefab(
            string diceName,
            DiceDefinition diceDefinition,
            Texture2D finalTexture,
            Mesh finalMesh, Mesh collisionMesh,
            Material finalMaterial, PhysicMaterial physicMaterial,
            FacesType facesType, GameObject[] dynamicFacesObjects,
            Sprite[] facesSprite,
            float[] facesPipOrientation,
            float[] facesPipSize,
            float[] facesPipStretch)
        {
            Debug.Log("Generating Dice prefab...");

            // Get the base prefab
            GameObject dicePrefabBase = Resources.Load("DicePrefabBase") as GameObject;

            if (dicePrefabBase == null)
            {
                Debug.LogError("No example prefab 'DicePrefabBase' found in the resources folder! Make sure not to delete or move it!");
                return(null);
            }

            // Create the new dice GameObject
            GameObject newDiceGo = GameObject.Instantiate(dicePrefabBase) as GameObject;
            var        newDice   = newDiceGo.GetComponent <Dice>();

            newDice.definition = diceDefinition;

            // Set meshes
            if (finalMesh == null)
            {
                Debug.LogError("No mesh was selected in the Dice Creator! Make sure you choose one.");
                return(null);
            }
            if (collisionMesh == null)
            {
                Debug.LogWarning("No collision mesh was selected in the Dice Creator! Your new dice prefab won't be able to react to collisions.");
            }
            if (physicMaterial == null)
            {
                Debug.LogWarning("No physical material was selected in the Dice Creator! Your new dice prefab will behave with default values.");
            }
            GameObject meshGo       = newDiceGo.transform.Find("Mesh").gameObject;
            var        meshFilter   = meshGo.GetComponent <MeshFilter>();
            var        meshCollider = newDiceGo.GetComponent <MeshCollider>();

            meshFilter.mesh         = finalMesh;
            meshCollider.sharedMesh = collisionMesh;
            meshCollider.material   = physicMaterial;

            // Instantiate the new material and save it in the output folder
            if (finalMaterial == null)
            {
                Debug.LogError("No material was assigned to the dice creator! Cannot generate prefab!");
                return(null);
            }
            Material mat = new Material(finalMaterial);

            mat.SetTexture("_MainTex", finalTexture);
            meshGo.GetComponent <MeshRenderer>().material = mat;
            string matPath = DM.Config.OutputPathComplete + "Materials";

            if (!Directory.Exists(matPath))
            {
                Debug.LogError("Cannot find directory at " + matPath + ".\nDid you move the folders? Make sure to update the DiceConfig script if you did!");
                return(null);
            }
            matPath += "/" + diceName + ".mat";
            AssetDatabase.CreateAsset(mat, matPath);
            EditorUtility.SetDirty(mat);

            // Check if we need to add something to the different faces
            if (facesType == FacesType.Dynamic || facesType == FacesType.Custom)
            {
                newDice.dynamicFaceGos = new GameObject[diceDefinition.numberOfFaces];
            }
            for (int faceIndex = 0; faceIndex < diceDefinition.faces.Length; faceIndex++)
            {
                var vectorToFace = diceDefinition.faces[faceIndex].direction * diceDefinition.faceDistance;

                // Check if we need to add dynamic faces
                if (facesType == FacesType.Dynamic || facesType == FacesType.Custom)
                {
                    var dynamicFaceGo = GameObject.Instantiate(dynamicFacesObjects[faceIndex]) as GameObject;
                    if (facesType == FacesType.Dynamic)
                    {
                        dynamicFaceGo.name = "DynamicFace_" + diceDefinition.faces[faceIndex].value;
                    }
                    else
                    {
                        dynamicFaceGo.name = "CustomFace_" + diceDefinition.faces[faceIndex].value;
                    }

                    var dynamicFaceTr = dynamicFaceGo.transform;

                    dynamicFaceTr.SetParent(newDiceGo.transform);

                    dynamicFaceTr.localPosition = vectorToFace;

                    if (facesType == FacesType.Dynamic)
                    {
                        dynamicFaceTr.forward = -vectorToFace;
                    }
                    else
                    {
                        dynamicFaceTr.forward = vectorToFace;
                    }

                    dynamicFaceTr.Rotate(Vector3.forward, facesPipOrientation[faceIndex], Space.Self);

                    dynamicFaceTr.localScale = new Vector3(1, facesPipStretch[faceIndex], 1);
                    //dynamicFaceTr.localScale *= diceDefinition.defaultPipsSize;
                    dynamicFaceTr.localScale *= facesPipSize[faceIndex];
                    dynamicFaceTr.localScale *= DiceConfig.Instance.dynamicFaceSizeMultiplier;

                    if (facesType == FacesType.Dynamic)
                    {
                        var dynamicFace = dynamicFaceGo.GetComponent <DynamicFace>();
                        if (dynamicFace != null)
                        {
                            dynamicFace.SetSprite(facesSprite[faceIndex]);
                        }
                    }

                    newDice.dynamicFaceGos[faceIndex] = dynamicFaceGo;
                }

                // Check if we need to add weights
                if (diceDefinition.faces[faceIndex].weight > 0)
                {
                    Debug.Log("Adding weight to face " + (faceIndex + 1) + " at axis " + (-diceDefinition.faces[faceIndex].direction));
                    var weightGo = new GameObject("Weight " + (faceIndex + 1).ToString());
                    weightGo.transform.parent = newDiceGo.transform;
                    var weightRb = weightGo.AddComponent <Rigidbody>();
                    weightRb.mass = diceDefinition.faces[faceIndex].weight;

                    // Note that the weight is at the other side fo the face
                    weightRb.transform.localPosition = -vectorToFace;

                    var weightJoint = weightGo.AddComponent <FixedJoint>();
                    weightJoint.connectedBody = newDiceGo.GetComponent <Rigidbody>();
                }
            }

            string targetPath = DM.Config.OutputPathComplete + "Prefabs";

            if (!Directory.Exists(targetPath))
            {
                Debug.LogError("Cannot find directory at " + targetPath + ".\nDid you move the folders? Make sure to update DiceConfig if you did!");
                return(null);
            }
            targetPath += "/" + diceName + ".prefab";

            GameObject newDiePrefab = null;
            bool       createIt     = false;

            if (AssetDatabase.LoadAssetAtPath(targetPath, typeof(GameObject)))
            {
                if (EditorUtility.DisplayDialog("Are you sure?",
                                                "The prefab already exists. Do you want to overwrite it?",
                                                "Yes",
                                                "No"))
                {
                    createIt = true;
                }
            }
            else
            {
                createIt = true;
            }

            if (createIt)
            {
                var prefab = PrefabUtility.CreateEmptyPrefab(targetPath);
                newDiePrefab = PrefabUtility.ReplacePrefab(newDiceGo, prefab, ReplacePrefabOptions.ReplaceNameBased);
                Debug.Log("Final dice prefab " + diceName + " generated! \n " + targetPath);
            }
            else
            {
                Debug.LogWarning("No dice prefab generated.");
            }


            // Remove temporary objects
            GameObject.DestroyImmediate(newDiceGo);

            // At the end, save and refresh
            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();

            return(newDiePrefab);
        }
        /// <summary>
        /// Generates a complete texture for the dice and save it
        /// </summary>
        /// <param name="diceName">Name of the dice to generate.</param>
        /// <param name="diceDefinition">Definition to use.</param>
        /// <param name="pipSprites">Sprites to use as pips for the faces of the dice.</param>
        /// <param name="patternTexture">Base pattern to use.</param>
        /// <param name="targetTextureSize">Size of the target (final) texture</param>
        /// <param name="facesPipOrientation">Orientation of each pip.</param>
        /// <param name="facesPipSize">Multiplier for the size of each pip.</param>
        /// <param name="facesPipStretch">Multiplier for the stretch of each pip.</param>
        /// <returns>The final generated texture.</returns>
        public static Texture2D GenerateFinalTexture(
            string diceName,
            DiceDefinition diceDefinition,
            Sprite[] pipSprites,
            Texture2D patternTexture,
            int targetTextureSize,
            float[] facesPipOrientation,
            float[] facesPipSize,
            float[] facesPipStretch,
            FacesType facesType)
        {
            if (facesType == FacesType.Dynamic || facesType == FacesType.Custom)
            {
                Debug.Log("When using non-texture faces, the final texture will just be the pattern.");
                if (patternTexture == null)
                {
                    Debug.LogError("Make sure you select a pattern!");
                    return(null);
                }
                return(patternTexture);
            }

            Debug.Log("Generating texture...");
            // Check readability
            if (!ReadabilityIsOk(pipSprites, patternTexture))
            {
                return(null);
            }

            // Define the size of the final texture
            // Changed if we need to have a different size for the target texture
            int target_width  = targetTextureSize;
            int target_height = target_width;

            // The UVs are written on texture of fixed size, so take the ratio into account
            float uv_to_target_ratio_x = target_width * 1f / original_uv_size;
            float uv_to_target_ratio_y = target_height * 1f / original_uv_size;

            // Define input and output
            Color[] sourcePixels;
            var     newTexture = new Texture2D(target_width, target_height, TextureFormat.ARGB32, false, true);

            newTexture.name = "New Texture";
            var targetPixels = newTexture.GetPixels();

            // First write the pattern below
            if (patternTexture != null)
            {
                int source_pattern_width  = patternTexture.width;
                int source_pattern_height = patternTexture.height;

                float pattern_to_target_x = target_width / source_pattern_width;
                float pattern_to_target_y = target_height / source_pattern_height;

                sourcePixels = patternTexture.GetPixels();
                for (int target_x = 0; target_x < target_width; target_x++)
                {
                    for (int target_y = 0; target_y < target_height; target_y++)
                    {
                        // Target to source
                        int source_x = Mathf.FloorToInt(target_x / pattern_to_target_x);
                        int source_y = Mathf.FloorToInt(target_y / pattern_to_target_y);

                        // Clamp if out of range
                        source_x = Mathf.Clamp(source_x, 0, source_pattern_width - 1);
                        source_y = Mathf.Clamp(source_y, 0, source_pattern_height - 1);

                        // Copy
                        var p = GetPixel(sourcePixels, source_pattern_width, source_pattern_height, source_x, source_y);
                        SetPixel(p, targetPixels, target_width, target_height, target_x, target_y);
                    }
                }
            }

            // Then add all the face pips
            for (int faceIndex = 0; faceIndex < diceDefinition.numberOfFaces; faceIndex++)
            {
                // Define the size of each face texture
                // This does not change the size of the final pip, but it changes the size of the available space
                // This is set according to how big the pips are needed (if the size gets out of scope)
                float faceSizeMultiplier = target_width / 256; // FIXED, to make sure it works for different sizes
                int   target_face_width  = 256;                // FIXED
                int   target_face_height = target_face_width;

                // Size multiplier is taken into account, since we need to have more space
                target_face_width  = Mathf.FloorToInt(target_face_width * faceSizeMultiplier);
                target_face_height = Mathf.FloorToInt(target_face_height * faceSizeMultiplier);

                // If we need to place them at vertices, do a special method
                if (diceDefinition.pipsAtVertices)
                {
                    // Compute UV for each vertex
                    // We will place them in a radial manner, starting from the top (we add 90 degrees for that)
                    float angle_delta       = 360 / diceDefinition.verticesNumber;
                    float angle_zero_offset = 90;
                    float radius            = diceDefinition.pipsRadius;
                    for (int v = 0; v < diceDefinition.verticesNumber; v++)
                    {
                        // We get the other faces
                        int other_face_index = faceIndex + 1 + v;
                        if (other_face_index >= diceDefinition.numberOfFaces)
                        {
                            other_face_index -= diceDefinition.numberOfFaces;
                        }

                        var pipSprite = pipSprites[other_face_index];
                        if (pipSprite == null)
                        {
                            continue;                       // No pip for this face
                        }
                        var faceData = diceDefinition.faces[faceIndex];

                        int   even_correction = ((faceIndex + 1) % 2 == 0 ? 1 : 0);             // Even degrees need a correction of 1 cycle
                        int   clockwise       = facesPipOrientation[faceIndex] == 180 ? -1 : 1; // Change direction based on the orientation
                        float angle_degrees   = angle_zero_offset + (angle_delta * clockwise * (v + even_correction)) + facesPipOrientation[faceIndex];
                        float angle_radians   = angle_degrees / 180 * Mathf.PI;
                        float uv_x            = faceData.uvFaceCenter.x + radius * Mathf.Cos(angle_radians);
                        float uv_y            = faceData.uvFaceCenter.y + radius * Mathf.Sin(angle_radians);

                        var tmpPipTexture = PrepareTextureFromSprite(pipSprite, -(angle_delta * clockwise * (v + even_correction)) + facesPipOrientation[faceIndex]);
                        tmpPipTexture.name = "Pip " + faceIndex;
                        sourcePixels       = tmpPipTexture.GetPixels();
                        int source_width  = tmpPipTexture.width;
                        int source_height = tmpPipTexture.height;

                        float size         = diceDefinition.defaultPipsSize * facesPipSize[faceIndex] / faceSizeMultiplier;
                        int   offset_x     = GetOffset(size, target_face_width, uv_x, uv_to_target_ratio_x);
                        float multiplier_x = GetMultiplier(size, target_face_width, source_width, uv_to_target_ratio_x);

                        size = size * diceDefinition.defaultPipsStretch * facesPipStretch[faceIndex];
                        int   offset_y     = GetOffset(size, target_face_height, uv_y, uv_to_target_ratio_y);
                        float multiplier_y = GetMultiplier(size, target_face_height, source_height, uv_to_target_ratio_y);

                        CopyPixels(sourcePixels, targetPixels,
                                   source_width, source_height,
                                   target_face_width, target_face_height,
                                   target_width, target_height,
                                   multiplier_x, multiplier_y,
                                   offset_x, offset_y
                                   );

                        // Cleanup
                        GameObject.DestroyImmediate(tmpPipTexture);
                    }
                }
                // Normal method: place at UV points
                else
                {
                    var pipSprite = pipSprites[faceIndex];
                    if (pipSprite == null)
                    {
                        continue;                       // No pip for this face
                    }
                    var faceData = diceDefinition.faces[faceIndex];

                    // Get the pip texture
                    int previous_width  = pipSprite.texture.width;
                    int previous_height = pipSprite.texture.height;

                    var tmpPipTexture = PrepareTextureFromSprite(pipSprite, facesPipOrientation[faceIndex]);
                    tmpPipTexture.name = "Pip " + faceIndex;
                    sourcePixels       = tmpPipTexture.GetPixels();
                    int source_width  = tmpPipTexture.width;
                    int source_height = tmpPipTexture.height;

                    // Take into account that the size may have changed
                    float new_ratio_x = source_width * 1f / previous_width;
                    float new_ratio_y = source_height * 1f / previous_height;
                    target_face_width  = (int)(target_face_width * new_ratio_x);
                    target_face_height = (int)(target_face_height * new_ratio_y);

                    float size         = diceDefinition.defaultPipsSize * facesPipSize[faceIndex] / faceSizeMultiplier;
                    int   offset_x     = GetOffset(size, target_face_width, faceData.uvFaceCenter.x, uv_to_target_ratio_x);
                    float multiplier_x = GetMultiplier(size, target_face_width, source_width, uv_to_target_ratio_x);

                    size = size * diceDefinition.defaultPipsStretch * facesPipStretch[faceIndex];
                    int   offset_y     = GetOffset(size, target_face_height, faceData.uvFaceCenter.y, uv_to_target_ratio_y);
                    float multiplier_y = GetMultiplier(size, target_face_height, source_height, uv_to_target_ratio_y);

                    CopyPixels(sourcePixels, targetPixels,
                               source_width, source_height,
                               target_face_width, target_face_height,
                               target_width, target_height,
                               multiplier_x, multiplier_y,
                               offset_x, offset_y
                               );

                    // Cleanup
                    GameObject.DestroyImmediate(tmpPipTexture);
                }
            }
            newTexture.SetPixels(targetPixels);
            newTexture.Apply(false);

            // At the end, save and reload
            newTexture.name = diceName + "_Texture";
            bool canSave = SaveTextureToFile(newTexture, diceName);

            if (canSave)
            {
                //EditorUtility.SetDirty(newTexture);
                AssetDatabase.SaveAssets();
                AssetDatabase.Refresh();
                GameObject.DestroyImmediate(newTexture);  // Cleaning-up the now saved texture for reload
                newTexture = (Texture2D)AssetDatabase.LoadAssetAtPath(
                    DM.Config.OutputPathComplete + "Textures/" + diceName + ".png", typeof(Texture2D));
                newTexture.name = diceName + "_Texture RELOAD";
            }

            return(newTexture);
        }