Example #1
0
        /// <summary>
        /// Add the provided prefabs as new prefab settings using the template specified by name.
        /// Clear is applied if requested.
        /// </summary>
        /// <param name="templateName"></param>
        /// <param name="prefabs"></param>
        /// <param name="clear"></param>
        public void AddPrefabs(string templateName, List <GameObject> prefabs, bool clear)
        {
            // find tree template
            PrefabSettingsTemplate template = editor.FindTemplate(templateName);

            if (!template)
            {
                Debug.LogError("Template not found: " + templateName);
                return;
            }

            // clear the prefab settings list if required
            if (clear)
            {
                editor.GetPainter().prefabSettingsList.Clear();
            }

            // add the prefabs using the given template
            foreach (GameObject prefab in prefabs)
            {
                PrefabSettings prefabSettings = new PrefabSettings();

                prefabSettings.prefab = prefab;

                prefabSettings.ApplyTemplate(template);

                editor.GetPainter().prefabSettingsList.Add(prefabSettings);
            }

            // Apply changes to the serializedProperty - always do this in the end of OnInspectorGUI.
            editor.serializedObject.ApplyModifiedProperties();
        }
        public void PersistPrefab(PrefabSettings prefabSettings, PrefabTransform prefabTransform)
        {
            // spawn item to vs pro
            if (editorTarget.brushSettings.spawnToVSPro)
            {
                vegetationStudioProIntegration.AddNewPrefab(prefabSettings, prefabTransform.position, prefabTransform.rotation, prefabTransform.scale);
            }
            // spawn item to scene
            else
            {
                // new prefab
                GameObject instance = PrefabUtility.InstantiatePrefab(prefabSettings.prefab) as GameObject;

                instance.transform.position   = prefabTransform.position;
                instance.transform.rotation   = prefabTransform.rotation;
                instance.transform.localScale = prefabTransform.scale;

                // attach as child of container
                instance.transform.parent = editorTarget.container.transform;

                Undo.RegisterCreatedObjectUndo(instance, "Instantiate Prefab");

                if (editorTarget.spawnSettings.autoSimulationType != SpawnSettings.AutoSimulationType.None)
                {
                    autoPhysicsCollection.Add(instance);
                }
            }
        }
Example #3
0
        private void AddNewPrefab(PrefabSettings prefabSettings, Vector3 position, Vector3 normal)
        {
            PrefabTransform appliedTransform = CreateAppliedTransform(prefabSettings, position, normal);

            // create instance and apply position / rotation / scale
            brushModuleEditor.PersistPrefab(prefabSettings, appliedTransform);
        }
        private void QuickRotationSetting(PrefabSettings prefabSettings, float x, float y, float z)
        {
            prefabSettings.randomRotation = true;

            prefabSettings.rotationMinX = 0f * x;
            prefabSettings.rotationMaxX = 360f * x;
            prefabSettings.rotationMinY = 0f * y;
            prefabSettings.rotationMaxY = 360f * y;
            prefabSettings.rotationMinZ = 0f * z;
            prefabSettings.rotationMaxZ = 360f * z;
        }
        public void AddPrefab(GameObject prefab, PrefabSettingsTemplate template)
        {
            // new settings
            PrefabSettings prefabSettings = new PrefabSettings();

            prefabSettings.ApplyTemplate(template);

            // initialize with dropped prefab
            prefabSettings.prefab = prefab;

            editor.newDraggedPrefabs.Add(prefabSettings);
        }
        public PrefabSettings CreatePrefabSettings()
        {
            PrefabSettings selectedItem = GetRandomWeightedPrefab();

            if (selectedItem == null)
            {
                Debug.LogError("No prefab is active! At least 1 prefab must be active.");
                return(null);
            }

            return(selectedItem);
        }
