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.space.camera;
26 
27 public import des.space.node;
28 public import des.space.resolver;
29 
30 import std.math;
31 
32 ///
33 class Camera: SpaceNode
34 {
35     mixin SpaceNodeHelper!false;
36 
37     ///
38     Resolver resolver;
39 
40     ///
41     Transform projection, transform;
42 
43     ///
44     this( SpaceNode par=null )
45     {
46         spaceParent = par;
47         resolver = new Resolver;
48     }
49 
50     const
51     {
52         ///
53         mat4 resolve( const(SpaceNode) obj ) { return resolver(obj, this); }
54         ///
55         mat4 matrix() @property { return getMatrix( transform ); }
56     }
57 }
58 
59 ///
60 class LookAtTransform : Transform
61 {
62     ///
63     vec3 pos=vec3(0), target=vec3(0), up=vec3(0,0,1);
64 
65     ///
66     @property mat4 matrix() const
67     { return calcLookAt( pos, target, up ); }
68 }
69 
70 ///
71 class PerspectiveTransform : Transform
72 {
73 protected:
74     float _fov = 70;
75     float _ratio = 4.0f / 3.0f;
76     float _near = 1e-1;
77     float _far = 1e5;
78 
79     mat4 self_mtr;
80 
81     void recalc() { self_mtr = calcPerspective( _fov, _ratio, _near, _far ); }
82 
83 public:
84 
85     @property
86     {
87         ///
88         float fov() const { return _fov; }
89         ///
90         float fov( float v ) in { assert(v>0); }
91         body { _fov = v; recalc(); return _fov; }
92 
93         ///
94         float ratio() const { return _ratio; }
95         ///
96         float ratio( float v ) in { assert(v>0); }
97         body { _ratio = v; recalc(); return _ratio; }
98 
99         ///
100         float near() const { return _near; }
101         ///
102         float near( float v ) in { assert(v>0); }
103         body { _near = v; recalc(); return _near; }
104 
105         ///
106         float far() const { return _far; }
107         ///
108         float far( float v ) in { assert(v>0); }
109         body { _far = v; recalc(); return _far; }
110 
111         ///
112         mat4 matrix() const { return self_mtr; }
113     }
114 }
115 
116 /++ simple lookAt perspective camera +/
117 class SimpleCamera : Camera
118 {
119 protected:
120     LookAtTransform look_tr;
121     PerspectiveTransform perspective;
122 
123 public:
124 
125     ///
126     this( SpaceNode p=null )
127     {
128         super(p);
129         look_tr = new LookAtTransform;
130         look_tr.up = vec3(0,0,1);
131         transform = look_tr;
132         perspective = new PerspectiveTransform;
133         projection = perspective;
134     }
135 
136     @property
137     {
138         ///
139         void fov( float val ) { perspective.fov = val; }
140         ///
141         float fov() const { return perspective.fov; }
142 
143         ///
144         void ratio( float val ) { perspective.ratio = val; }
145         ///
146         float ratio() const { return perspective.ratio; }
147 
148         ///
149         void near( float val ) { perspective.near = val; }
150         ///
151         float near() const { return perspective.near; }
152 
153         ///
154         void far( float val ) { perspective.far = val; }
155         ///
156         float far() const { return perspective.far; }
157 
158         ///
159         void pos( in vec3 val ) { look_tr.pos = val; }
160         ///
161         vec3 pos() const { return look_tr.pos; }
162 
163         ///
164         void up( in vec3 val ) { look_tr.up = val; }
165         ///
166         vec3 up() const { return look_tr.up; }
167 
168         ///
169         void target( in vec3 val ) { look_tr.target = val; }
170         ///
171         vec3 target() const { return look_tr.target; }
172     }
173 }
174 
175 private:
176 
177 mat4 calcLookAt( in vec3 pos, in vec3 trg, in vec3 up )
178 {
179     auto z = (pos-trg).e;
180     auto x = cross(up,z).e;
181     vec3 y;
182     if( x ) y = cross(z,x).e;
183     else
184     {
185         y = cross(z,vec3(1,0,0)).e;
186         x = cross(y,z).e;
187     }
188     return mat4( x.x, y.x, z.x, pos.x,
189                  x.y, y.y, z.y, pos.y,
190                  x.z, y.z, z.z, pos.z,
191                    0,   0,   0,     1 );
192 }
193 
194 mat4 calcPerspective( float fov_degree, float ratio, float znear, float zfar )
195 {
196                         /+ fov conv to radians and div 2 +/
197     float h = 1.0 / tan( fov_degree * PI / 360.0 );
198     float w = h / ratio;
199 
200     float depth = znear - zfar;
201     float q = ( znear + zfar ) / depth;
202     float n = ( 2.0f * znear * zfar ) / depth;
203 
204     return mat4( w, 0,  0, 0,
205                  0, h,  0, 0,
206                  0, 0,  q, n,
207                  0, 0, -1, 0 );
208 }
209 
210 mat4 calcOrtho( float w, float h, float znear, float zfar )
211 {
212     float x = znear - zfar;
213     return mat4( 2/w, 0,   0,       0,
214                  0,   2/h, 0,       0,
215                  0,   0,  -1/x,     0,
216                  0,   0,   znear/x, 1 );
217 }