mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/PCK-Studio.git
synced 2026-05-23 01:35:11 +00:00
209 lines
6.0 KiB
C#
209 lines
6.0 KiB
C#
/* Copyright (c) 2024-present miku-666
|
|
* This software is provided 'as-is', without any express or implied
|
|
* warranty. In no event will the authors be held liable for any damages
|
|
* arising from the use of this software.
|
|
*
|
|
* Permission is granted to anyone to use this software for any purpose,
|
|
* including commercial applications, and to alter it and redistribute it
|
|
* freely, subject to the following restrictions:
|
|
*
|
|
* 1.The origin of this software must not be misrepresented; you must not
|
|
* claim that you wrote the original software. If you use this software
|
|
* in a product, an acknowledgment in the product documentation would be
|
|
* appreciated but is not required.
|
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
|
* misrepresented as being the original software.
|
|
* 3. This notice may not be removed or altered from any source distribution.
|
|
**/
|
|
// movement code taken from:
|
|
// https://github.com/TheCherno/Hazel/blob/master/Hazel/src/Hazel/Renderer/EditorCamera.cpp
|
|
using System;
|
|
using System.Drawing;
|
|
using OpenTK;
|
|
|
|
namespace PckStudio.Rendering.Camera
|
|
{
|
|
public class PerspectiveCamera : Camera
|
|
{
|
|
public float NearClip
|
|
{
|
|
get => _nearClip;
|
|
set
|
|
{
|
|
_nearClip = value;
|
|
UpdateProjection();
|
|
}
|
|
}
|
|
|
|
public float FarClip
|
|
{
|
|
get => _farClip;
|
|
set
|
|
{
|
|
_farClip = value;
|
|
UpdateProjection();
|
|
}
|
|
}
|
|
|
|
public float Distance
|
|
{
|
|
get => _spherical.Radius;
|
|
set
|
|
{
|
|
_spherical.Radius = Math.Max(value, 2f);
|
|
UpdateViewMatrix();
|
|
}
|
|
}
|
|
|
|
public float RotationSpeed { get; set; } = 5f;
|
|
|
|
public Size ViewportSize
|
|
{
|
|
get => _viewportSize;
|
|
set
|
|
{
|
|
_viewportSize = value;
|
|
UpdateProjection();
|
|
}
|
|
}
|
|
|
|
public Vector3 WorldPosition => _position;
|
|
|
|
public Vector3 FocalPoint
|
|
{
|
|
get => _focalPoint;
|
|
set
|
|
{
|
|
_focalPoint = value;
|
|
UpdateViewMatrix();
|
|
}
|
|
}
|
|
|
|
public float Pitch
|
|
{
|
|
get => _spherical.Theta;
|
|
set
|
|
{
|
|
_spherical.Theta = MathHelper.Clamp(value, -90f, 90f);
|
|
UpdateViewMatrix();
|
|
}
|
|
}
|
|
|
|
public float Yaw
|
|
{
|
|
get => _spherical.Phi;
|
|
set
|
|
{
|
|
_spherical.Phi = value % 360f;
|
|
UpdateViewMatrix();
|
|
}
|
|
}
|
|
|
|
public Vector3 Orientation => -Vector3.UnitZ;
|
|
|
|
public Vector3 Up => Vector3.UnitY;
|
|
|
|
public float MinimumFov { get; } = 30f;
|
|
public float MaximumFov { get; } = 180f;
|
|
|
|
public float Fov
|
|
{
|
|
get => _fov;
|
|
set
|
|
{
|
|
_fov = MathHelper.Clamp(value, MinimumFov, MaximumFov);
|
|
UpdateProjection();
|
|
}
|
|
}
|
|
|
|
public PerspectiveCamera(float fov, Vector3 target)
|
|
{
|
|
_fov = fov;
|
|
_focalPoint = target;
|
|
_nearClip = 1f;
|
|
_farClip = 1000f;
|
|
UpdateProjection();
|
|
}
|
|
|
|
private Matrix4 viewMatrix;
|
|
private float _fov;
|
|
|
|
private float _nearClip;
|
|
private float _farClip;
|
|
private Spherical _spherical;
|
|
private Size _viewportSize;
|
|
private Vector3 _position;
|
|
private Vector3 _focalPoint;
|
|
|
|
public override Matrix4 GetViewProjection()
|
|
{
|
|
return viewMatrix * projectionMatrix;
|
|
}
|
|
|
|
public Matrix4 GetProjection()
|
|
{
|
|
return projectionMatrix;
|
|
}
|
|
|
|
private void UpdateViewMatrix()
|
|
{
|
|
Matrix4 rotation = Matrix4.CreateRotationY(MathHelper.DegreesToRadians(Yaw)) * Matrix4.CreateRotationX(MathHelper.DegreesToRadians(Pitch));
|
|
|
|
viewMatrix = Matrix4.CreateTranslation(FocalPoint) * rotation * Matrix4.CreateTranslation(0, 0, -Distance);
|
|
// Position in Right-handed coordinates
|
|
_position = viewMatrix.Inverted().ExtractTranslation();
|
|
}
|
|
|
|
private void UpdateProjection()
|
|
{
|
|
float aspect = (float)ViewportSize.Width / (float)ViewportSize.Height;
|
|
projectionMatrix = Matrix4.CreatePerspectiveFieldOfView((float)MathHelper.DegreesToRadians(Fov), aspect, NearClip, FarClip);
|
|
}
|
|
|
|
private Vector2 GetPanSpeed()
|
|
{
|
|
float x = Math.Min(ViewportSize.Width / 100.0f, 1.4f); // max = 2.4f
|
|
float xFactor = 0.0366f * (x * x) - 0.1778f * x + 0.3021f;
|
|
|
|
float y = Math.Min(ViewportSize.Height / 100.0f, 1.4f); // max = 2.4f
|
|
float yFactor = 0.0366f * (y * y) - 0.1778f * y + 0.3021f;
|
|
|
|
return new Vector2(xFactor, yFactor);
|
|
}
|
|
|
|
public void Pan(Vector2 delta)
|
|
{
|
|
Pan(delta.X, delta.Y);
|
|
}
|
|
|
|
public void Pan(float deltaX, float deltaY)
|
|
{
|
|
Vector2 panSpeed = GetPanSpeed();
|
|
|
|
// Taken from: blockbench
|
|
// https://github.com/JannisX11/blockbench/blob/a56fe01a517ace8d013f67bbd3d02442c44d3141/js/preview/OrbitControls.js#L271-L322
|
|
Vector3 left = viewMatrix.Column0.Xyz * -Distance;
|
|
Vector3 up = viewMatrix.Column1.Xyz * Distance;
|
|
_focalPoint -= left * deltaX * panSpeed.X;
|
|
_focalPoint -= up * deltaY * panSpeed.Y;
|
|
UpdateViewMatrix();
|
|
}
|
|
|
|
public void Rotate(Vector2 delta)
|
|
{
|
|
Rotate(delta.X, delta.Y);
|
|
}
|
|
|
|
public void Rotate(float deltaX,float deltaY)
|
|
{
|
|
Yaw += deltaX * RotationSpeed;
|
|
Pitch += deltaY * RotationSpeed;
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
return $"FOV: {Fov}\nPosition: {WorldPosition}\nRotation: {_spherical}";
|
|
}
|
|
}
|
|
}
|