1 module prova.entities.camera; 2 3 import prova.entities; 4 import prova.math; 5 6 /// 7 enum SortingMethod { Z, DISTANCE } 8 /// 9 enum Projection { PERSPECTIVE, ORTHOGRAPHIC } 10 11 /// 12 class Camera : Entity 13 { 14 /// 15 Projection projection = Projection.PERSPECTIVE; 16 /// 17 SortingMethod sortingMethod = SortingMethod.DISTANCE; 18 /// 19 bool useDepthBuffer = true; 20 /// Width and height will be set to the screen resolution when true 21 bool resolutionDependent = false; 22 /// 23 float zNear = float.min_normal; 24 /// 25 float zFar = 1000; 26 /// For orthographic projection and UI 27 float width = 1; 28 /// For orthographic projection and UI 29 float height = 1; 30 /// For perspective projection 31 float FOV = 90; 32 33 /// 34 @property float zRange() 35 { 36 return zFar - zNear; 37 } 38 39 /// 40 Matrix getViewMatrix() 41 { 42 Vector3 worldPosition = getWorldPosition(); 43 Quaternion worldRotation = getWorldRotation(); 44 45 Matrix transform = Matrix.identity; 46 transform = transform.translate(-worldPosition); 47 transform = transform.rotate(worldRotation.getConjugate()); 48 transform = transform.scale(scale); 49 50 return transform; 51 } 52 53 /// 54 Matrix getProjectionMatrix() 55 { 56 if(projection == Projection.ORTHOGRAPHIC) 57 return Matrix.ortho(-width/2, width/2, height/2, -height/2, zNear, zFar); 58 return Matrix.perspective(width, height, zNear, zFar, FOV); 59 } 60 61 /** 62 * Converts world position to screen position 63 * - This is equal to getProjectionMatrix() * getViewMatrix() 64 */ 65 Matrix getScreenMatrix() 66 { 67 return getProjectionMatrix() * getViewMatrix(); 68 } 69 70 /// 71 Vector2 getScreenPosition(Vector3 worldPosition) 72 { 73 Vector4 worldPositionVec4 = worldPosition; 74 worldPositionVec4.w = 1; 75 76 Vector4 clipSpacePosition = getScreenMatrix() * worldPositionVec4; 77 78 return clipSpacePosition.xy / clipSpacePosition.w; 79 } 80 81 /// 82 Matrix getUIMatrix() 83 { 84 const float left = 0; 85 const float right = width / scale.x; 86 const float top = height / scale.y; 87 const float bottom = 0; 88 89 return Matrix.ortho(left, right, top, bottom, -1, 1); 90 } 91 92 /// 93 bool delegate(Entity, Entity) getSortDelegate() 94 { 95 final switch(sortingMethod) 96 { 97 case SortingMethod.DISTANCE: 98 return (a, b) => distanceSort(a, b); 99 case SortingMethod.Z: 100 return (a, b) => zSort(a, b); 101 } 102 } 103 104 private bool distanceSort(Entity entityA, Entity entityB) 105 { 106 float distanceA = position.distanceTo(entityA.position); 107 float distanceB = position.distanceTo(entityB.position); 108 109 return distanceA < distanceB; 110 } 111 112 private bool zSort(Entity entityA, Entity entityB) 113 { 114 return entityA.position.z < entityB.position.z; 115 } 116 }