Created
October 16, 2018 08:52
-
-
Save andybak/409cdc37f3f7116d93eac738995d14ab to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using System; | |
using System.Collections; | |
public class SubdivideDialog : Dialog { | |
ThingPart thingPart; | |
bool dropVertexMoverOnClosing = true; | |
VertexMover vertexMover = null; | |
GameObject confirmButton = null; | |
ThingPartBase baseGroup = ThingPartBase.Cube; | |
public void Start() { | |
Init(gameObject); | |
AddFundament(); | |
AddBackButton(); | |
AddCloseButton(); | |
AddHeadline("Detail"); | |
if (CreationHelper.thingPartWhoseStatesAreEdited != null) { | |
thingPart = CreationHelper.thingPartWhoseStatesAreEdited.GetComponent<ThingPart>(); | |
baseGroup = (ThingPartBase)Managers.thingManager.GetSubdividableGroup(thingPart.baseType); | |
} | |
vertexMover = (VertexMover) | |
Managers.personManager.OurPersonRig.GetComponentInChildren<VertexMover>(); | |
AddButtons(); | |
AddGenericHelpButton(); | |
} | |
void AddButtons() { | |
wrapper = GetUiWrapper(); | |
SetUiWrapper(wrapper); | |
const int spacing = 160; | |
ThingPartBase defaultBaseType = baseGroup == ThingPartBase.Cube ? | |
ThingPartBase.Cube : ThingPartBase.Quad; | |
string baseTypeString = baseGroup == ThingPartBase.Cube ? | |
"Cube" : "Quad"; | |
for (int x = 0; x <= 4; x++) { | |
for (int y = 0; y <= 3; y++) { | |
int linesX = x + 2; | |
int linesY = y + 2; | |
string name = linesX + "x" + linesY; | |
string icon = "SubdividedCube/" + name; | |
int positionX = (x - 2) * spacing; | |
int positionY = -220 + y * spacing; | |
ThingPartBase baseType = defaultBaseType; | |
if ( !(x == 0 && y == 0) ) { | |
baseType = (ThingPartBase) Enum.Parse( typeof(ThingPartBase), | |
baseTypeString + name, true ); | |
} | |
bool state = baseType == thingPart.baseType; | |
string contextName = thingPart.changedVertices != null && | |
thingPart.changedVertices.Count >= 1 ? | |
"confirmChoose" : "choose"; | |
GameObject button = AddButton( | |
contextName, baseType.ToString(), null, "ButtonSmall", | |
positionX, positionY, icon: icon, state: state ); | |
DialogPart dialogPart = button.GetComponent<DialogPart>(); | |
dialogPart.autoStopHighlight = false; | |
} | |
} | |
SetUiWrapper(gameObject); | |
} | |
void Update() { | |
if (thingPart == null || vertexMover == null) { CloseDialog(); } | |
base.Update(); | |
} | |
void DropVertexMover() { | |
if (vertexMover != null && vertexMover.transform.parent != null) { | |
Destroy(vertexMover.transform.parent.gameObject); | |
} | |
} | |
void OnDestroy() { | |
if (dropVertexMoverOnClosing) { | |
DropVertexMover(); | |
} | |
} | |
public override void OnClick(string contextName, string contextId, bool state, GameObject thisButton) { | |
switch (contextName) { | |
case "confirmChoose": { | |
ThingPartBase baseType = (ThingPartBase) Enum.Parse( typeof(ThingPartBase), contextId, true ); | |
if (baseType == thingPart.baseType) { | |
dropVertexMoverOnClosing = false; | |
SwitchTo(DialogType.VertexMover); | |
} | |
else { | |
Destroy(confirmButton); | |
Destroy(wrapper); | |
SetUiWrapper(gameObject); | |
confirmButton = AddButton( "choose", baseType.ToString(), | |
"Reset points to this?", | |
"ButtonCompactNoIcon", 0, -10 ); | |
} | |
} | |
break; | |
case "choose": { | |
ThingPartBase baseType = (ThingPartBase) Enum.Parse( typeof(ThingPartBase), contextId, true ); | |
if (baseType != thingPart.baseType) { | |
vertexMover.SwitchToNewMeshForSubdivision(baseType); | |
Managers.soundManager.Play("success", transform, 0.15f); | |
} | |
dropVertexMoverOnClosing = false; | |
SwitchTo(DialogType.VertexMover); | |
} | |
break; | |
case "help": | |
Managers.browserManager.OpenGuideBrowser("CBOPUw9-Ecg"); | |
break; | |
case "close": | |
CloseDialog(); | |
break; | |
case "back": | |
dropVertexMoverOnClosing = false; | |
SwitchTo(DialogType.VertexMover); | |
break; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// vertices function | |
static string GetChangedVerticesJson(ThingPart thingPart, Dictionary<string,int> changedVerticesIndexReference, int indexWithinThing) { | |
// Changed Vertices c: [ [x, y, z, i1, relative i2, ...], ... ] | |
string s = ""; | |
Dictionary<string,string> indicesByPosition = new Dictionary<string,string>(); | |
foreach (KeyValuePair<int,Vector3> item in thingPart.changedVertices) { | |
int index = item.Key; | |
Vector3 position = item.Value; | |
string positionString = JsonHelper.GetJsonNoBrackets(position); | |
if ( !indicesByPosition.ContainsKey(positionString) ) { | |
string indices = ""; | |
int previousInnerIndex = 0; | |
foreach (KeyValuePair<int,Vector3> innerItem in thingPart.changedVertices) { | |
int innerIndex = innerItem.Key; | |
Vector3 innerPosition = innerItem.Value; | |
if ( JsonHelper.GetJsonNoBrackets(innerPosition) == positionString ) { | |
if (indices != "") { indices += ","; } | |
int relativeIndex = innerIndex - previousInnerIndex; | |
indices += relativeIndex.ToString(); | |
previousInnerIndex = innerIndex; | |
} | |
} | |
indicesByPosition[positionString] = indices; | |
} | |
} | |
foreach (KeyValuePair<string,string> item in indicesByPosition) { | |
if (s != "") { s += ","; } | |
s += "[" + item.Key + "," + item.Value + "]"; | |
} | |
if (s != "") { | |
s = "\"c\":[" + s + "]"; | |
string key = s; | |
if (thingPart.smoothingAngle != null) { key += ( (int) thingPart.smoothingAngle ).ToString(); } | |
key += "_"; | |
if (thingPart.convex != null) { key += thingPart.convex == true ? "1" : "0"; } | |
int existingIndex; | |
if ( changedVerticesIndexReference.TryGetValue(key, out existingIndex) ) { | |
s = "\"v\":" + existingIndex; | |
thingPart.smoothingAngle = null; | |
thingPart.convex = null; | |
} | |
else { | |
changedVerticesIndexReference[key] = indexWithinThing; | |
} | |
} | |
return s; | |
} | |
#4 | |
Philipp [developer] 19 hours ago | |
JsonToThingConverter.cs vertices function | |
static void ApplyVertexChangesAndSmoothingAngle(ThingPart thingPart, JSONNode partNode, bool isForEditing, JSONNode thingNode) { | |
if (partNode["c"] != null || partNode["v"] != null || partNode["sa"] != null) { | |
MeshFilter meshFilter = thingPart.GetComponent<MeshFilter>(); | |
if (meshFilter == null) { return; } | |
Mesh mesh = meshFilter.mesh; | |
// Changed Vertices reference v: 2 | |
if (partNode["v"] != null) { | |
int indexReference = partNode["v"].AsInt; | |
partNode["c"] = thingNode[indexReference]["c"]; | |
if (thingNode[indexReference]["sa"] != null) { | |
partNode["sa"] = thingNode[indexReference]["sa"]; | |
} | |
if (thingNode[indexReference]["cx"] != null) { | |
partNode["cx"] = thingNode[indexReference]["cx"]; | |
} | |
} | |
// Changed Vertices c: [ [x, y, z, i1, relative i2, ...], ... ] | |
if (partNode["c"] != null) { | |
Vector3[] vertices = mesh.vertices; | |
if (isForEditing) { | |
thingPart.changedVertices = new Dictionary<int,Vector3>(); | |
} | |
int itemMax = partNode["c"].Count; | |
for (int itemI = 0; itemI < itemMax; itemI++) { | |
JSONNode item = partNode["c"][itemI]; | |
Vector3 vector = new Vector3(item[0].AsFloat, item[1].AsFloat, item[2].AsFloat); | |
int vertexMax = item.Count; | |
int previousVertexIndex = 0; | |
for (int vertexI = 3; vertexI < vertexMax; vertexI++) { | |
int relativeVertexIndex = item[vertexI].AsInt; | |
int vertexIndex = previousVertexIndex + relativeVertexIndex; | |
vertices[vertexIndex] = vector; | |
previousVertexIndex = vertexIndex; | |
if (isForEditing) { | |
thingPart.changedVertices[vertexIndex] = vector; | |
} | |
} | |
} | |
mesh.vertices = vertices; | |
} | |
// Smoothing Angle | |
int smoothingAngle = 0; | |
if (partNode["sa"] != null) { | |
thingPart.smoothingAngle = partNode["sa"].AsInt; | |
smoothingAngle = (int)thingPart.smoothingAngle; | |
} | |
else { | |
int defaultSmoothingAngle = 0; | |
if ( Managers.thingManager.smoothingAngles.TryGetValue(thingPart.baseType, out defaultSmoothingAngle) ) { | |
smoothingAngle = defaultSmoothingAngle; | |
} | |
} | |
// Convex override | |
if (partNode["cx"] != null) { | |
thingPart.convex = partNode["cx"].AsInt == 1; | |
} | |
mesh.RecalculateNormals(smoothingAngle); | |
bool usePreciseCollision = mesh.vertices.Length <= VertexMover.maxVertexCountForPreciseCollisions; | |
if (usePreciseCollision) { | |
RecreateColliderAndChangeTypeIfNeeded(thingPart, mesh); | |
} | |
mesh.RecalculateTangents(); | |
} | |
else if (partNode["cx"] != null) { | |
thingPart.convex = partNode["cx"].AsInt == 1; | |
MeshCollider meshCollider = thingPart.GetComponent<MeshCollider>(); | |
if (meshCollider != null) { | |
meshCollider.convex = (bool)thingPart.convex; | |
} | |
} | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using System; | |
using System.Collections; | |
using System.Collections.Generic; | |
public class VertexMover : MonoBehaviour { | |
public Material wireframeMaterial; | |
ThingPart thingPart; | |
Thing thing; | |
bool pressed = false; | |
public Transform[] tweezers; | |
Hand hand = null; | |
public HandDot handDot { get; private set; } | |
public Mesh mesh = null; | |
bool didLetGoSinceGrabbing = false; | |
GameObject vertexHighlight; | |
int defaultSmoothingAngle = 0; | |
float tweezerAngle = 0f; | |
ThingPart appliedWireframeThingPart = null; | |
int closestVertexIndex = -1; | |
int grabbedVertexIndex = -1; | |
Vector3 grabStart = Vector3.zero; | |
Vector3 originalVertexPosition = Vector3.zero; | |
Vector3 grabStartVertex = Vector3.zero; | |
public static bool snapPosition = false; | |
public static bool snapToGrid = false; | |
public static bool showEdges = false; | |
public static bool separatePoints = false; | |
public const int maxVertexCountForPreciseCollisions = 500; | |
public const int positionFloatDigits = 3; | |
Mesh insideMesh = null; | |
void Start() { | |
hand = transform.parent.parent.GetComponent<Hand>(); | |
handDot = hand.handDot.GetComponent<HandDot>(); | |
didLetGoSinceGrabbing = CrossDevice.type == DeviceType.OculusTouch; | |
vertexHighlight = (GameObject)GameObject.Instantiate( Resources.Load("Prefabs/VertexHighlight") ); | |
Misc.RemoveCloneFromName(vertexHighlight); | |
SetThingPart( CreationHelper.thingPartWhoseStatesAreEdited.GetComponent<ThingPart>() ); | |
} | |
public void SetThingPart(ThingPart thingPart) { | |
if (grabbedVertexIndex != -1 && mesh != null) { | |
UpdateMeshAfterChanges(); | |
} | |
this.thingPart = thingPart; | |
thing = this.thingPart.GetMyRootThing(); | |
Managers.thingManager.smoothingAngles.TryGetValue(thingPart.baseType, out defaultSmoothingAngle); | |
MeshFilter meshFilter = this.thingPart.GetComponent<MeshFilter>(); | |
if (meshFilter != null) { | |
mesh = meshFilter.mesh; | |
mesh.MarkDynamic(); | |
} | |
SetVertexHighlightColor(); | |
UpdateBasedOnShowEdges(); | |
ResetGrabData(); | |
} | |
void ResetGrabData() { | |
pressed = false; | |
closestVertexIndex = -1; | |
grabbedVertexIndex = -1; | |
grabStart = Vector3.zero; | |
grabStartVertex = Vector3.zero; | |
originalVertexPosition = Vector3.zero; | |
vertexHighlight.SetActive(false); | |
} | |
void Update() { | |
if (thingPart == null || mesh == null || hand == null || | |
Our.mode != EditModes.Thing || CreationHelper.thingPartWhoseStatesAreEdited == null) { | |
Destroy(transform.parent.gameObject); | |
return; | |
} | |
AdjustVertexHighlightSizeByDistance(); | |
HandlePress(); | |
FollowTweezerTargets(); | |
if (grabbedVertexIndex == -1 && !pressed) { | |
SetClosestVertex(); | |
} | |
if (grabbedVertexIndex != -1) { | |
AdjustGrabbedVertexPosition(); | |
hand.TriggerHapticPulse(Universe.veryLowHapticPulse); | |
} | |
} | |
void AdjustVertexHighlightSizeByDistance() { | |
if (vertexHighlight != null) { | |
Vector3 ourPosition = Managers.personManager.ourPerson.Head.transform.position; | |
float distance = Vector3.Distance(ourPosition, vertexHighlight.transform.position); | |
float scale = distance * 0.005f; | |
vertexHighlight.transform.localScale = Misc.GetUniformVector3( Mathf.Clamp(scale, 0.01f, 10f) ); | |
} | |
} | |
void AdjustGrabbedVertexPosition(bool roundIfNeeded = false) { | |
Vector3 offset = transform.position - grabStart; | |
Vector3 absoluteNewVertexPosition = originalVertexPosition + offset; | |
vertexHighlight.transform.position = absoluteNewVertexPosition; | |
Vector3[] vertices = mesh.vertices; | |
Vector3 oldPosition = vertices[grabbedVertexIndex]; | |
Vector3 newPosition = thingPart.transform.InverseTransformPoint(absoluteNewVertexPosition); | |
if (oldPosition != newPosition) { | |
if (snapPosition) { | |
newPosition = SnapHelper.SnapPositionAlongAxis(newPosition, grabStartVertex); | |
} | |
if (snapToGrid) { | |
newPosition = SnapToGrid(newPosition, 0.1f); | |
} | |
vertexHighlight.transform.position = thingPart.transform.TransformPoint(newPosition); | |
if (thingPart.changedVertices == null) { | |
thingPart.changedVertices = new Dictionary<int,Vector3>(); | |
} | |
if ( roundIfNeeded && Misc.GetLargestValueOfVector(thingPart.transform.localScale) <= 10f ) { | |
newPosition = Misc.ReduceVector3Digits(newPosition, positionFloatDigits); | |
} | |
if (separatePoints) { | |
vertices[grabbedVertexIndex] = newPosition; | |
thingPart.changedVertices[grabbedVertexIndex] = newPosition; | |
} | |
else { | |
for (int i = 0; i < vertices.Length; i++) { | |
if (vertices\[i\] == oldPosition) { | |
vertices\[i\] = newPosition; | |
thingPart.changedVertices\[i\] = newPosition; | |
} | |
} | |
} | |
} | |
mesh.vertices = vertices; | |
RecalculateNormals(); | |
} | |
Vector3 SnapToGrid(Vector3 position, float gridSize) { | |
return new Vector3( | |
SnapHelper.SnapValueToGrid(position.x, gridSize), | |
SnapHelper.SnapValueToGrid(position.y, gridSize), | |
SnapHelper.SnapValueToGrid(position.z, gridSize) | |
); | |
} | |
void SetClosestVertex() { | |
const float maxDistance = 100f; | |
float closestDistance = maxDistance; | |
int closestIndex = -1; | |
Vector3 closestPosition = Vector3.zero; | |
Vector3 sourcePosition = transform.position; | |
Transform targetTransform = thingPart.transform; | |
Vector3[] vertices = mesh.vertices; | |
for (int i = 0; i < vertices.Length; i++) { | |
Vector3 vertexPosition = targetTransform.TransformPoint(vertices\[i\]); | |
float distance = Vector3.Distance(sourcePosition, vertexPosition); | |
if (distance <= closestDistance) { | |
closestIndex = i; | |
closestPosition = vertexPosition; | |
closestDistance = distance; | |
} | |
} | |
if (closestIndex != -1) { | |
if (closestVertexIndex != closestIndex) { | |
closestVertexIndex = closestIndex; | |
hand.TriggerHapticPulse(Universe.lowHapticPulse); | |
} | |
vertexHighlight.SetActive(true); | |
vertexHighlight.transform.position = closestPosition; | |
originalVertexPosition = closestPosition; | |
} | |
else { | |
vertexHighlight.SetActive(false); | |
} | |
} | |
void OnTriggerStay(Collider other) { | |
if ( handDot != null && !other.gameObject.CompareTag("ThingPart") ) { | |
handDot.HandlePressableDialogPartCollision(other); | |
} | |
} | |
void HandlePress() { | |
if ( hand.GetPressDown(CrossDevice.button_grabTip) ) { | |
if (didLetGoSinceGrabbing && !thingPart.isLocked) { | |
pressed = true; | |
grabbedVertexIndex = closestVertexIndex; | |
grabStart = transform.position; | |
grabStartVertex = mesh.vertices[grabbedVertexIndex]; | |
} | |
} | |
else if ( hand.GetPressUp(CrossDevice.button_grabTip) ) { | |
didLetGoSinceGrabbing = true; | |
pressed = false; | |
if (grabbedVertexIndex != -1) { | |
AdjustGrabbedVertexPosition(roundIfNeeded: true); | |
grabbedVertexIndex = -1; | |
UpdateMeshAfterChanges(); | |
} | |
} | |
if ( CrossDevice.type == DeviceType.OculusTouch && hand.GetPressUp(CrossDevice.button_grab) ) { | |
if ( Managers.dialogManager.GetCurrentNonStartDialogType() == DialogType.VertexMover ) { | |
Managers.dialogManager.SwitchToNewDialog(DialogType.ThingPart); | |
} | |
else { | |
Destroy(transform.parent.gameObject); | |
} | |
} | |
} | |
public void UpdateMeshAfterChanges() { | |
RecalculateNormals(); | |
bool usePreciseCollision = mesh.vertices.Length <= VertexMover.maxVertexCountForPreciseCollisions; | |
if (usePreciseCollision) { | |
JsonToThingConverter.RecreateColliderAndChangeTypeIfNeeded(thingPart, mesh); | |
} | |
mesh.RecalculateTangents(); | |
CreateInsideMeshFacesIfNeeded(); | |
} | |
public void ResetAll() { | |
int baseIndex = (int)thingPart.baseType; | |
GameObject baseShape = (GameObject)UnityEngine.Object.Instantiate( | |
Managers.thingManager.thingPartBases[baseIndex]); | |
MeshFilter baseMeshFilter = baseShape.GetComponent<MeshFilter>(); | |
mesh.vertices = baseMeshFilter.mesh.vertices; | |
Destroy(baseShape); | |
thingPart.changedVertices = null; | |
thingPart.smoothingAngle = null; | |
UpdateMeshAfterChanges(); | |
} | |
public void RecalculateNormals() { | |
int smoothingAngle = thingPart.smoothingAngle != null ? | |
(int)thingPart.smoothingAngle : defaultSmoothingAngle; | |
mesh.RecalculateNormals(smoothingAngle); | |
} | |
void FollowTweezerTargets() { | |
Vector3 rotation; | |
tweezerAngle = Mathf.MoveTowards(tweezerAngle, | |
pressed ? 5.35f : 0f, | |
100f * Time.deltaTime); | |
tweezers[0].localEulerAngles = new Vector3(-tweezerAngle, 0f, 0f); | |
tweezers[1].localEulerAngles = new Vector3( tweezerAngle, 0f, 0f); | |
} | |
void SetVertexHighlightColor() { | |
Renderer partRenderer = thingPart.GetComponent<Renderer>(); | |
if (partRenderer != null) { | |
float hue, saturation, lightness; | |
Color.RGBToHSV(partRenderer.material.color, out hue, out saturation, out lightness); | |
Renderer highlightRenderer = vertexHighlight.GetComponent<Renderer>(); | |
Color highlightColor = lightness <= 0.75f ? | |
new Color(1f, 1f, 1f, 0.5f) : | |
new Color(0f, 0f, 0f, 0.7f); | |
highlightRenderer.material.color = highlightColor; | |
} | |
} | |
public void UpdateBasedOnShowEdges() { | |
if (showEdges) { | |
Renderer partRenderer = thingPart.GetComponent<Renderer>(); | |
Material[] existingMaterials = partRenderer.materials; | |
Material[] newMaterials = new Material[existingMaterials.Length + 2]; | |
int i = 0; | |
for (i = 0; i < existingMaterials.Length; i++) { | |
newMaterials\[i\] = existingMaterials\[i\]; | |
} | |
float hue, saturation, lightness; | |
Color.RGBToHSV(partRenderer.material.color, out hue, out saturation, out lightness); | |
const float lightnessAdjust = 0.1f; | |
lightness = lightness <= 0.5f ? | |
lightness + lightnessAdjust : lightness - lightnessAdjust; | |
lightness = Mathf.Clamp(lightness, 0f, 1f); | |
Color edgeColor = Color.HSVToRGB(hue, saturation, lightness); | |
wireframeMaterial.SetColor("_ShaderColor", edgeColor); | |
wireframeMaterial.SetColor("_BaseColor", partRenderer.material.color); | |
wireframeMaterial.SetFloat("_ShaderStrength", 0.2f); | |
wireframeMaterial.SetInt("_WireSmoothness", 20); | |
newMaterials[++i] = wireframeMaterial; | |
partRenderer.materials = newMaterials; | |
appliedWireframeThingPart = thingPart; | |
} | |
else { | |
ClearCurrentAppliedWireframe(); | |
} | |
} | |
void ClearCurrentAppliedWireframe() { | |
if (appliedWireframeThingPart != null) { | |
appliedWireframeThingPart.UpdateTextures(forcedUpdate: true); | |
appliedWireframeThingPart = null; | |
} | |
} | |
public void SwitchToNewMeshForSubdivision(ThingPartBase baseType) { | |
int baseIndex = (int)baseType; | |
GameObject baseShape = (GameObject)UnityEngine.Object.Instantiate( | |
Managers.thingManager.thingPartBases[baseIndex]); | |
MeshFilter baseMeshFilter = baseShape.GetComponent<MeshFilter>(); | |
MeshFilter meshFilter = thingPart.GetComponent<MeshFilter>(); | |
meshFilter.sharedMesh = baseMeshFilter.mesh; | |
mesh = meshFilter.sharedMesh; | |
mesh.vertices = baseMeshFilter.mesh.vertices; | |
Destroy(baseShape); | |
mesh.RecalculateBounds(); | |
mesh.RecalculateNormals(); | |
mesh.RecalculateTangents(); | |
mesh = null; | |
mesh = thingPart.GetComponent<MeshFilter>().mesh; | |
thingPart.baseType = baseType; | |
UpdateMeshAfterChanges(); | |
} | |
void CreateInsideMeshFacesIfNeeded() { | |
if (separatePoints) { | |
if (insideMesh == null) { | |
GameObject clonedObject = (GameObject)Instantiate(thingPart.gameObject); | |
clonedObject.transform.parent = thingPart.transform; | |
clonedObject.transform.localPosition = Vector3.zero; | |
clonedObject.transform.localRotation = Quaternion.identity; | |
clonedObject.transform.localScale = Vector3.one; | |
Destroy( clonedObject.GetComponent<ThingPart>() ); | |
Destroy( clonedObject.GetComponent<Collider>() ); | |
clonedObject.tag = "Untagged"; | |
MeshFilter clonedMeshFilter = clonedObject.GetComponent<MeshFilter>(); | |
insideMesh = clonedMeshFilter.mesh; | |
clonedObject.GetComponent<MeshFilter>().mesh = insideMesh; | |
InvertNormals(insideMesh); | |
} | |
else { | |
insideMesh.vertices = mesh.vertices; | |
} | |
} | |
} | |
void InvertNormals(Mesh mesh) { | |
Vector3[] normals = mesh.normals; | |
for (int i = 0; i < normals.Length; i++) { | |
normals\[i\] = -normals\[i\]; | |
} | |
mesh.normals = normals; | |
for (int m = 0; m < mesh.subMeshCount; m++) { | |
int[] triangles = mesh.GetTriangles(m); | |
for (int i = 0; i < triangles.Length; i += 3) { | |
int temp = triangles[i + 0]; | |
triangles[i + 0] = triangles[i + 1]; | |
triangles[i + 1] = temp; | |
} | |
mesh.SetTriangles(triangles, m); | |
} | |
} | |
void OnDestroy() { | |
ClearCurrentAppliedWireframe(); | |
Destroy(vertexHighlight); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using System; | |
using System.Collections; | |
public class VertexMoverDialog : Dialog { | |
ThingPart thingPart; | |
bool dropVertexMoverOnClosing = true; | |
VertexMover vertexMover = null; | |
DialogSlider slider; | |
const float sliderOffset = 0f; | |
const float sliderFactor = 1.8f; | |
int defaultSmoothingAngle = 0; | |
GameObject lockButton = null; | |
GameObject secondaryWrapper = null; | |
GameObject resetAllButton = null; | |
bool originalMeshIsConvex = true; | |
public void Start() { | |
Init(gameObject); | |
AddFundament(); | |
AddBackButton(); | |
AddModelButton("MinimizeButton", "minimize", xOnFundament: -170); | |
AddCloseButton(); | |
if (CreationHelper.thingPartWhoseStatesAreEdited != null) { | |
thingPart = CreationHelper.thingPartWhoseStatesAreEdited.GetComponent<ThingPart>(); | |
SetOriginalMeshIsConvex(); | |
} | |
else { | |
return; | |
} | |
vertexMover = (VertexMover) | |
Managers.personManager.OurPersonRig.GetComponentInChildren<VertexMover>(); | |
Managers.thingManager.smoothingAngles.TryGetValue(thingPart.baseType, out defaultSmoothingAngle); | |
AddInterface(); | |
} | |
void SetOriginalMeshIsConvex() { | |
int baseIndex = (int)thingPart.baseType; | |
GameObject baseShape = (GameObject)UnityEngine.Object.Instantiate( | |
Managers.thingManager.thingPartBases[baseIndex]); | |
MeshCollider meshCollider = baseShape.GetComponent<MeshCollider>(); | |
originalMeshIsConvex = meshCollider == null || meshCollider.convex; | |
} | |
void AddInterface() { | |
if (thingPart.isLocked) { | |
Destroy(wrapper); | |
Destroy(secondaryWrapper); | |
lockButton = AddModelButton("Lock", "toggleLock", null, 0, -15); | |
ApplyEmissionColorToShape(lockButton, true); | |
} | |
else { | |
Destroy(lockButton); | |
AddIconCheckboxes(); | |
StartCoroutine( DoAddInterface() ); | |
StartCoroutine( DoAddBacksideInterface() ); | |
} | |
} | |
IEnumerator DoAddInterface() { | |
if (secondaryWrapper != null) { Destroy(secondaryWrapper); yield return false; } | |
secondaryWrapper = GetUiWrapper(); | |
SetUiWrapper(secondaryWrapper); | |
AddButtons(); | |
AddSlider(); | |
SetUiWrapper(gameObject); | |
} | |
IEnumerator DoAddBacksideInterface() { | |
if (backsideWrapper != null) { Destroy(backsideWrapper); yield return false; } | |
backsideWrapper = GetUiWrapper(); | |
SetUiWrapper(backsideWrapper); | |
MeshFilter meshFilter = thingPart.GetComponent<MeshFilter>(); | |
int meshCount = meshFilter.mesh.vertices.Length; | |
bool usePreciseCollision = meshCount <= VertexMover.maxVertexCountForPreciseCollisions; | |
AddLabel("Points: " + meshCount, 0, -60, align: TextAlignment.Center); | |
AddLabel("Collision: " + (usePreciseCollision ? "Precise": "Based on original"), | |
0, 40, align: TextAlignment.Center, | |
textColor: (usePreciseCollision ? TextColor.Green : TextColor.Gray) | |
); | |
/* | |
AddIconCheckbox("separatePoints", null, "Separate" + Environment.NewLine + "points", | |
-400, 380, | |
"SeparatePoints", state: VertexMover.separatePoints); | |
*/ | |
int helpX = 420 * (handSide == Side.Left ? -1 : 1); | |
AddHelpButton("help", helpX, -420); | |
RotateBacksideWrapper(); | |
SetUiWrapper(gameObject); | |
} | |
void AddButtons() { | |
ThingPartBase? subdividableBaseGroup = Managers.thingManager.GetSubdividableGroup(thingPart.baseType); | |
if (subdividableBaseGroup != null) { | |
AddButton("subdivide", null, "Detail...", "ButtonCompactSquareIcon", 235, -77, | |
icon: "SubdividedCube/SquareIcon"); | |
} | |
bool convex = originalMeshIsConvex; | |
if (thingPart.convex != null) { convex = (bool)thingPart.convex; } | |
AddCheckbox("concave", null, "Hollow collision", 235, 400, !convex, | |
prefabName: "CheckboxCompact", extraIcon: ExtraIcon.Concave); | |
AddResetAllConfirmButton(); | |
} | |
void AddResetAllButton(bool isConfirm = false) { | |
string name = isConfirm ? "resetAllConfirm" : "resetAll"; | |
string label = isConfirm ? "Reset..." : "Reset all?"; | |
TextColor textColor = isConfirm ? TextColor.Gray : TextColor.Red; | |
Destroy(resetAllButton); | |
resetAllButton = AddButton( | |
name, null, label, "ButtonCompactNoIcon", -235, 400, | |
textColor: textColor); | |
} | |
void AddResetAllConfirmButton() { | |
AddResetAllButton(isConfirm: true); | |
} | |
void AddIconCheckboxes() { | |
StartCoroutine( DoAddIconCheckboxes() ); | |
} | |
IEnumerator DoAddIconCheckboxes() { | |
if (wrapper != null) { Destroy(wrapper); yield return false; } | |
const int x = -400, y = -280; | |
const int buttonSpaceX = 475, buttonSpaceY = 180; | |
wrapper = GetUiWrapper(); | |
SetUiWrapper(wrapper); | |
AddIconCheckbox("snapPosition", null, "Snap" + Environment.NewLine + "position", | |
x + buttonSpaceX * 0, y + buttonSpaceY * 0, | |
"SnapVertexPosition", state: VertexMover.snapPosition); | |
AddIconCheckbox("showEdges", null, "Show" + Environment.NewLine + "edges", | |
x + buttonSpaceX * 1, y + buttonSpaceY * 0, | |
"ShowEdges", state: VertexMover.showEdges); | |
AddIconCheckbox("snapToGrid", null, "Snap to" + Environment.NewLine + "grid", | |
x + buttonSpaceX * 0, y + buttonSpaceY * 1, | |
"SnapToVertexGrid", state: VertexMover.snapToGrid); | |
SetUiWrapper(gameObject); | |
} | |
void AddSlider() { | |
int smoothingAngle = thingPart.smoothingAngle != null ? | |
(int)thingPart.smoothingAngle : defaultSmoothingAngle; | |
slider = AddSlider(y: 190, value: smoothingAngle, textSizeFactor: 0.8f, | |
minValue: 0f, maxValue: 180f, | |
onValueChange: OnSliderChange, valuePrefix: "Smoothing: ", | |
roundValues: true, showValue: true); | |
FinalizeSlider(); | |
} | |
void OnSliderChange(float value) { | |
thingPart.smoothingAngle = Mathf.RoundToInt(value); | |
if (thingPart.smoothingAngle == defaultSmoothingAngle) { | |
thingPart.smoothingAngle = null; | |
} | |
vertexMover.RecalculateNormals(); | |
FinalizeSlider(); | |
} | |
void FinalizeSlider() { | |
slider.valueSuffix = thingPart.smoothingAngle == null ? | |
" (Default)".ToUpper() : ""; | |
} | |
void Update() { | |
if (thingPart == null || vertexMover == null) { CloseDialog(); } | |
ReactToOnClickInWrapper(secondaryWrapper); | |
base.Update(); | |
} | |
public void SetThingPart(ThingPart thingPart) { | |
this.thingPart.UpdateTextures(forcedUpdate: true); | |
this.thingPart = thingPart; | |
SetOriginalMeshIsConvex(); | |
defaultSmoothingAngle = 0; | |
Managers.thingManager.smoothingAngles.TryGetValue(this.thingPart.baseType, out defaultSmoothingAngle); | |
AddInterface(); | |
} | |
void DropVertexMover() { | |
if (vertexMover != null && vertexMover.transform.parent != null) { | |
Destroy(vertexMover.transform.parent.gameObject); | |
} | |
} | |
void OnDestroy() { | |
if (dropVertexMoverOnClosing) { | |
DropVertexMover(); | |
} | |
} | |
void UpdateConvexBasedOnValue() { | |
MeshCollider meshCollider = thingPart.GetComponent<MeshCollider>(); | |
if (meshCollider != null) { | |
bool convex = originalMeshIsConvex; | |
if (thingPart.convex != null) { convex = (bool)thingPart.convex; } | |
meshCollider.convex = convex; | |
} | |
} | |
public override void OnClick(string contextName, string contextId, bool state, GameObject thisButton) { | |
switch (contextName) { | |
case "snapPosition": | |
VertexMover.snapPosition = state; | |
break; | |
case "snapToGrid": | |
VertexMover.snapToGrid = state; | |
break; | |
case "separatePoints": | |
VertexMover.separatePoints = state; | |
break; | |
case "showEdges": | |
VertexMover.showEdges = state; | |
vertexMover.UpdateBasedOnShowEdges(); | |
break; | |
case "resetAllConfirm": | |
CancelInvoke("AddResetAllConfirmButton"); | |
AddResetAllButton(); | |
Invoke("AddResetAllConfirmButton", 4f); | |
break; | |
case "resetAll": | |
CancelInvoke("AddResetAllConfirmButton"); | |
vertexMover.ResetAll(); | |
Managers.soundManager.Play("success", transform, 0.2f); | |
thingPart.convex = null; | |
UpdateConvexBasedOnValue(); | |
AddInterface(); | |
break; | |
case "toggleLock": | |
thingPart.isLocked = false; | |
Destroy(lockButton); | |
AddInterface(); | |
break; | |
case "subdivide": | |
dropVertexMoverOnClosing = false; | |
SwitchTo(DialogType.Subdivide); | |
break; | |
case "concave": | |
bool convex = !state; | |
thingPart.convex = null; | |
if (convex != originalMeshIsConvex) { | |
thingPart.convex = convex; | |
} | |
UpdateConvexBasedOnValue(); | |
break; | |
case "help": | |
Managers.browserManager.OpenGuideBrowser("CBOPUw9-Ecg"); | |
break; | |
case "minimize": | |
dropVertexMoverOnClosing = false; | |
CloseDialog(); | |
break; | |
case "close": | |
CloseDialog(); | |
break; | |
case "back": | |
SwitchTo(DialogType.ThingPart); | |
break; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment