Skip to content

Instantly share code, notes, and snippets.

@DuncanF
Last active August 24, 2020 07:57
Show Gist options
  • Save DuncanF/81510835a44d767df79551ad9b1907c9 to your computer and use it in GitHub Desktop.
Save DuncanF/81510835a44d767df79551ad9b1907c9 to your computer and use it in GitHub Desktop.
Unity preset handling for use with editor MIDI control
Presets and some editor functionality (screencap that works when not in play mode) in PresetHandling.cs file.
MidiControl script utilises Keijiro's MidiJack: https://github.com/keijiro/MidiJack
Midi controller (Korg NanoKontrol2) transport buttons mapped to creating new presets, cycling through existing presets and editor play mode handling by the below:
void HandleMidi(MidiChannel channel, int knobOrNoteNum, float value)
{
foreach (MidiMapping mapping in mappings)
{
MidiLearn(mapping, channel, knobOrNoteNum);
if ((mapping.channel != channel && mapping.channel != MidiChannel.All)
|| mapping.ccNum != knobOrNoteNum)
{
continue;
}
float mappedValue = Mathf.Lerp(mapping.min, mapping.max, value);
if (mapping.field.FieldType == typeof(float))
{
mapping.field.SetValue(target, mappedValue);
}
else if (mapping.field.FieldType == typeof(int))
{
mapping.field.SetValue(target, (int)mappedValue);
}
else if (mapping.field.FieldType == typeof(bool))
{
// Toggle bool value on button down
if (mappedValue > 0.5)
{
bool currentVal = (bool)mapping.field.GetValue(target);
mapping.field.SetValue(target, !currentVal);
}
}
else
{
DebugLog($"Unhandled field type [{mapping.field.FieldType}]");
}
}
}
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
using UnityEditor.Presets;
using UnityEditor.SceneManagement;
public static class PresetHandling
{
const string presetExtension = ".preset";
public static int CreatePresetInDatabase(UnityEngine.Object source)
{
Preset preset = new Preset(source);
string presetPath = FindNextPresetPath(source, out int num);
AssetDatabase.CreateAsset(preset, presetPath);
SaveScreenshotToPictures(Path.GetFileName(presetPath), true);
return num;
}
public static void SaveScreenshot(string filePath)
{
// NB, below doesn't work when not in play mode, and we want to ensure we use screen res as set in display 1
//ScreenCapture.CaptureScreenshot(filename + ".png");
var cam = Camera.main;
var renderTexture = new RenderTexture(cam.pixelWidth, cam.pixelHeight, 24);
cam.targetTexture = renderTexture;
cam.Render();
cam.targetTexture = null;
RenderTexture.active = renderTexture;
Texture2D screenshot = new Texture2D(cam.pixelWidth, cam.pixelHeight, TextureFormat.RGB24, false);
screenshot.ReadPixels(new Rect(0, 0, cam.pixelWidth, cam.pixelHeight), 0, 0);
screenshot.Apply();
RenderTexture.active = null;
//Encode screenshot to PNG
byte[] bytes = screenshot.EncodeToPNG();
UnityEngine.Object.DestroyImmediate(screenshot);
string folder = Path.GetDirectoryName(filePath);
if (!Directory.Exists(folder))
{
Directory.CreateDirectory(folder);
}
File.WriteAllBytes(filePath, bytes);
}
public static void SaveScreenshotToPictures(string filenameNoExtension, bool overwrite = false)
{
string targetFolder = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.MyPictures),
PlayerSettings.productName);
string targetFileName = Path.Combine(targetFolder, filenameNoExtension + ".png");
if (!overwrite)
{
int screenCapNum = 0;
do
{
targetFileName = Path.Combine(targetFolder,
filenameNoExtension + $"{screenCapNum:000}" + ".png");
++screenCapNum;
}
while (File.Exists(targetFileName) && screenCapNum < 1000);
Debug.Assert(screenCapNum != 1000);
}
PresetHandling.SaveScreenshot(targetFileName);
}
[MenuItem("Screencap/TakeScreencap")]
static void TakeScreencap()
{
string capName = $"Screencap_{EditorSceneManager.GetActiveScene().name}_{DateTime.Now.ToLongTimeString().Replace(':', '_')}";
Debug.Log($"Saving {capName}");
SaveScreenshotToPictures(capName);
}
private static string FindNextPresetPath(UnityEngine.Object source, out int num)
{
string currentScenePath = UnityEditor.SceneManagement.EditorSceneManager.GetActiveScene().path;
string folder = Path.GetDirectoryName(currentScenePath);
num = 0;
string newPath = PresetPath(source, folder, num);
while (File.Exists(newPath))
{
++num;
newPath = PresetPath(source, folder, num);
}
return newPath;
}
private static string PresetPath(UnityEngine.Object source, string folder, int num)
{
string presetsFolder = Path.Combine(folder, "Presets");
if (!Directory.Exists(presetsFolder))
{
Directory.CreateDirectory(presetsFolder);
}
return Path.Combine(presetsFolder, source.name + $"{num:000}" + presetExtension);
}
public static bool LoadPreset(UnityEngine.Object target, int presetNumber)
{
string currentScenePath = UnityEditor.SceneManagement.EditorSceneManager.GetActiveScene().path;
string folder = Path.GetDirectoryName(currentScenePath);
string nextPresetPath = PresetPath(target, folder, presetNumber);
if (File.Exists(nextPresetPath))
{
Preset preset = AssetDatabase.LoadAssetAtPath<Preset>(nextPresetPath);
if (preset != null && preset.CanBeAppliedTo(target))
{
Debug.Log("Loaded preset " + Path.GetFileName(nextPresetPath));
preset.ApplyTo(target);
return true;
}
else
{
Debug.Log("Could not load or apply preset " + nextPresetPath);
}
}
else
{
Debug.Log("Could not find " + nextPresetPath);
}
return false;
}
public static bool LoadLastPreset(UnityEngine.Object target, out int foundPresetID)
{
string nextPath = FindNextPresetPath(target, out int num);
foundPresetID = num-1;
return LoadPreset(target, foundPresetID);
}
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment