1 /+ 2 The MIT License (MIT) 3 4 Copyright (c) <2013> <Oleg Butko (deviator), Anton Akzhigitov (Akzwar)> 5 6 Permission is hereby granted, free of charge, to any person obtaining a copy 7 of this software and associated documentation files (the "Software"), to deal 8 in the Software without restriction, including without limitation the rights 9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 copies of the Software, and to permit persons to whom the Software is 11 furnished to do so, subject to the following conditions: 12 13 The above copyright notice and this permission notice shall be included in 14 all copies or substantial portions of the Software. 15 16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 THE SOFTWARE. 23 +/ 24 25 module des.math.linear.view.camera; 26 27 public import des.math.linear.view.node; 28 public import des.math.linear.view.resolver; 29 30 import std.math; 31 32 class Camera: Node 33 { 34 protected: 35 Node _parent; 36 37 public: 38 39 Resolver resolver; 40 Transform projection, transform; 41 42 this( Node par=null ) 43 { 44 _parent = par; 45 resolver = new Resolver; 46 } 47 48 const 49 { 50 mat4 resolve( const(Node) obj ) { return resolver(obj, this); } 51 52 mat4 opCall( const(Node) obj ) 53 { return getMatrix( projection ) * resolve(obj); } 54 55 @property 56 { 57 mat4 matrix() { return getMatrix( transform ); } 58 const(Node) parent() { return _parent; } 59 } 60 } 61 } 62 63 class LookAtTransform : Transform 64 { 65 vec3 pos=vec3(0), target=vec3(0), up=vec3(0,0,1); 66 @property mat4 matrix() const 67 { return calcLookAt( pos, target, up ); } 68 } 69 70 class ResolveTransform : Transform 71 { 72 protected: 73 Resolver resolver; 74 public: 75 void setResolver( Resolver rsl ) { resolver = rsl; } 76 abstract @property mat4 matrix() const; 77 } 78 79 class LookAtNodeTransform : ResolveTransform 80 { 81 Node center, target, up; 82 83 override @property mat4 matrix() const 84 in 85 { 86 assert( center !is null ); 87 assert( target !is null ); 88 assert( up !is null ); 89 assert( resolver !is null ); 90 } 91 body 92 { 93 return calcLookAt( center.offset, 94 resolveOffset(target), 95 resolveOffset(up) ); 96 } 97 98 protected: 99 100 vec3 resolveOffset( const(Node) node ) const 101 { return vec3( resolver(node,center).col(3)[0..3] ); } 102 } 103 104 class PerspectiveTransform : Transform 105 { 106 float fov = 70; 107 float ratio = 4.0f / 3.0f; 108 float near = 1e-1; 109 float far = 1e5; 110 111 @property mat4 matrix() const 112 in 113 { 114 assert( fov > 0 ); 115 assert( ratio > 0 ); 116 assert( near > 0 ); 117 assert( far > 0 ); 118 } 119 body { return calcPerspective( fov, ratio, near, far ); } 120 } 121 122 /+ simple lookAt perspective camera +/ 123 class SimpleCamera : Camera 124 { 125 protected: 126 LookAtTransform look_tr; 127 PerspectiveTransform perspective; 128 129 public: 130 131 this( Node p=null ) 132 { 133 super(p); 134 look_tr = new LookAtTransform; 135 look_tr.up = vec3(0,0,1); 136 transform = look_tr; 137 perspective = new PerspectiveTransform; 138 projection = perspective; 139 } 140 141 @property 142 { 143 void fov( float val ) { perspective.fov = val; } 144 float fov() const { return perspective.fov; } 145 146 void ratio( float val ) { perspective.ratio = val; } 147 float ratio() const { return perspective.ratio; } 148 149 void near( float val ) { perspective.near = val; } 150 float near() const { return perspective.near; } 151 152 void far( float val ) { perspective.far = val; } 153 float far() const { return perspective.far; } 154 155 void pos( in vec3 val ) { look_tr.pos = val; } 156 vec3 pos() const { return look_tr.pos; } 157 158 void up( in vec3 val ) { look_tr.up = val; } 159 vec3 up() const { return look_tr.up; } 160 161 void target( in vec3 val ) { look_tr.target = val; } 162 vec3 target() const { return look_tr.target; } 163 } 164 } 165 166 private: 167 168 mat4 calcLookAt( in vec3 pos, in vec3 trg, in vec3 up ) 169 { 170 auto z = (pos-trg).e; 171 auto x = cross(up,z).e; 172 vec3 y; 173 if( x ) y = cross(z,x).e; 174 else 175 { 176 y = cross(z,vec3(1,0,0)).e; 177 x = cross(y,z).e; 178 } 179 return mat4( x.x, y.x, z.x, pos.x, 180 x.y, y.y, z.y, pos.y, 181 x.z, y.z, z.z, pos.z, 182 0, 0, 0, 1 ); 183 } 184 185 mat4 calcPerspective( float fov_degree, float ratio, float znear, float zfar ) 186 { 187 /+ fov conv to radians and div 2 +/ 188 float h = 1.0 / tan( fov_degree * PI / 360.0 ); 189 float w = h / ratio; 190 191 float depth = znear - zfar; 192 float q = ( znear + zfar ) / depth; 193 float n = ( 2.0f * znear * zfar ) / depth; 194 195 return mat4( w, 0, 0, 0, 196 0, h, 0, 0, 197 0, 0, q, n, 198 0, 0, -1, 0 ); 199 } 200 201 mat4 calcOrtho( float w, float h, float znear, float zfar ) 202 { 203 float x = znear - zfar; 204 return mat4( 2/w, 0, 0, 0, 205 0, 2/h, 0, 0, 206 0, 0, -1/x, 0, 207 0, 0, znear/x, 1 ); 208 }