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 }