//----------------------------------------------------------------------- //----------------------------------------------------------------------- // file="Camera.cs" // Project: StgSharp // AuthorGroup: Nitload Space // Copyright (c) Nitload Space. All rights reserved. // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation // files (the “Software”), to deal in the Software without restriction, // including without limitation the rights to use, copy, modify, merge, // publish, distribute, sublicense, and/or sell copies of the Software, // and to permit persons to whom the Software is furnished to do so, // subject to the following conditions: // // The above copyright notice and // this permission notice shall be included in all copies // or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED “AS IS”, // WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, // ARISING FROM, OUT OF OR IN CONNECTION WITH // THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // //----------------------------------------------------------------------- //----------------------------------------------------------------------- using StgSharp.Graphics; using StgSharp.Graphics.ShaderEdit; using StgSharp.Math; using System; using System.Collections.Generic; using System.Numerics; using System.Runtime.InteropServices; using System.Text; namespace StgSharp.Graphic { public sealed class Camera : IglConvertable { Uniform[] convertedUniform ; glHandleSet uniformHandle; internal bool _isLookAtAvailable; internal Matrix44 cameraAtt; internal vec3d cameraCoord; internal Matrix44 _lookAt; internal Matrix44 _projection; public Camera() { cameraAtt = Matrix44.Unit; cameraCoord = Vec3d.Unit; _isLookAtAvailable = false; _lookAt = Matrix44.Unit; convertedUniform = new Uniform[2]; } public Camera(vec3d position, vec3d target, vec3d up) : this() { SetLookAt(position, target, up); } public Matrix44 LookAt { get { if (_isLookAtAvailable) { return _lookAt; } Matrix44 att = cameraAtt; att.Colum1 = Linear.Normalize(att.Colum1); Matrix44 coord = Matrix44.Unit; coord.Colum3.vec -= cameraCoord.vec; _lookAt = att.Transpose * coord; _isLookAtAvailable = true; return _lookAt; } } public Matrix44 Projection => _projection; public void MoveNear(float distance) { cameraCoord.Z -= distance; } public void MoveRight(float distance) { cameraCoord.X -= distance; } public void MoveUp(float distance) { cameraCoord.Y -= distance; } public void Perspective(Radius fovy, Vec2d size, float zNear, float zFar) { if (fovy == Radius.Zero) { fovy = new Radius(0.000001f); } if (zFar == zNear) { return; } float rad = fovy._radius; float aspect = size.X / size.Y; float tanHalfFovy = Scaler.Tan(rad / 2.0f); tanHalfFovy = tanHalfFovy==float.PositiveInfinity? float.MaxValue : tanHalfFovy; tanHalfFovy = tanHalfFovy == float.NegativeInfinity ? float.MinValue : tanHalfFovy; _projection.Colum0.X = 1.0f / (aspect * tanHalfFovy); _projection.Colum1.Y = 1.0f / tanHalfFovy; _projection.Colum2.Z = (-(zFar + zNear)) / (zFar - zNear); _projection.Colum3.W = -1.0f; _projection.Colum2.Y = (-(2.0f * zFar * zNear)) / (zFar - zNear); } public void Pitch(Radius r) { Matrix32 partialCoord = new Matrix32( cameraAtt.Colum1.vec, cameraAtt.Colum2.vec ); Matrix22 rotation = new Matrix22( GeometryScaler.Cos(r), -GeometryScaler.Sin(r), GeometryScaler.Sin(r), -GeometryScaler.Cos(r) ); partialCoord *= rotation; cameraAtt.Colum1.vec = partialCoord.colum0.vec; cameraAtt.Colum2.vec = partialCoord.colum1.vec; } public void SetLookAt(vec3d position, vec3d target, vec3d up) { vec3d direction = target - position; Linear.Normalize(ref direction, ref up); vec3d right = Linear.Cross(up, direction); cameraAtt.Colum0.vec = direction.vec; cameraAtt.Colum1.vec = up.vec; cameraAtt.Colum2.vec = right.vec; } public void DisplayGLtypeDefinition() { Console.WriteLine( $"struct camera\n" + "\t{{\n" + "\tmatrix4x4 Perspective;\n" + "\tmatrix4x4 View;\n" + "\t}}\n" ); } /// /// Get all uniform related to this . /// /// Shader program requires this camera. /// /// Name of all related uniforms. /// If you fallow form from /// /// public unsafe void GainAllUniforms(ShaderProgram source, params string[] uniformName) { GLcontext* gl = GL.api; uniformHandle = new glHandleSet(2); byte[] name1; byte[] name2; Console.WriteLine(uniformName.Length); switch (uniformName.Length) { case 2: name1 = Encoding.UTF8.GetBytes(uniformName[0]); name2 = Encoding.UTF8.GetBytes(uniformName[1]); fixed (byte* namePtr = name1) { uniformHandle[(uint)0].Value = gl->glGetUniformLocation( source.handle.Value, namePtr); } fixed (byte* namePtr = name2) { uniformHandle[(uint)1].Value = gl->glGetUniformLocation( source.handle.Value, namePtr); } convertedUniform[0] = Uniform.FromHandle(uniformHandle[(uint)0]); convertedUniform[1] = Uniform.FromHandle(uniformHandle[(uint)1]); break; case 1: name1 = Encoding.UTF8.GetBytes($"{uniformName[0]}.Perspective"); name2 = Encoding.UTF8.GetBytes($"{uniformName[0]}.View"); fixed (byte* namePtr = name1) { uniformHandle[(uint)0].Value = gl->glGetUniformLocation( source.handle.Value, namePtr); } fixed (byte* namePtr = name2) { uniformHandle[(uint)1].Value = gl->glGetUniformLocation( source.handle.Value, namePtr); } convertedUniform[0] = Uniform.FromHandle(uniformHandle[(uint)0]); convertedUniform[1] = Uniform.FromHandle(uniformHandle[(uint)1]); break; default: throw new ArgumentException(); } } ShaderStruct IglConvertable.GetConvertedGLtype() { throw new NotImplementedException(); } public unsafe void SetAllUniforms() { GL.SetValue(convertedUniform[0], _projection); GL.SetValue(convertedUniform[1], LookAt); } ~Camera() { if (uniformHandle != null) { uniformHandle.Release(); } } } }