Example #7
0
        /// <summary>
        /// Add prefabs, mode Center
        /// </summary>
        public void AddPrefabs_Center(Vector3 position, Vector3 normal)
        {
            // check if a gameobject is already within the brush size
            // allow only 1 instance per bush size
            GameObject container = editorTarget.container as GameObject;

            // check if a prefab already exists within the brush
            bool prefabExists = false;

            // check overlap
            if (!editorTarget.brushSettings.allowOverlap)
            {
                float brushRadius = editorTarget.brushSettings.brushSize / 2f;

                foreach (Transform child in container.transform)
                {
                    // ignore the preview
                    if (previewPrefab != null && child.gameObject == previewPrefab.prefabInstance)
                    {
                        continue;
                    }

                    float dist = Vector3.Distance(position, child.transform.position);

                    // check against the brush
                    if (dist <= brushRadius)
                    {
                        prefabExists = true;
                        break;
                    }
                }
            }

            // create position vector
            Vector3 prefabPosition = new Vector3(position.x, position.y, position.z);

            //// auto physics height offset is moved to AddNewPrefab
            // prefabPosition = ApplyAutoPhysicsHeightOffset(prefabPosition);

            if (!prefabExists)
            {
                bool isInFilter = filterEvaluator.IsInFilter(position, editorTarget.filterSettings);

                if (isInFilter)
                {
                    PrefabSettings prefabSettings = previewPrefab.prefabSettings;

                    AddNewPrefab(prefabSettings, prefabPosition, normal);
                }
            }
        }
        private void QuickRotationSetting(PrefabSettings prefabSettings, float x, float y, float z)
        {
            float min = prefabSettings.rotationRange.GetMinimum();
            float max = prefabSettings.rotationRange.GetMaximum();

            prefabSettings.randomRotation = true;

            prefabSettings.rotationMinX = min * x;
            prefabSettings.rotationMaxX = max * x;
            prefabSettings.rotationMinY = min * y;
            prefabSettings.rotationMaxY = max * y;
            prefabSettings.rotationMinZ = min * z;
            prefabSettings.rotationMaxZ = max * z;
        }
Example #9
0
        public void AddNewPrefab(PrefabSettings prefabSettings, Vector3 newPosition, Quaternion newRotation, Vector3 newLocalScale)
        {
            // brush mode
            float brushSize = editor.GetPainter().brushSettings.brushSize;

            // poisson mode: use the discs as brush size
            if (editor.GetPainter().brushSettings.distribution == BrushSettings.Distribution.Poisson_Any || editor.GetPainter().brushSettings.distribution == BrushSettings.Distribution.Poisson_Terrain)
            {
                brushSize = editor.GetPainter().brushSettings.poissonDiscSize;
            }

            GameObject prefab       = prefabSettings.prefab;
            bool       allowOverlap = editor.GetPainter().brushSettings.allowOverlap;

            terrainTreeManager.PlacePrefab(prefab, newPosition, newLocalScale, newRotation, brushSize, randomTreeColor, treeColorAdjustment, allowOverlap);
        }
Example #10
0
        /// <summary>
        /// Ensure the prefab has a VegetationItemID
        /// </summary>
        /// <param name="prefabSettings"></param>
        private void updateVSProSettings(PrefabSettings prefabSettings, bool forceVegetationItemIDUpdate)
        {
#if VEGETATION_STUDIO_PRO
            GameObject prefab = prefabSettings.prefab;

            // check if we have a VegetationItemID, otherwise create it using the current prefab
            if (string.IsNullOrEmpty(prefabSettings.vspro_VegetationItemID) || forceVegetationItemIDUpdate)
            {
                // get the asset guid
                if (string.IsNullOrEmpty(prefabSettings.assetGUID))
                {
                    string assetPath = AssetDatabase.GetAssetPath(prefab);
                    if (!string.IsNullOrEmpty(assetPath))
                    {
                        string assetGUID = AssetDatabase.AssetPathToGUID(assetPath);
                        prefabSettings.assetGUID = assetGUID;
                    }
                }

                // if we have a guid, get the vs pro id
                if (!string.IsNullOrEmpty(prefabSettings.assetGUID))
                {
                    // get the VegetationItemID
                    prefabSettings.vspro_VegetationItemID = VegetationStudioManager.GetVegetationItemID(prefabSettings.assetGUID);

                    // if the vegetation item id doesn't exist, create a new vegetation item
                    if (string.IsNullOrEmpty(prefabSettings.vspro_VegetationItemID))
                    {
                        VegetationType vegetationType     = VegetationType.Objects;
                        bool           enableRuntimeSpawn = false; // no runtime spawn, we want it spawned from persistent storage
                        BiomeType      biomeType          = BiomeType.Default;

                        prefabSettings.vspro_VegetationItemID = VegetationStudioManager.AddVegetationItem(prefab, vegetationType, enableRuntimeSpawn, biomeType);
                    }
                }
                else
                {
                    Debug.LogError("Can't get assetGUID for prefab " + prefab);
                }
            }

            if (string.IsNullOrEmpty(prefabSettings.vspro_VegetationItemID))
            {
                Debug.LogError("Can't get VegetationItemId for prefab " + prefab);
            }
#endif
        }
