Rasagar/Assets/TerrainStitcher/Editor/TerrainStitcherWindow.js
2024-09-28 18:07:23 +03:00

198 lines
6.1 KiB
JavaScript

/*
* Copyright (c) 2011 Reijer Hooijkaas.
* All rights reserved.
*
* Contact: reijerh AT gmail.com
*
* TERRAIN STITCHER v1.1
*
* TerrainStitcher is free for private, non-commercial use only, please
* refer to License.txt for conditions that apply to commercial use.
*/
class TerrainStitcherWindow extends EditorWindow {
var terrain1 : Terrain;
var terrain2 : Terrain;
var numSamplesAuto = 20;
var numSamplesManual = 20;
var dominatingTerrain = 0;
var setAutoSamples = false;
var setManualSamples = false;
@MenuItem ("Terrain/Terrain Stitcher...")
static function Init () {
// Get existing open window or if none, make a new one:
var window : TerrainStitcherWindow = EditorWindow.GetWindow(TerrainStitcherWindow);
}
function OnSelectionChange() {
Repaint();
}
function findNeighbors(terrain : GameObject, gameObjects, originalPositions) {
var neighbors = new Array();
var thisPos = originalPositions[terrain];
var width = terrain.GetComponent(Terrain).terrainData.size.x;
for (var go : GameObject in gameObjects) {
if (terrain == go)
continue;
var pos = originalPositions[go];
var diffX = pos.x - thisPos.x;
var diffZ = pos.z - thisPos.z;
// A neighbor is positioned N, E, S or W of this terrain
if (((diffZ >= width && diffZ < 1.5 * width) && (diffX > -0.5 * width && diffX < 0.5 * width)) || // N
((diffZ > -0.5 * width && diffZ < 0.5 * width) && (diffX >= width && diffX < width * 1.5)) || // E
((diffZ <= -width && diffZ > -1.5 * width) && (diffX > -0.5 * width && diffX < 0.5 * width)) || // S
((diffZ > -0.5 * width && diffZ < 0.5 * width) && (diffX <= -width && diffX > -1.5 * width))) // W
neighbors.Add(go);
}
return neighbors;
}
function stitchTerrains(terrains, numSamples) {
var originalPositions = new Hashtable();
for (var go : GameObject in terrains) {
var pos = go.GetComponent(Terrain).transform.position;
originalPositions.Add(go, pos);
}
var affectedTerrains = new ArrayList();
var visitedTerrains = new ArrayList();
var performedStitches = new Hashtable();
do {
for (var go : GameObject in terrains) {
if (performedStitches[go] == null)
performedStitches[go] = new ArrayList();
var neighbors = findNeighbors(go, terrains, originalPositions);
// If we have no neighbors we don't need stitching
if (neighbors.length == 0) {
visitedTerrains.Add(go);
continue;
}
// Terrain must be the first or already affected by another terrain to be allowed
// to dominate another terrain
if (!((affectedTerrains.Count == 0 || affectedTerrains.Contains(go)) &&
!visitedTerrains.Contains(go)))
continue;
if (EditorUtility.DisplayCancelableProgressBar("Stitching terrains...", "",
parseFloat(visitedTerrains.Count) / terrains.length)) {
EditorUtility.ClearProgressBar();
return;
}
for (var neighbor : GameObject in neighbors) {
// No need to stitch if we are already stitched
if (performedStitches[neighbor] != null && performedStitches[neighbor].Contains(go))
continue;
if (TerrainStitcher.stitch(go.GetComponent(Terrain), neighbor.GetComponent(Terrain), numSamples, 1) == -1) {
EditorUtility.DisplayDialog("Terrain dimensions don't match!", "All terrains must have equal dimensions to"
+ " allow stitching.", "OK");
return;
}
performedStitches[go].Add(neighbor);
affectedTerrains.Add(neighbor);
}
visitedTerrains.Add(go);
}
} while (visitedTerrains.Count < terrains.length);
EditorUtility.ClearProgressBar();
}
function OnGUI () {
EditorGUILayout.BeginVertical();
/* AUTO STITCHING */
GUILayout.Label("Auto Stitching");
// Every selected object must be a terrain for stitch button to stay enabled
// and at least 2 terrains must be selected
GUI.enabled = true;
var selected = Selection.gameObjects;
var numTerrains = 0;
for (var go : GameObject in selected) {
if (go.GetComponent(Terrain) == null) {
GUI.enabled = false;
break;
} else {
numTerrains++;
}
}
EditorGUILayout.BeginHorizontal();
GUILayout.Label("Number of tiles to smooth: ");
if (numTerrains < 2) {
GUI.enabled = false;
setAutoSamples = false;
numSamplesAuto = EditorGUILayout.IntSlider(numSamplesAuto, 0, 0);
} else {
var width = selected[0].GetComponent(Terrain).terrainData.heightmapWidth;
if (!setAutoSamples) {
numSamplesAuto = width / 25 > 0 ? width / 25 : 1;
setAutoSamples = true;
}
numSamplesAuto = EditorGUILayout.IntSlider(numSamplesAuto, 1, width);
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("Stitch Selected"))
stitchTerrains(selected, numSamplesAuto);
EditorGUILayout.EndHorizontal();
EditorGUILayout.Space();
/* MANUAL STITCHING */
GUI.enabled = true;
GUILayout.Label("Manual Stitching");
terrain1 = EditorGUILayout.ObjectField("Terrain 1", terrain1, Terrain, true);
terrain2 = EditorGUILayout.ObjectField("Terrain 2", terrain2, Terrain, true);
EditorGUILayout.BeginHorizontal();
GUILayout.Label(GUIContent("Don't alter corners of terrain: ", "(0 = alter both terrains)"));
dominatingTerrain = EditorGUILayout.IntSlider(dominatingTerrain, 0, 2);
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
GUILayout.Label("Number of samples to smooth: ");
if (terrain1 == null || terrain2 == null) {
GUI.enabled = false;
setManualSamples = false;
numSamplesManual = EditorGUILayout.IntSlider(numSamplesManual, 0, 0);
} else {
width = terrain1.terrainData.heightmapWidth;
if (!setManualSamples) {
numSamplesManual = width / 25 > 0 ? width / 25 : 1;
setManualSamples = true;
}
numSamplesManual = EditorGUILayout.IntSlider(numSamplesManual, 1, width);
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("Stitch")) {
TerrainStitcher.stitch(terrain1, terrain2, numSamplesManual, dominatingTerrain);
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.EndVertical();
}
}