using CW.Common;
using PaintCore;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace game
{
/// This class contains common code for screen based mouse/finger hit components.
public abstract class BHitScreenBase : CwHitPointers
{
public enum RotationType
{
Normal,
World,
ThisRotation,
ThisLocalRotation,
CustomRotation,
CustomLocalRotation
}
public enum RelativeType
{
WorldUp,
CameraUp,
DrawAngle
}
public enum DirectionType
{
HitNormal,
RayDirection,
CameraDirection
}
public enum EmitType
{
PointsIn3D = 0,
PointsOnUV = 20,
TrianglesIn3D = 30
}
[System.Flags]
public enum ButtonTypes
{
LeftMouse = 1 << 0,
RightMouse = 1 << 1,
MiddleMouse = 1 << 2,
Touch = 1 << 5
}
/// Orient to a specific camera?
/// None = MainCamera.
public Camera Camera { set { _camera = value; } get { return _camera; } }
[SerializeField] private Camera _camera;
/// The layers you want the raycast to hit.
public LayerMask Layers { set { layers = value; } get { return layers; } }
[SerializeField] private LayerMask layers = Physics.DefaultRaycastLayers;
/// This allows you to control the hit data this component sends out.
/// PointsIn3D = Point drawing in 3D.
/// PointsOnUV = Point drawing on UV (requires non-convex MeshCollider).
/// TrianglesIn3D = Triangle drawing in 3D (requires non-convex MeshCollider).
public EmitType Emit { set { emit = value; } get { return emit; } }
[UnityEngine.Serialization.FormerlySerializedAs("draw")][SerializeField] private EmitType emit;
/// This allows you to control how the paint is rotated.
/// Normal = The rotation will be based on a normal direction, and rolled relative to an up axis.
/// World = The rotation will be aligned to the world, or given no rotation.
/// ThisRotation = The current Transform.rotation will be used.
/// ThisLocalRotation = The current Transform.localRotation will be used.
/// CustomRotation = The specified CustomTransform.rotation will be used.
/// CustomLocalRotation = The specified CustomTransform.localRotation will be used.
public RotationType RotateTo { set { rotateTo = value; } get { return rotateTo; } }
[SerializeField] private RotationType rotateTo;
/// Which direction should the hit point rotation be based on?
public DirectionType NormalDirection { set { normalDirection = value; } get { return normalDirection; } }
[UnityEngine.Serialization.FormerlySerializedAs("normal")][SerializeField] private DirectionType normalDirection = DirectionType.CameraDirection;
/// Based on the normal direction, what should the rotation be rolled relative to?
/// WorldUp = It will be rolled so the up vector is world up.
/// CameraUp = It will be rolled so the up vector is camera up.
/// DrawAngle = It will be rolled according to the mouse/finger movement on screen.
public RelativeType NormalRelativeTo { set { normalRelativeTo = value; } get { return normalRelativeTo; } }
[UnityEngine.Serialization.FormerlySerializedAs("orientation")][SerializeField] private RelativeType normalRelativeTo = RelativeType.CameraUp;
/// This allows you to specify the Transform when using RotateTo = CustomRotation/CustomLocalRotation.
public Transform CustomTransform { set { customTransform = value; } get { return customTransform; } }
[SerializeField] private Transform customTransform;
/// Should painting triggered from this component be eligible for being undone?
public bool StoreStates { set { storeStates = value; } get { return storeStates; } }
[SerializeField] protected bool storeStates = true;
/// This allows you to override the order this paint gets applied to the object during the current frame.
public int Priority { set { priority = value; } get { return priority; } }
[SerializeField] private int priority;
/// If you want the raycast hit point to be offset from the surface a bit, this allows you to set by how much in world space.
public float NormalOffset { set { normalOffset = value; } get { return normalOffset; } }
[SerializeField] private float normalOffset;
// No longer used
[SerializeField] private ButtonTypes requiredButtons;
// No longer used
[SerializeField] private KeyCode requiredKey;
// No longer used
[SerializeField] private float mouseOffset;
// No longer used
[SerializeField] private float touchOffset;
// No longer used
[SerializeField] private bool showPreview;
private static Transform m_TargetTransform = null;
public static void SetTargetTransform(Transform targetTransform)
{
m_TargetTransform = targetTransform;
}
public bool NeedsDrawAngle
{
get
{
return rotateTo == RotationType.Normal && normalRelativeTo == RelativeType.DrawAngle;
}
}
private bool m_IsAuthorizedDrawing = false;
public void AuthorizedDrawing()
{
m_IsAuthorizedDrawing = true;
}
public void NotAuthorizedDrawing()
{
m_IsAuthorizedDrawing = false;
}
#if UNITY_EDITOR
protected virtual void Reset()
{
if (GetComponent() == null)
{
requiredButtons &= ~ButtonTypes.LeftMouse;
requiredButtons &= ~ButtonTypes.RightMouse;
requiredButtons &= ~ButtonTypes.MiddleMouse;
gameObject.AddComponent();
}
if (GetComponent() == null)
{
requiredButtons &= ~ButtonTypes.Touch;
gameObject.AddComponent();
}
if (GetComponent() == null)
{
gameObject.AddComponent();
}
}
#endif
public bool ShouldUpgradePointers()
{
return (requiredButtons & ButtonTypes.LeftMouse) != 0
|| (requiredButtons & ButtonTypes.RightMouse) != 0
|| (requiredButtons & ButtonTypes.MiddleMouse) != 0
|| (requiredButtons & ButtonTypes.Touch) != 0;
}
public void TryUpgradePointers()
{
var lmb = (requiredButtons & ButtonTypes.LeftMouse) != 0;
var rmb = (requiredButtons & ButtonTypes.RightMouse) != 0;
var mmb = (requiredButtons & ButtonTypes.MiddleMouse) != 0;
if (lmb == true || rmb == true || mmb == true)
{
requiredButtons &= ~ButtonTypes.LeftMouse;
requiredButtons &= ~ButtonTypes.RightMouse;
requiredButtons &= ~ButtonTypes.MiddleMouse;
var pointerMouse = gameObject.AddComponent();
pointerMouse.Preview = showPreview;
if (lmb == true)
{
pointerMouse.TryAddKey(KeyCode.Mouse0);
}
if (rmb == true)
{
pointerMouse.TryAddKey(KeyCode.Mouse1);
}
if (mmb == true)
{
pointerMouse.TryAddKey(KeyCode.Mouse2);
}
}
if ((requiredButtons & ButtonTypes.Touch) != 0)
{
requiredButtons &= ~ButtonTypes.Touch;
var pointerTouch = gameObject.AddComponent();
pointerTouch.Offset = touchOffset;
}
}
protected virtual void DoQuery(Vector2 screenPosition, ref Camera camera, ref Ray ray, ref CwHit hit3D, ref RaycastHit2D hit2D)
{
var hit = default(RaycastHit);
camera = CwHelper.GetCamera(_camera);
ray = camera.ScreenPointToRay(screenPosition);
hit2D = Physics2D.GetRayIntersection(ray, float.PositiveInfinity, layers);
Physics.Raycast(ray, out hit, float.PositiveInfinity, layers);
hit3D = new CwHit(hit);
}
protected void PaintAt(CwPointConnector connector, CwHitCache hitCache, Vector2 screenPosition, Vector2 screenPositionOld, bool preview, float pressure, object owner)
{
var camera = default(Camera);
var ray = default(Ray);
var hit2D = default(RaycastHit2D);
var hit3D = default(CwHit);
var finalPosition = default(Vector3);
var finalRotation = default(Quaternion);
DoQuery(screenPosition, ref camera, ref ray, ref hit3D, ref hit2D);
var valid2D = hit2D.distance > 0.0f;
var valid3D = hit3D.Distance > 0.0f;
// Hit 3D?
if (valid3D == true && (valid2D == false || hit3D.Distance < hit2D.distance))
{
CalcHitData(hit3D.Position, hit3D.Normal, ray, camera, screenPositionOld, ref finalPosition, ref finalRotation);
if (emit == EmitType.PointsIn3D)
{
if (connector != null)
{
if (m_TargetTransform != null && hit3D.Transform != m_TargetTransform) { return; }
if (m_IsAuthorizedDrawing)
{
connector.SubmitPoint(gameObject, preview, priority, pressure, finalPosition, finalRotation, owner);
}
FishingYachtAct.Publish(new EventWashingCleanerFollowPositionData(finalPosition, hit3D.Normal));
}
else
{
hitCache.InvokePoint(gameObject, preview, priority, pressure, finalPosition, finalRotation);
}
return;
}
else if (emit == EmitType.PointsOnUV)
{
hitCache.InvokeCoord(gameObject, preview, priority, pressure, hit3D, finalRotation);
return;
}
else if (emit == EmitType.TrianglesIn3D)
{
hitCache.InvokeTriangle(gameObject, preview, priority, pressure, hit3D, finalRotation);
return;
}
}
// Hit 2D?
else if (valid2D == true)
{
CalcHitData(hit2D.point, new Vector3(0.0f, 0.0f, -1.0f), ray, camera, screenPositionOld, ref finalPosition, ref finalRotation);
if (emit == EmitType.PointsIn3D)
{
if (connector != null)
{
connector.SubmitPoint(gameObject, preview, priority, pressure, finalPosition, finalRotation, owner);
}
else
{
hitCache.InvokePoint(gameObject, preview, priority, pressure, finalPosition, finalRotation);
}
return;
}
}
if (connector != null)
{
connector.BreakHits(owner);
}
}
private void CalcHitData(Vector3 hitPoint, Vector3 hitNormal, Ray ray, Camera camera, Vector2 screenPositionOld, ref Vector3 finalPosition, ref Quaternion finalRotation)
{
finalPosition = hitPoint + hitNormal * normalOffset;
finalRotation = Quaternion.identity;
switch (rotateTo)
{
case RotationType.Normal:
{
var finalNormal = default(Vector3);
switch (normalDirection)
{
case DirectionType.HitNormal: finalNormal = hitNormal; break;
case DirectionType.RayDirection: finalNormal = -ray.direction; break;
case DirectionType.CameraDirection: finalNormal = -camera.transform.forward; break;
}
var finalUp = Vector3.up;
switch (normalRelativeTo)
{
case RelativeType.CameraUp: finalUp = camera.transform.up; break;
case RelativeType.DrawAngle:
{
var rayOld = camera.ScreenPointToRay(screenPositionOld);
if (camera.orthographic == true)
{
finalUp = Vector3.Cross(rayOld.GetPoint(1.0f) - ray.origin, ray.GetPoint(1.0f) - ray.origin);
}
else
{
finalUp = Vector3.Cross(rayOld.direction, ray.direction);
}
}
break;
}
finalRotation = Quaternion.LookRotation(-finalNormal, finalUp);
}
break;
case RotationType.World: finalRotation = Quaternion.identity; break;
case RotationType.ThisRotation: finalRotation = transform.rotation; break;
case RotationType.ThisLocalRotation: finalRotation = transform.localRotation; break;
case RotationType.CustomRotation: if (customTransform != null) finalRotation = customTransform.rotation; break;
case RotationType.CustomLocalRotation: if (customTransform != null) finalRotation = customTransform.localRotation; break;
}
}
}
}