using Pumkin.AvatarTools;
using Pumkin.DataStructures;
using Pumkin.Dependencies;
using Pumkin.HelperFunctions;
using Pumkin.PoseEditor;
using System;
using UnityEditor;
using UnityEngine;
#if VRC_SDK_VRCSDK2 || (VRC_SDK_VRCSDK3 && !UDON)
using VRC.SDKBase;
#endif
namespace Pumkin.Presets
{
[Serializable]
public class PumkinsCameraPreset : PumkinPreset
{
#if VRC_SDK_VRCSDK2 || (VRC_SDK_VRCSDK3 && !UDON)
public enum CameraOffsetMode { Viewpoint, AvatarRoot, Transform }
public CameraOffsetMode offsetMode = CameraOffsetMode.Viewpoint;
#else
public enum CameraOffsetMode { AvatarRoot = 1, Transform }
public CameraOffsetMode offsetMode = CameraOffsetMode.AvatarRoot;
#endif
public enum CameraBackgroundOverrideType { Color, Skybox, Image }
public Vector3 positionOffset = Vector3.zero;
public Vector3 rotationAnglesOffset = Vector3.zero;
public string transformPath = "";
public bool useOverlay = false;
public string overlayImagePath = "";
public Color overlayImageTint = Color.white;
public bool useBackground = false;
public CameraBackgroundOverrideType backgroundType = CameraBackgroundOverrideType.Color;
public Color backgroundColor = Color.white;
public string backgroundImagePath = "";
public Color backgroundImageTint = Color.white;
public Material backgroundMaterial = null;
private PumkinsCameraPreset() { }
///
/// Applies preset to selected camera
///
public override bool ApplyPreset(GameObject avatar)
{
Camera cam = PumkinsAvatarTools.SelectedCamera;
if(!cam || !avatar)
return false;
Undo.RegisterFullObjectHierarchyUndo(cam.gameObject, "Apply Camera Preset");
Helpers.FixCameraClippingPlanes(cam);
Transform dummy = null;
try
{
#if VRC_SDK_VRCSDK2 || (VRC_SDK_VRCSDK3 && !UDON)
if(offsetMode == CameraOffsetMode.Viewpoint)
{
dummy = new GameObject("Dummy").transform;
var desc = avatar.GetComponent();
if(desc)
{
dummy.localPosition = desc.transform.position + desc.ViewPosition;
cam.transform.localPosition = positionOffset + dummy.transform.localPosition;
cam.transform.localEulerAngles = rotationAnglesOffset + dummy.transform.localEulerAngles;
}
else
{
PumkinsAvatarTools.Log(Strings.Log.descriptorIsMissingCantGetViewpoint);
}
}
#endif
if(offsetMode > 0)
{
Transform t = avatar.transform.Find(transformPath);
dummy = new GameObject("Dummy").transform;
if(t)
{
Transform oldCamParent = cam.transform.parent;
cam.transform.parent = dummy;
cam.transform.localPosition = positionOffset;
cam.transform.localEulerAngles = rotationAnglesOffset;
dummy.SetPositionAndRotation(t.position, t.rotation);
cam.transform.parent = oldCamParent;
}
}
}
catch(Exception e)
{
Debug.LogError(e.Message);
if(dummy)
Helpers.DestroyAppropriate(dummy.gameObject);
return false;
}
finally
{
if(dummy)
Helpers.DestroyAppropriate(dummy.gameObject);
}
PumkinsAvatarTools.Instance.bThumbnails_use_camera_overlay = useOverlay;
if(useOverlay)
{
PumkinsAvatarTools.Instance.SetOverlayToImageFromPath(overlayImagePath);
}
PumkinsAvatarTools.Instance.bThumbnails_use_camera_background = useBackground;
if(useBackground)
{
PumkinsAvatarTools.Instance.cameraBackgroundType = backgroundType;
switch(backgroundType)
{
case CameraBackgroundOverrideType.Color:
PumkinsAvatarTools.Instance.SetCameraBackgroundToColor(backgroundColor);
break;
case CameraBackgroundOverrideType.Image:
PumkinsAvatarTools.Instance.cameraBackgroundImageTint = backgroundImageTint;
PumkinsAvatarTools.Instance.SetBackgroundToImageFromPath(backgroundImagePath);
break;
case CameraBackgroundOverrideType.Skybox:
PumkinsAvatarTools.Instance.SetCameraBackgroundToSkybox(backgroundMaterial);
break;
default:
break;
}
}
PumkinsAvatarTools.Instance.RefreshBackgroundOverrideType();
return true;
}
///
/// Creates new preset based on camera and reference, applies all settings from this object then saves it to assets
///
public bool SavePreset(GameObject referenceObject, Camera camera, bool overwriteExisting)
{
PumkinsCameraPreset p = ScriptableObjectUtility.CreateAndSaveAsset(name, PumkinsAvatarTools.MainFolderPath + "/Resources/Presets/Cameras/", overwriteExisting) as PumkinsCameraPreset;
if(!p)
return false;
p.name = name;
p.offsetMode = offsetMode;
if(p.offsetMode == CameraOffsetMode.AvatarRoot)
CalculateOffsets(referenceObject.transform.root, camera);
else if(p.offsetMode == CameraOffsetMode.Transform)
CalculateOffsets(referenceObject.transform, camera);
#if VRC_SDK_VRCSDK2 || (VRC_SDK_VRCSDK3 && !UDON)
else
CalculateOffsets(PumkinsAvatarTools.SelectedAvatar.GetComponent(), camera);
#endif
p.positionOffset = positionOffset;
p.rotationAnglesOffset = rotationAnglesOffset;
p.transformPath = transformPath;
p.useOverlay = PumkinsAvatarTools.Instance.bThumbnails_use_camera_overlay;
if(p.useOverlay)
{
p.overlayImagePath = PumkinsAvatarTools.Instance._overlayPath;
p.overlayImageTint = PumkinsAvatarTools.Instance.cameraOverlayImageTint;
}
p.useBackground = PumkinsAvatarTools.Instance.bThumbnails_use_camera_background;
p.backgroundType = PumkinsAvatarTools.Instance.cameraBackgroundType;
if(p.useBackground)
{
switch(p.backgroundType)
{
case CameraBackgroundOverrideType.Color:
p.backgroundColor = PumkinsAvatarTools.Instance._thumbsCamBgColor;
break;
case CameraBackgroundOverrideType.Image:
p.backgroundImagePath = PumkinsAvatarTools.Instance._backgroundPath;
p.backgroundImageTint = PumkinsAvatarTools.Instance.cameraBackgroundImageTint;
break;
case CameraBackgroundOverrideType.Skybox:
p.backgroundMaterial = RenderSettings.skybox;
break;
default:
break;
}
}
EditorUtility.SetDirty(p);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
PumkinsPresetManager.LoadPresets();
return true;
}
///
/// Returns position and rotation offsets from target transform to camera
///
public void CalculateOffsets(Transform target, Camera cam)
{
if(!target || !cam)
return;
if(target == target.root)
offsetMode = CameraOffsetMode.AvatarRoot;
else
offsetMode = CameraOffsetMode.Transform;
Transform dummy = null;
try
{
dummy = new GameObject("Dummy").transform;
dummy.position = target.position;
dummy.rotation = target.rotation;
Transform oldParent = cam.transform.parent;
cam.transform.parent = dummy;
positionOffset = cam.transform.localPosition;
rotationAnglesOffset = cam.transform.localEulerAngles;
transformPath = Helpers.GetGameObjectPath(target);
cam.transform.parent = oldParent;
}
finally
{
if(dummy)
Helpers.DestroyAppropriate(dummy.gameObject);
}
}
///
/// Gets camera offsets from transform and returns a SerialTransform
///
/// SerialTransform only holds values, it doesn't reference a real transform
public static SerialTransform GetOffsetsFromTransform(Transform transform, Camera cam)
{
if(!cam || !transform)
return null;
Transform oldCamParent = cam.transform.parent;
cam.transform.parent = transform;
SerialTransform offsets = new SerialTransform()
{
localPosition = cam.transform.localPosition,
localRotation = cam.transform.localRotation,
localEulerAngles = cam.transform.localEulerAngles,
};
cam.transform.parent = oldCamParent;
return offsets;
}
///
/// Sets camera position and rotation focusing focusTransform with position and rotation offsets
///
/// Transform to focus
/// Camera to move
/// Position offset
/// Rotation offset
/// Not working yet
public static void ApplyPositionAndRotationWithTransformFocus(Transform focusTransform, Camera cam, Vector3 pos, Vector3 rotationAngles, bool moveSceneCameraAsWell)
{
if(!cam || !focusTransform)
return;
Transform dummy = new GameObject("dummy").transform;
try
{
dummy.SetPositionAndRotation(focusTransform.position, focusTransform.rotation);
cam.transform.parent = dummy;
cam.transform.localPosition = pos;
cam.transform.localEulerAngles = rotationAngles;
cam.transform.parent = null;
if(moveSceneCameraAsWell)
{
Transform t = SceneView.lastActiveSceneView.camera.transform;
t.SetPositionAndRotation(cam.transform.position, cam.transform.rotation);
}
}
catch(Exception e)
{
Debug.LogError(e.Message);
}
finally
{
if(dummy)
Helpers.DestroyAppropriate(dummy.gameObject);
}
}
///
/// Returns the name of the preset
///
public override string ToString()
{
return name;
}
#if VRC_SDK_VRCSDK2 || (VRC_SDK_VRCSDK3 && !UDON)
///
/// Returns position and rotation offsets from viewpoint to camera
///
public void CalculateOffsets(VRC_AvatarDescriptor desc, Camera cam)
{
if(!desc || !cam)
return;
SerialTransform offsets = GetOffsetsFromViewpoint(desc, cam);
if(offsets)
{
offsetMode = CameraOffsetMode.Viewpoint;
positionOffset = offsets.localPosition;
rotationAnglesOffset = offsets.localEulerAngles;
}
}
//Static Functions
///
/// Sets camera position and rotation focusing viewpoint with position and rotation offsets
///
/// Not working yet
public static void ApplyPositionAndRotationWithViewpointFocus(GameObject avatar, Camera cam, Vector3 position, Vector3 rotationAngles, bool moveSceneCameraAsWell)
{
if(!cam || !avatar)
return;
Transform dummy = null;
try
{
dummy = new GameObject("Dummy").transform;
var desc = avatar.GetComponent();
dummy.localPosition = desc.ViewPosition + desc.gameObject.transform.position;
cam.transform.localPosition = position + dummy.transform.position;
cam.transform.localEulerAngles = rotationAngles + dummy.transform.eulerAngles;
if(moveSceneCameraAsWell)
SceneView.lastActiveSceneView.camera.transform.SetPositionAndRotation(cam.transform.position, cam.transform.rotation);
}
catch(Exception e)
{
Debug.LogError(e.Message);
}
finally
{
if(dummy)
Helpers.DestroyAppropriate(dummy.gameObject);
}
}
///
/// Gets camera offsets from viewpoint and returns a SerialTransform
///
/// SerialTransform only holds values, it doesn't reference a real transform
public static SerialTransform GetOffsetsFromViewpoint(VRC_AvatarDescriptor desc, Camera cam)
{
SerialTransform offsets = new SerialTransform();
Transform dummy = null;
try
{
dummy = new GameObject("Dummy").transform;
dummy.localPosition = desc.ViewPosition + desc.gameObject.transform.position;
offsets.localPosition = cam.transform.localPosition - dummy.localPosition;
offsets.localEulerAngles = cam.transform.localEulerAngles - dummy.localEulerAngles;
}
catch(Exception e)
{
Debug.LogError(e.Message);
}
finally
{
if(dummy)
Helpers.DestroyAppropriate(dummy.gameObject);
}
return offsets;
}
///
/// Gets camera offset from viewpoint and returns a SerialTransform
///
/// SerialTransform only holds values, it doesn't reference a real transform
public static SerialTransform GetCameraOffsetFromViewpoint(GameObject avatar, Camera cam)
{
VRC_AvatarDescriptor desc = avatar.GetComponent();
SerialTransform offsets = null;
if(desc)
offsets = GetOffsetsFromViewpoint(desc, cam);
return offsets;
}
///
/// Sets camera position and rotation based on position and rotation offsets from transform
///
public static void ApplyTransformWithViewpointFocus(GameObject avatar, Camera cam, SerialTransform trans)
{
ApplyPositionAndRotationWithViewpointFocus(avatar, cam, trans.position, trans.localEulerAngles, true);
}
#endif
}
}