Example #11
0
        public void PersistPrefab(PrefabSettings prefabSettings, PrefabTransform prefabTransform)
        {
            switch (editorTarget.brushSettings.spawnTarget)
            {
            case BrushSettings.SpawnTarget.PrefabContainer:

                // new prefab
                GameObject instance = PrefabUtility.InstantiatePrefab(prefabSettings.prefab) as GameObject;

                instance.transform.position   = prefabTransform.position;
                instance.transform.rotation   = prefabTransform.rotation;
                instance.transform.localScale = prefabTransform.scale;

                // attach as child of container
                instance.transform.parent = editorTarget.container.transform;

                Undo.RegisterCreatedObjectUndo(instance, "Instantiate Prefab");

                if (editorTarget.spawnSettings.autoSimulationType != SpawnSettings.AutoSimulationType.None)
                {
                    autoPhysicsCollection.Add(instance);
                }

                break;

            case BrushSettings.SpawnTarget.TerrainTrees:

                unityTerrainTreesIntegration.AddNewPrefab(prefabSettings, prefabTransform.position, prefabTransform.rotation, prefabTransform.scale);

                break;

            case BrushSettings.SpawnTarget.TerrainDetails:

                Debug.LogError("Not implemented");

                break;

            case BrushSettings.SpawnTarget.VegetationStudioPro:

                vegetationStudioProIntegration.AddNewPrefab(prefabSettings, prefabTransform.position, prefabTransform.rotation, prefabTransform.scale);

                break;
            }
        }
Example #12
0
        /// <summary>
        /// Add prefabs, mode Center
        /// </summary>
        public void AddPrefabs_Center(Vector3 position, Vector3 normal)
        {
            // check if a gameobject is already within the brush size
            // allow only 1 instance per bush size
            GameObject container = editorTarget.container as GameObject;

            // check if a prefab already exists within the brush
            bool prefabExists = false;

            // check overlap
            if (!editorTarget.brushSettings.allowOverlap)
            {
                float brushRadius = editorTarget.brushSettings.brushSize / 2f;

                foreach (Transform child in container.transform)
                {
                    // ignore the preview
                    if (previewPrefab != null && child.gameObject == previewPrefab.prefabInstance)
                    {
                        continue;
                    }

                    float dist = Vector3.Distance(position, child.transform.position);

                    // check against the brush
                    if (dist <= brushRadius)
                    {
                        prefabExists = true;
                        break;
                    }
                }
            }

            if (!prefabExists)
            {
                PrefabSettings prefabSettings = previewPrefab.prefabSettings;

                AddNewPrefab(prefabSettings, position, normal);
            }
        }
