/************************************************************************************
|
|
Filename : ONSPPropagationMaterialEditor.cs
|
|
Content : Propagation material editor class
|
|
Attach to geometry to define material properties
|
|
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
|
|
|
|
Licensed under the Oculus SDK Version 3.5 (the "License");
|
|
you may not use the Oculus SDK except in compliance with the License,
|
|
which is provided at the time of installation or download, or which
|
|
otherwise accompanies this software in either electronic or hard copy form.
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
https://developer.oculus.com/licenses/sdk-3.5/
|
|
|
|
Unless required by applicable law or agreed to in writing, the Oculus SDK
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
************************************************************************************/
|
|
using UnityEditor;
|
|
using UnityEngine;
|
|
|
|
using Spectrum = ONSPPropagationMaterial.Spectrum;
|
|
using Point = ONSPPropagationMaterial.Point;
|
|
|
|
[CustomEditor(typeof(ONSPPropagationMaterial))]
|
|
internal sealed class ONSPPropagationMaterialEditor : Editor{
|
|
|
|
private enum AxisScale{ Lin, Log, Sqr }
|
|
|
|
private sealed class SpectrumDrawer{
|
|
|
|
private const float cutoff = 20000f;
|
|
|
|
private static readonly Texture2D texture = EditorGUIUtility.whiteTexture;
|
|
|
|
private static readonly GUIStyle textStyle = new GUIStyle{
|
|
|
|
alignment = TextAnchor.MiddleLeft,
|
|
clipping = TextClipping.Overflow,
|
|
fontSize = 8,
|
|
fontStyle = FontStyle.Bold,
|
|
wordWrap = false,
|
|
normal = new GUIStyleState{ textColor = Color.grey },
|
|
focused = new GUIStyleState{ textColor = Color.grey }
|
|
|
|
};
|
|
|
|
private static int focus;
|
|
|
|
private readonly string label;
|
|
|
|
private readonly AxisScale scale;
|
|
private readonly Spectrum spectrum;
|
|
|
|
private bool dragInitiated;
|
|
private bool isDragging;
|
|
|
|
private bool displaySpectrum;
|
|
private bool displayPoints;
|
|
|
|
internal bool IsFocus{
|
|
|
|
get{
|
|
|
|
return focus == spectrum.GetHashCode();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
internal SpectrumDrawer(string label, Spectrum spectrum, AxisScale scale){
|
|
|
|
this.label = label;
|
|
this.spectrum = spectrum;
|
|
this.scale = scale;
|
|
|
|
}
|
|
|
|
internal void Draw(Event e){
|
|
|
|
displaySpectrum = EditorGUILayout.Foldout(displaySpectrum, label);
|
|
|
|
if(displaySpectrum){
|
|
|
|
EditorGUI.indentLevel++;
|
|
DrawSpectrum(e);
|
|
|
|
displayPoints = EditorGUILayout.Foldout(displayPoints, "Points");
|
|
|
|
if(displayPoints){
|
|
|
|
EditorGUI.indentLevel++;
|
|
DrawPoints();
|
|
EditorGUI.indentLevel--;
|
|
|
|
}
|
|
|
|
EditorGUI.indentLevel--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
internal void LoadFoldoutState(){
|
|
|
|
displaySpectrum = EditorPrefs.GetBool(label + "Spectrum", true);
|
|
displayPoints = EditorPrefs.GetBool(label + "Points", false);
|
|
|
|
}
|
|
|
|
internal void SaveFoldoutState(){
|
|
|
|
EditorPrefs.SetBool(label + "Spectrum", displaySpectrum);
|
|
EditorPrefs.SetBool(label + "Points", displayPoints);
|
|
|
|
}
|
|
|
|
private void DrawSpectrum(Event e){
|
|
|
|
float height = 10 * EditorGUIUtility.singleLineHeight;
|
|
Rect r = EditorGUILayout.GetControlRect(true, height);
|
|
|
|
r.width -= rightMargin;
|
|
DrawDataTicks(r);
|
|
r = AudioCurveRendering.BeginCurveFrame(r);
|
|
|
|
AudioCurveRendering.DrawFilledCurve(r, EvaluateCurve, AudioCurveRendering.kAudioOrange);
|
|
|
|
DrawFrequencyTicks(r);
|
|
|
|
HandleEvent(r, e);
|
|
if(IsFocus) DrawSelected(r);
|
|
|
|
AudioCurveRendering.EndCurveFrame();
|
|
|
|
}
|
|
|
|
private void DrawPoints(){
|
|
|
|
var points = spectrum.points;
|
|
int lines = points.Count > 0 ? points.Count + 2 : 1;
|
|
float height = EditorGUIUtility.singleLineHeight * lines;
|
|
Rect r1 = EditorGUILayout.GetControlRect(true, height);
|
|
r1.width -= rightMargin;
|
|
r1.height = EditorGUIUtility.singleLineHeight;
|
|
|
|
{
|
|
|
|
int oldCount = points.Count;
|
|
int newCount = EditorGUI.DelayedIntField(r1, "Size", oldCount);
|
|
r1.y += r1.height;
|
|
|
|
if(newCount < points.Count){
|
|
|
|
points.RemoveRange(newCount, oldCount - newCount);
|
|
Undo.SetCurrentGroupName("Points Removed");
|
|
GUI.changed = true;
|
|
|
|
} else if(newCount > oldCount){
|
|
|
|
if(newCount > points.Capacity)
|
|
points.Capacity = newCount;
|
|
|
|
for(int i = oldCount; i < newCount; i++)
|
|
points.Add(new Point(125 * (1 << i)));
|
|
|
|
Undo.SetCurrentGroupName("Points Added");
|
|
GUI.changed = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(points.Count > 0){
|
|
|
|
Rect r2 = new Rect(r1.xMax + 9, r1.y + r1.height * 1.125f, 24, r1.height * .75f);
|
|
|
|
r1.width /= 2;
|
|
EditorGUI.LabelField(r1, "Frequency");
|
|
r1.x += r1.width;
|
|
EditorGUI.LabelField(r1, "Data");
|
|
r1.x -= r1.width;
|
|
r1.y += r1.height;
|
|
|
|
for(int i = 0; i < points.Count; i++){
|
|
|
|
points[i].frequency = EditorGUI.FloatField(r1, points[i].frequency);
|
|
points[i].frequency = Mathf.Clamp(points[i].frequency, 0f, cutoff);
|
|
r1.x += r1.width;
|
|
points[i].data = EditorGUI.FloatField(r1, points[i].data);
|
|
points[i].data = Mathf.Clamp01(points[i].data);
|
|
r1.x -= r1.width;
|
|
r1.y += r1.height;
|
|
|
|
if(GUI.Button(r2, "–")){
|
|
|
|
RemovePointAt(i);
|
|
break;
|
|
|
|
}
|
|
|
|
r2.y += r1.height;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
private void DrawDataTicks(Rect r){
|
|
|
|
const int ticks = 10;
|
|
Rect label = new Rect(r.xMax + 9, r.y - r.height / (2 * ticks), 24, r.height / ticks);
|
|
Rect tick = new Rect(r.xMax + 2, r.y - 1, 4.5f, 2);
|
|
|
|
for(int i = 0; i <= ticks; i++){
|
|
|
|
float value = MapData(1 - (float)i / ticks, false);
|
|
|
|
EditorGUI.DrawRect(tick, textStyle.normal.textColor);
|
|
GUI.Label(label, value.ToString("0.000"), textStyle);
|
|
tick.y += label.height;
|
|
label.y += label.height;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
private void DrawFrequencyTicks(Rect r){
|
|
|
|
Rect tick = new Rect(r.x, r.y, 1, r.height);
|
|
Rect label = new Rect(r.x, r.yMax - 1.5f * EditorGUIUtility.singleLineHeight, 32, EditorGUIUtility.singleLineHeight);
|
|
|
|
for(int i = 1; i < 30; i++){
|
|
|
|
float frequency;
|
|
|
|
if(MapFrequencyTick(i, out frequency)){
|
|
|
|
tick.x = MapFrequency(frequency) * r.width;
|
|
tick.height = label.y - r.y;
|
|
tick.width = 2;
|
|
EditorGUI.DrawRect(tick, textStyle.normal.textColor);
|
|
|
|
tick.y = label.yMax;
|
|
tick.height = r.yMax - label.yMax;
|
|
EditorGUI.DrawRect(tick, textStyle.normal.textColor);
|
|
|
|
label.x = tick.x - 2;
|
|
GUI.Label(label, FrequencyToString(frequency), textStyle);
|
|
|
|
tick.y = r.y;
|
|
tick.height = r.height;
|
|
tick.width = 1;
|
|
|
|
} else{
|
|
|
|
tick.x = MapFrequency(frequency) * r.width;
|
|
EditorGUI.DrawRect(tick, textStyle.normal.textColor);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
private void DrawSelected(Rect r){
|
|
|
|
if(spectrum.points.Count > spectrum.selection){
|
|
|
|
const float radius = 12;
|
|
Vector2 position = MapPointPosition(r, spectrum.points[spectrum.selection]);
|
|
Vector2 size = new Vector2(radius, radius);
|
|
r = new Rect(position - size / 2, size);
|
|
|
|
#if UNITY_5
|
|
GUI.DrawTexture(r, texture, ScaleMode.StretchToFill, false, 0);
|
|
GUI.DrawTexture(r, texture, ScaleMode.StretchToFill, false, 0);
|
|
#else
|
|
GUI.DrawTexture(r, texture, ScaleMode.StretchToFill, false, 0, Color.white, 0, radius);
|
|
GUI.DrawTexture(r, texture, ScaleMode.StretchToFill, false, 0, Color.black, 2, radius);
|
|
#endif
|
|
|
|
}
|
|
}
|
|
|
|
private void HandleEvent(Rect r, Event e){
|
|
|
|
Vector2 position = e.mousePosition;
|
|
|
|
switch(e.type){
|
|
|
|
case EventType.MouseDown:
|
|
|
|
if(r.Contains(position)){
|
|
|
|
if(e.clickCount == 2){
|
|
|
|
spectrum.selection = spectrum.points.Count;
|
|
spectrum.points.Add(MapMouseEvent(r, position));
|
|
Undo.SetCurrentGroupName("Point Added");
|
|
GUI.changed = true;
|
|
|
|
} else{
|
|
|
|
int selection = spectrum.selection;
|
|
float minDistance = float.MaxValue;
|
|
|
|
for(int i = 0; i < spectrum.points.Count; i++){
|
|
|
|
float distance = Vector2.Distance(MapPointPosition(r, spectrum.points[i]), position);
|
|
|
|
if(distance < minDistance){
|
|
|
|
selection = i;
|
|
minDistance = distance;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(selection != spectrum.selection){
|
|
|
|
spectrum.selection = selection;
|
|
Undo.SetCurrentGroupName("Point Selected");
|
|
GUI.changed = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
focus = spectrum.GetHashCode();
|
|
dragInitiated = true;
|
|
|
|
} else{
|
|
|
|
isDragging = false;
|
|
focus = 0;
|
|
|
|
}
|
|
|
|
e.Use();
|
|
|
|
break;
|
|
|
|
case EventType.MouseDrag:
|
|
|
|
if(dragInitiated){
|
|
|
|
dragInitiated = false;
|
|
isDragging = true;
|
|
|
|
}
|
|
|
|
if(isDragging && spectrum.selection < spectrum.points.Count){
|
|
|
|
spectrum.points[spectrum.selection] = MapMouseEvent(r, position);
|
|
e.Use();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case EventType.Ignore:
|
|
case EventType.MouseUp:
|
|
|
|
dragInitiated = false;
|
|
|
|
if(isDragging){
|
|
|
|
isDragging = false;
|
|
Undo.SetCurrentGroupName("Point Moved");
|
|
GUI.changed = true;
|
|
e.Use();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case EventType.KeyDown:
|
|
|
|
switch(e.keyCode){
|
|
|
|
case KeyCode.Delete:
|
|
case KeyCode.Backspace:
|
|
|
|
if(spectrum.selection < spectrum.points.Count){
|
|
|
|
RemovePointAt(spectrum.selection);
|
|
e.Use();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
private void RemovePointAt(int index){
|
|
|
|
spectrum.points.RemoveAt(index);
|
|
|
|
if(spectrum.selection == index)
|
|
spectrum.selection = spectrum.points.Count;
|
|
|
|
Undo.SetCurrentGroupName("Point Removed");
|
|
GUI.changed = true;
|
|
|
|
}
|
|
|
|
private float EvaluateCurve(float f){
|
|
|
|
return 2 * MapData(spectrum[MapFrequency(f, false)]) - 1;
|
|
|
|
}
|
|
|
|
private Vector2 MapPointPosition(Rect r, Point point){
|
|
|
|
return new Vector2{
|
|
|
|
x = r.x + r.width * MapFrequency(point.frequency),
|
|
y = r.y + r.height * (1 - MapData(point.data))
|
|
|
|
};
|
|
|
|
}
|
|
|
|
private Point MapMouseEvent(Rect r, Vector2 v){
|
|
|
|
return new Point{
|
|
|
|
frequency = v.x < r.xMin ? 0 : v.x > r.xMax ? cutoff : MapFrequency((v.x - r.x) / r.width, false),
|
|
data = v.y < r.yMin ? 1 : v.y > r.yMax ? 0 : MapData(1 - (v.y - r.y) / r.height, false)
|
|
|
|
};
|
|
|
|
}
|
|
|
|
private float MapData(float f, bool forward = true){
|
|
|
|
switch(scale){
|
|
|
|
case AxisScale.Log:
|
|
return forward ? f < 1e-3f ? 0 : 1 + Mathf.Log10(f) / 3 : Mathf.Pow(10, -3 * (1 - f));
|
|
|
|
case AxisScale.Sqr:
|
|
return forward ? Mathf.Sqrt(f) : f * f;
|
|
|
|
default:
|
|
case AxisScale.Lin:
|
|
return f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
public static bool MapFrequencyTick(int i, out float frequency){
|
|
|
|
int power = i / 9 + 1;
|
|
int multiplier = i % 9 + 1;
|
|
|
|
frequency = multiplier * Mathf.Pow(10, power);
|
|
|
|
return multiplier == 1;
|
|
|
|
}
|
|
|
|
public static float MapFrequency(float f, bool forward = true){
|
|
|
|
return forward ? f < 10 ? 0 : Mathf.Log(f / 10, cutoff / 10) : 10 * Mathf.Pow(cutoff / 10, f);
|
|
|
|
}
|
|
|
|
private static string FrequencyToString(float frequency){
|
|
|
|
if(frequency < 1000)
|
|
return string.Format("{0:F0} Hz", frequency);
|
|
else
|
|
return string.Format("{0:F0} kHz", frequency * .001f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
private const float rightMargin = 36;
|
|
|
|
private SpectrumDrawer absorption, scattering, transmission;
|
|
|
|
private void OnEnable(){
|
|
|
|
GetSpectra(out absorption, out scattering, out transmission);
|
|
|
|
absorption.LoadFoldoutState();
|
|
scattering.LoadFoldoutState();
|
|
transmission.LoadFoldoutState();
|
|
|
|
}
|
|
|
|
private void OnDisable(){
|
|
|
|
absorption.SaveFoldoutState();
|
|
scattering.SaveFoldoutState();
|
|
transmission.SaveFoldoutState();
|
|
|
|
}
|
|
|
|
public override void OnInspectorGUI(){
|
|
|
|
ONSPPropagationMaterial material = target as ONSPPropagationMaterial;
|
|
|
|
EditorGUI.BeginChangeCheck();
|
|
|
|
Rect r = EditorGUILayout.GetControlRect();
|
|
r.width -= rightMargin;
|
|
|
|
ONSPPropagationMaterial.Preset newPreset =
|
|
(ONSPPropagationMaterial.Preset)EditorGUI.EnumPopup(r, "Preset", material.preset);
|
|
|
|
Event e = Event.current;
|
|
EventType type = e.type;
|
|
absorption.Draw(e);
|
|
scattering.Draw(e);
|
|
transmission.Draw(e);
|
|
|
|
if(EditorGUI.EndChangeCheck()){
|
|
|
|
string groupName = Undo.GetCurrentGroupName();
|
|
|
|
Undo.RegisterCompleteObjectUndo(material, groupName);
|
|
|
|
if(groupName == "Point Added")
|
|
Undo.CollapseUndoOperations(Undo.GetCurrentGroup() - 1);
|
|
|
|
if(material.preset != newPreset)
|
|
material.preset = newPreset;
|
|
else
|
|
material.preset = ONSPPropagationMaterial.Preset.Custom;
|
|
|
|
if(Application.isPlaying)
|
|
material.UploadMaterial();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
private void GetSpectra(out SpectrumDrawer absorption,
|
|
out SpectrumDrawer scattering,
|
|
out SpectrumDrawer transmission){
|
|
|
|
ONSPPropagationMaterial material = target as ONSPPropagationMaterial;
|
|
|
|
absorption = new SpectrumDrawer("Absorption", material.absorption, AxisScale.Sqr);
|
|
scattering = new SpectrumDrawer("Scattering", material.scattering, AxisScale.Lin);
|
|
transmission = new SpectrumDrawer("Transmission", material.transmission, AxisScale.Sqr);
|
|
|
|
}
|
|
|
|
}
|