Skip to content

Instantly share code, notes, and snippets.

@andybak
Created October 16, 2018 08:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save andybak/409cdc37f3f7116d93eac738995d14ab to your computer and use it in GitHub Desktop.
Save andybak/409cdc37f3f7116d93eac738995d14ab to your computer and use it in GitHub Desktop.
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;
}
}
}
// 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;
}
}
}
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);
}
}
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