Example #13
0
        public void AddNewPrefab(PrefabSettings prefabSettings, Vector3 newPosition, Quaternion newRotation, Vector3 newLocalScale)
        {
#if VEGETATION_STUDIO_PRO
            // ensure the prefab has a VegetationItemID
            updateVSProSettings(prefabSettings, true);

            if (!string.IsNullOrEmpty(prefabSettings.vspro_VegetationItemID))
            {
                string     vegetationItemID  = prefabSettings.vspro_VegetationItemID;
                Vector3    worldPosition     = newPosition;
                Vector3    scale             = newLocalScale; // TODO local or world?
                Quaternion rotation          = newRotation;
                bool       applyMeshRotation = true;          // TODO ???
                float      distanceFalloff   = 1f;            // TODO ???
                bool       clearCellCache    = true;          // TODO ???

                byte vegetationSourceID = Constants.VegetationStudioPro_SourceId;

                VegetationStudioManager.AddVegetationItemInstance(vegetationItemID, worldPosition, scale, rotation, applyMeshRotation, vegetationSourceID, distanceFalloff, clearCellCache);
            }
#endif
        }
        private void ApplyPrefabSettings(int offsetLane, PrefabSettings prefabSettings, GameObject prefab, Vector3 currentPosition, Vector3 direction, List <SplinePoint> splinePoints, int currentSplinePointIndex)
        {
            // add prefab's position offset
            prefab.transform.position += prefabSettings.positionOffset;

            // auto physics: add additional height offset
            if (prefabPainter.spawnSettings.autoSimulationType != SpawnSettings.AutoSimulationType.None)
            {
                prefab.transform.position += new Vector3(0f, prefabPainter.spawnSettings.autoSimulationHeightOffset, 0f);
            }

            // lanes
            Vector3    splinePosition = prefab.transform.position;
            Quaternion splineRotation = Quaternion.LookRotation(direction);

            Vector3 addDistanceToDirection = Vector3.zero;

            if (offsetLane == 0)
            {
                // check if the objects should be aligned next to each other
                // TODO this is only done for the center lane currently; we don't have the information about the others
                //      ie this only works in center lane mode currently
                if (prefabPainter.splineSettings.separation == SplineSettings.Separation.PrefabRadiusBounds)
                {
                    // move along in the spline rotation, considering the radius (/2)
                    addDistanceToDirection = splineRotation * prefab.transform.forward * GetDistanceToMove(prefab) / 2;
                }
                else if (prefabPainter.splineSettings.separation == SplineSettings.Separation.PrefabForwardSize)
                {
                    // move along in the spline rotation, considering the extents (/2)
                    addDistanceToDirection = splineRotation * prefab.transform.forward * GetDistanceToMove(prefab) / 2;
                }
            }
            // lane mode, all lanes except center
            else
            {
                // calculate offset distance to spline
                float offsetDistance = offsetLane * prefabPainter.splineSettings.laneDistance;

                // calculate the distance considering the spline direction
                //Vector3 distance = prefabPainter.splineSettings.lanePositionOffset - go.transform.position;
                addDistanceToDirection = splineRotation * prefab.transform.right * offsetDistance;
            }

            prefab.transform.position += addDistanceToDirection;


            // size
            if (prefabSettings.changeScale)
            {
                prefab.transform.localScale = Vector3.one * Random.Range(prefabSettings.scaleMin, prefabSettings.scaleMax);
            }

            // initial rotation
            Quaternion rotation = Quaternion.identity;

            switch (prefabPainter.splineSettings.instanceRotation)
            {
            case SplineSettings.Rotation.Spline:
                // rotation along spline
                rotation = Quaternion.LookRotation(direction);
                break;

            case SplineSettings.Rotation.SplineRandom:

                // rotation along spline
                rotation = Quaternion.LookRotation(direction);

                // add random rotation
                if (prefabSettings.randomRotation)
                {
                    float rotationX = rotation.eulerAngles.x + Random.Range(prefabSettings.rotationMinX, prefabSettings.rotationMaxX);
                    float rotationY = rotation.eulerAngles.y + Random.Range(prefabSettings.rotationMinY, prefabSettings.rotationMaxY);
                    float rotationZ = rotation.eulerAngles.z + Random.Range(prefabSettings.rotationMinZ, prefabSettings.rotationMaxZ);

                    rotation = Quaternion.Euler(rotationX, rotationY, rotationZ);
                }

                break;

            case SplineSettings.Rotation.Prefab:
                // rotation of the prefab
                if (prefabSettings.randomRotation)
                {
                    float rotationX = Random.Range(prefabSettings.rotationMinX, prefabSettings.rotationMaxX);
                    float rotationY = Random.Range(prefabSettings.rotationMinY, prefabSettings.rotationMaxY);
                    float rotationZ = Random.Range(prefabSettings.rotationMinZ, prefabSettings.rotationMaxZ);

                    rotation = Quaternion.Euler(rotationX, rotationY, rotationZ);
                }
                break;
            }

            // lerp rotation between control points along the spline
            if (prefabPainter.splineSettings.controlPointRotation)
            {
                /*
                 * Quaternion controlPointRotation = prefabPainter.splineSettings.controlPoints[currentSplinePointIndex].rotation;
                 * rotation *= controlPointRotation;
                 */

                int currentControlPointIndex = splinePoints[currentSplinePointIndex].startControlPointIndex;
                int nextControlPointIndex    = currentControlPointIndex + 1;

                // check loop
                if (prefabPainter.splineSettings.loop)
                {
                    if (nextControlPointIndex > prefabPainter.splineSettings.controlPoints.Count - 1)
                    {
                        nextControlPointIndex = 0;
                    }
                }

                Vector3 currentControlPointPosition = prefabPainter.splineSettings.controlPoints[currentControlPointIndex].position;
                Vector3 nextControlPointPosition    = prefabPainter.splineSettings.controlPoints[nextControlPointIndex].position;

                // the percentage that a spline point is between control points. ranges from 0 to 1
                float percentageOnSegment = MathUtils.InverseLerp(currentControlPointPosition, nextControlPointPosition, currentPosition);

                // calculate lerp roation
                Quaternion currentControlPointRotation = prefabPainter.splineSettings.controlPoints[currentControlPointIndex].rotation;
                Quaternion nextControlPointRotation    = prefabPainter.splineSettings.controlPoints[nextControlPointIndex].rotation;

                Quaternion lerpRotation = Quaternion.Lerp(currentControlPointRotation, nextControlPointRotation, percentageOnSegment);

                // add rotation
                rotation *= lerpRotation;
            }

            prefab.transform.rotation = rotation;

            // add prefab rotation offset
            prefab.transform.Rotate(prefabSettings.rotationOffset);
        }
Example #15
0
        private PrefabTransform CreateAppliedTransform(PrefabSettings prefabSettings, Vector3 position, Vector3 normal)
        {
            ///
            /// Calculate position / rotation / scale
            ///

            // get new position
            Vector3 newPosition = position;

            // add offset of brush in up direction
            newPosition += CalculateBrushOffsetUp();

            // add offset of prefab settings
            newPosition += prefabSettings.positionOffset;

            // auto physics height offset
            newPosition = ApplyAutoPhysicsHeightOffset(newPosition);

            Vector3 newLocalScale = prefabSettings.prefab.transform.localScale;

            // size
            // please note that the scale might be change later again (scale to brush size)
            // which should happen after the rotation
            if (prefabSettings.changeScale)
            {
                newLocalScale = Vector3.one * Random.Range(prefabSettings.scaleMin, prefabSettings.scaleMax);
            }

            // rotation
            Quaternion alignedRotation = Quaternion.identity;
            Quaternion objectRotation;

            if (this.editorTarget.brushSettings.alignToTerrain)
            {
                alignedRotation = Quaternion.FromToRotation(Vector3.up, normal);
            }

            if (prefabSettings.randomRotation)
            {
                objectRotation = prefabSettings.instanceRotation;
            }
            else
            {
                objectRotation = Quaternion.Euler(prefabSettings.rotationOffset);
            }

            // additionally consider brush rotation
            Quaternion brushRotation = Quaternion.Euler(0f, editorTarget.brushSettings.brushRotation, 0f);

            // combine terrain aligned rotation and object rotation
            Quaternion newRotation = alignedRotation * objectRotation * brushRotation;

            // scale to brush size
            // this uses world bounds and happens after the rotation
            if (editorTarget.brushSettings.distribution == BrushSettings.Distribution.Fluent)
            {
                GameObject prefab = prefabSettings.prefab;

                Quaternion prevRotation = prefab.transform.rotation;
                {
                    // we need to rotate the gameobject now in order to calculate the world bounds
                    prefab.transform.rotation = newRotation;

                    float  brushSize   = editorTarget.brushSettings.brushSize;
                    Bounds worldBounds = BoundsUtils.CalculateBounds(prefab);

                    Vector3 prefabScale = prefab.transform.localScale;

                    float scaleFactorX = brushSize / worldBounds.size.x;
                    float scaleFactorY = brushSize / worldBounds.size.y;
                    float scaleFactorZ = brushSize / worldBounds.size.z;

                    float scaleFactorXYZ = Mathf.Min(scaleFactorX, scaleFactorY, scaleFactorZ);

                    newLocalScale = prefabScale * scaleFactorXYZ;
                }
                prefab.transform.rotation = prevRotation;
            }

            PrefabTransform prefabTransform = new PrefabTransform(newPosition, newRotation, newLocalScale);

            return(prefabTransform);
        }
        public void OnSceneGUI()
        {
            // paint prefabs on mouse drag. don't do anything if no mode is selected, otherwise e.g. movement in scene view wouldn't work with alt key pressed
            if (brushComponent.DrawBrush(editorTarget.brushSettings, out BrushMode brushMode, out RaycastHit raycastHit))
            {
                switch (brushMode)
                {
                case BrushMode.ShiftDrag:

                    AddPrefabs(raycastHit);

                    needsPhysicsApplied = true;

                    // consume event
                    Event.current.Use();
                    break;

                case BrushMode.ShiftCtrlDrag:

                    RemovePrefabs(raycastHit);

                    // consume event
                    Event.current.Use();
                    break;
                }
            }

            if (IsFluent())
            {
                if (!brushDistribution.HasPreviewPrefab())
                {
                    brushDistribution.CreatePreviewPrefab();
                }

                // alt + mousewheel = modify height of preview prefab in transform up direction
                if (Event.current.modifiers == EventModifiers.Alt)
                {
                    if (Event.current.isScrollWheel)
                    {
                        PrefabSettings previewPrefabSettings = brushDistribution.GetPreviewPrefabSettings();

                        // the delta value will be modified (reduced) in the offset calculation; it might be too much as it is
                        previewPrefabSettings.brushOffsetUp += Event.current.delta.y;

                        Event.current.Use();
                    }
                }

                brushDistribution.UpdatePreviewPrefab(raycastHit.point, raycastHit.normal);
            }

            // info for the scene gui; used to be dynamic and showing number of prefabs (currently is static until refactoring is done)
            string[] guiInfo = new string[] {
                "Add prefabs: shift + drag mouse"
                + "\nRemove prefabs: shift + ctrl + drag mouse" +
                "\nBrush size: ctrl + mousewheel, Brush rotation: ctrl + shift + mousewheel"
            };

            brushComponent.Layout(guiInfo);

            // auto physics
            bool applyAutoPhysics = needsPhysicsApplied &&
                                    autoPhysicsCollection.Count > 0 &&
                                    editorTarget.spawnSettings.autoSimulationType != SpawnSettings.AutoSimulationType.None &&
                                    Event.current.type == EventType.MouseUp;

            if (applyAutoPhysics)
            {
                AutoPhysicsSimulation.ApplyPhysics(editorTarget.physicsSettings, autoPhysicsCollection, editorTarget.spawnSettings.autoSimulationType);

                autoPhysicsCollection.Clear();
            }
        }
        public void OnInspectorGUI()
        {
            GUILayout.BeginVertical("box");
            {
                EditorGUILayout.LabelField("Prefabs", GUIStyles.BoxTitleStyle);

                #region template drop targets
                GUILayout.BeginHorizontal();
                {
                    GUILayout.BeginVertical();
                    {
                        // change background color in case there are no prefabs yet
                        if (editorTarget.prefabSettingsList.Count == 0)
                        {
                            EditorGUILayout.HelpBox("Drop prefabs on the prefab template boxes in order to use them.", MessageType.Info);

                            editor.SetErrorBackgroundColor();
                        }

                        int gridRows = Mathf.CeilToInt((float)templateCollection.templates.Count / Constants.PrefabTemplateGridColumnCount);

                        for (int row = 0; row < gridRows; row++)
                        {
                            GUILayout.BeginHorizontal();
                            {
                                for (int column = 0; column < Constants.PrefabTemplateGridColumnCount; column++)
                                {
                                    int index = column + row * Constants.PrefabTemplateGridColumnCount;

                                    PrefabSettingsTemplate template = index < templateCollection.templates.Count ? templateCollection.templates[index] : defaultTemplate;

                                    // drop area
                                    Rect prefabDropArea = GUILayoutUtility.GetRect(0.0f, 34.0f, GUIStyles.DropAreaStyle, GUILayout.ExpandWidth(true));

                                    bool hasDropArea = index < templateCollection.templates.Count;
                                    if (hasDropArea)
                                    {
                                        // drop area box with background color and info text
                                        GUI.color = GUIStyles.DropAreaBackgroundColor;
                                        GUI.Box(prefabDropArea, template.templateName, GUIStyles.DropAreaStyle);
                                        GUI.color = GUIStyles.DefaultBackgroundColor;

                                        Event evt = Event.current;
                                        switch (evt.type)
                                        {
                                        case EventType.DragUpdated:
                                        case EventType.DragPerform:

                                            if (prefabDropArea.Contains(evt.mousePosition))
                                            {
                                                DragAndDrop.visualMode = DragAndDropVisualMode.Copy;

                                                if (evt.type == EventType.DragPerform)
                                                {
                                                    DragAndDrop.AcceptDrag();

                                                    // list of new prefabs that should be created via drag/drop
                                                    // we can't do it in the drag/drop code itself, we'd get exceptions like
                                                    //   ArgumentException: Getting control 12's position in a group with only 12 controls when doing dragPerform. Aborting
                                                    // followed by
                                                    //   Unexpected top level layout group! Missing GUILayout.EndScrollView/EndVertical/EndHorizontal? UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr)
                                                    // they must be added when everything is done (currently at the end of this method)
                                                    editor.newDraggedPrefabs = new List <PrefabSettings>();

                                                    foreach (Object droppedObject in DragAndDrop.objectReferences)
                                                    {
                                                        // allow only prefabs
                                                        if (PrefabUtility.GetPrefabAssetType(droppedObject) == PrefabAssetType.NotAPrefab)
                                                        {
                                                            Debug.Log("Not a prefab: " + droppedObject);
                                                            continue;
                                                        }

                                                        // add the prefab to the list using the template
                                                        AddPrefab(droppedObject as GameObject, template);
                                                    }
                                                }
                                            }
                                            break;
                                        }
                                    }
                                }
                            }
                            GUILayout.EndHorizontal();
                        }

                        editor.SetDefaultBackgroundColor();
                    }
                    GUILayout.EndVertical();
                }
                GUILayout.EndHorizontal();

                #endregion template drop targets

                if (editorTarget.prefabSettingsList.Count > 0)
                {
                    EditorGUILayout.Space();
                }

                for (int i = 0; i < editorTarget.prefabSettingsList.Count; i++)
                {
                    // horizontal separator
                    editor.AddGUISeparator(i == 0 ? 0f : 10f, 10f);

                    PrefabSettings prefabSettings = this.editorTarget.prefabSettingsList[i];

                    GUILayout.BeginHorizontal();
                    {
                        // preview

                        // try to get the asset preview
                        Texture2D previewTexture = AssetPreview.GetAssetPreview(prefabSettings.prefab);

                        // if no asset preview available, try to get the mini thumbnail
                        if (!previewTexture)
                        {
                            previewTexture = AssetPreview.GetMiniThumbnail(prefabSettings.prefab);
                        }

                        // if a preview is available, paint it
                        if (previewTexture)
                        {
                            //GUILayout.Label(previewTexture, EditorStyles.objectFieldThumb, GUILayout.Width(50), GUILayout.Height(50)); // without border, but with size
                            GUILayout.Label(previewTexture, GUILayout.Width(50), GUILayout.Height(50)); // without border, but with size

                            //GUILayout.Box(previewTexture); // with border
                            //GUILayout.Label(previewTexture); // no border
                            //GUILayout.Box(previewTexture, GUILayout.Width(50), GUILayout.Height(50)); // with border and size
                            //EditorGUI.DrawPreviewTexture(new Rect(25, 60, 100, 100), previewTexture); // draws it in absolute coordinates
                        }

                        // right align the buttons
                        GUILayout.FlexibleSpace();

                        if (GUILayout.Button("Add", EditorStyles.miniButton))
                        {
                            this.editorTarget.prefabSettingsList.Insert(i + 1, new PrefabSettings());
                        }
                        if (GUILayout.Button("Duplicate", EditorStyles.miniButton))
                        {
                            PrefabSettings newPrefabSettings = prefabSettings.Clone();
                            this.editorTarget.prefabSettingsList.Insert(i + 1, newPrefabSettings);
                        }
                        if (GUILayout.Button("Reset", EditorStyles.miniButton))
                        {
                            // remove existing
                            this.editorTarget.prefabSettingsList.RemoveAt(i);

                            // add new
                            this.editorTarget.prefabSettingsList.Insert(i, new PrefabSettings());
                        }
                        if (GUILayout.Button("Remove", EditorStyles.miniButton))
                        {
                            this.editorTarget.prefabSettingsList.Remove(prefabSettings);
                        }
                    }
                    GUILayout.EndHorizontal();

                    GUILayout.Space(4);

                    prefabSettings.prefab = (GameObject)EditorGUILayout.ObjectField("Prefab", prefabSettings.prefab, typeof(GameObject), true);

                    prefabSettings.active      = EditorGUILayout.Toggle("Active", prefabSettings.active);
                    prefabSettings.probability = EditorGUILayout.Slider("Probability", prefabSettings.probability, 0, 1);

                    // scale
                    if (editorTarget.brushSettings.distribution == BrushSettings.Distribution.Fluent)
                    {
                        // use the brush scale, hide the change scale option
                    }
                    else
                    {
                        prefabSettings.changeScale = EditorGUILayout.Toggle("Change Scale", prefabSettings.changeScale);

                        if (prefabSettings.changeScale)
                        {
                            prefabSettings.scaleMin = EditorGUILayout.FloatField("Scale Min", prefabSettings.scaleMin);
                            prefabSettings.scaleMax = EditorGUILayout.FloatField("Scale Max", prefabSettings.scaleMax);
                        }
                    }
                    // position
                    prefabSettings.positionOffset = EditorGUILayout.Vector3Field("Position Offset", prefabSettings.positionOffset);

                    // rotation
                    prefabSettings.rotationOffset = EditorGUILayout.Vector3Field("Rotation Offset", prefabSettings.rotationOffset);
                    GUILayout.BeginHorizontal();
                    {
                        prefabSettings.randomRotation = EditorGUILayout.Toggle("Random Rotation", prefabSettings.randomRotation);

                        // right align the buttons
                        GUILayout.FlexibleSpace();

                        if (GUILayout.Button("X", EditorStyles.miniButton))
                        {
                            QuickRotationSetting(prefabSettings, 1f, 0f, 0f);
                        }
                        if (GUILayout.Button("Y", EditorStyles.miniButton))
                        {
                            QuickRotationSetting(prefabSettings, 0f, 1f, 0f);
                        }
                        if (GUILayout.Button("Z", EditorStyles.miniButton))
                        {
                            QuickRotationSetting(prefabSettings, 0f, 0f, 1f);
                        }
                        if (GUILayout.Button("XYZ", EditorStyles.miniButton))
                        {
                            QuickRotationSetting(prefabSettings, 1f, 1f, 1f);
                        }

                        if (GUILayout.Button(prefabSettings.rotationRange.GetDisplayName(), EditorStyles.miniButton))
                        {
                            prefabSettings.rotationRange = prefabSettings.rotationRange.GetNext();
                        }
                    }
                    GUILayout.EndHorizontal();

                    // rotation limits
                    if (prefabSettings.randomRotation)
                    {
                        float min = prefabSettings.rotationRange.GetMinimum();
                        float max = prefabSettings.rotationRange.GetMaximum();

                        EditorGuiUtilities.MinMaxEditor("  Rotation Limit X", ref prefabSettings.rotationMinX, ref prefabSettings.rotationMaxX, min, max);
                        EditorGuiUtilities.MinMaxEditor("  Rotation Limit Y", ref prefabSettings.rotationMinY, ref prefabSettings.rotationMaxY, min, max);
                        EditorGuiUtilities.MinMaxEditor("  Rotation Limit Z", ref prefabSettings.rotationMinZ, ref prefabSettings.rotationMaxZ, min, max);
                    }

                    // VS Pro Id
#if VEGETATION_STUDIO_PRO
                    EditorGUI.BeginDisabledGroup(true);
                    EditorGUILayout.TextField("Asset GUID", prefabSettings.assetGUID);
                    EditorGUILayout.TextField("VSPro Id", prefabSettings.vspro_VegetationItemID);
                    EditorGUI.EndDisabledGroup();
#endif
                }
            }

            GUILayout.EndVertical();
        }
        /// <summary>
        /// Add a new prefab to the spline
        /// </summary>
        // TODO: rewrite, use different approach: Use fake splines around the current spline. That way the separation distance doesn't matter
        //       and you could have small prefabs on the outer spline, and big prefabs on the inner spline and they would distribute better
        private GameObject AddPrefab(ref int prefabInstanceIndex, Vector3 position, Vector3 direction, List <SplinePoint> splinePoints, int currentSplinePointIndex)
        {
            GameObject instance = null;

            // offset for lanes: lanes are from left to right, center is the spline.
            // so a spline with 5 lanes has these offset lanes: -2, -1, 0, 1, 2
            int offsetLane = -prefabPainter.splineSettings.lanes / 2;

            for (var lane = 1; lane <= prefabPainter.splineSettings.lanes; lane++)
            {
                // skip center lane if requested
                if (prefabPainter.splineSettings.skipCenterLane && offsetLane == 0)
                {
                    offsetLane++;
                    continue;
                }

                // get settings for the prefab to instantiate
                PrefabSettings prefabSettings = prefabPainter.CreatePrefabSettings();

                // check if we have settings at all
                if (prefabSettings == null)
                {
                    return(null);
                }

                // instance will be created or used => advance index
                prefabInstanceIndex++;

                // reset the instance; check later if we should reuse one or create a new one
                instance = null;

                // check if we have to create a new instance or use an existing one
                if (prefabPainter.splineSettings.reusePrefabs)
                {
                    if (prefabInstanceIndex < prefabPainter.splineSettings.prefabInstances.Count)
                    {
                        instance = prefabPainter.splineSettings.prefabInstances[prefabInstanceIndex];
                    }
                }

                // create instance if we don't have one yet
                if (instance == null)
                {
                    // instantiate gameobject clone (lose reference to prefab
                    //instance = GameObject.Instantiate(prefabSettings.prefab);

                    // instantiate prefab
                    instance = PrefabUtility.InstantiatePrefab(prefabSettings.prefab) as GameObject;

                    prefabPainter.splineSettings.prefabInstances.Add(instance);
                }

                // reset position & rotation
                instance.transform.position = position;
                instance.transform.rotation = Quaternion.identity;

                ApplyPrefabSettings(offsetLane, prefabSettings, instance, position, direction, splinePoints, currentSplinePointIndex);

                // reparent the child to the container
                instance.transform.parent = prefabPainter.container.transform;

                offsetLane++;
            }

            return(instance);
        }