1 /*
2     Copyright (C) 2009 Andrew Caudwell (acaudwell@gmail.com)
3 
4     This program is free software; you can redistribute it and/or
5     modify it under the terms of the GNU General Public License
6     as published by the Free Software Foundation; either version
7     3 of the License, or (at your option) any later version.
8 
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13 
14     You should have received a copy of the GNU General Public License
15     along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 */
17 
18 #include "zoomcamera.h"
19 
ZoomCamera()20 ZoomCamera::ZoomCamera() {
21 }
22 
ZoomCamera(vec3 pos,vec3 target,float min_distance,float max_distance)23 ZoomCamera::ZoomCamera(vec3 pos, vec3 target, float min_distance, float max_distance) :
24     pos(pos), _pos(pos), target(target), _target(target),  dest(pos), fov(90.0f) {
25 
26     znear = 0.1;
27 
28     up = vec3(0.0f, -1.0f, 0.0f);
29 
30     setMinDistance(min_distance);
31     setMaxDistance(max_distance);
32 
33     padding = 1.0;
34     speed = 1.0;
35     lockon = false;
36     lockon_time = 0.0;
37     reset();
38 }
39 
reset()40 void ZoomCamera::reset() {
41     pos    = _pos;
42     target = _target;
43 }
44 
getMaxDistance()45 float ZoomCamera::getMaxDistance() { return max_distance; }
getMinDistance()46 float ZoomCamera::getMinDistance() { return min_distance; }
47 
setPadding(float padding)48 void ZoomCamera::setPadding(float padding) {
49     this->padding = padding;
50 }
51 
setMaxDistance(float max)52 void ZoomCamera::setMaxDistance(float max) {
53     max_distance = max;
54     zfar = max + 1.0;
55 }
56 
setMinDistance(float min)57 void ZoomCamera::setMinDistance(float min) {
58     min_distance = min;
59 }
60 
lockOn(bool lockon)61 void ZoomCamera::lockOn(bool lockon) {
62 
63     if(lockon) {
64          lockon_time = 1.0;
65     }
66 
67     this->lockon = lockon;
68 }
69 
look()70 void ZoomCamera::look() {
71     lookAt(target);
72 }
73 
lookAt(const vec3 & target)74 void ZoomCamera::lookAt(const vec3& target) {
75     gluLookAt( pos.x,    pos.y,    pos.z,
76                target.x, target.y, target.z,
77                up.x,     up.y,     up.z);
78 }
79 
focus()80 void ZoomCamera::focus() {
81     display.mode3D(fov, znear, zfar);
82     look();
83 }
84 
stop()85 void ZoomCamera::stop() {
86     this->dest = pos;
87 }
88 
setSpeed(float speed)89 void ZoomCamera::setSpeed(float speed) {
90     this->speed = speed;
91 }
adjust(const Bounds2D & bounds)92 void ZoomCamera::adjust(const Bounds2D& bounds) {
93     adjust(bounds, true);
94 }
95 
adjust(const Bounds2D & bounds,bool adjust_distance)96 void ZoomCamera::adjust(const Bounds2D& bounds, bool adjust_distance) {
97 
98     //center camera on bounds
99 
100     vec2 centre  = bounds.centre();
101 
102     //adjust by screen ratio
103     dest.x = centre.x;
104     dest.y = centre.y;
105 
106     if(!adjust_distance) return;
107 
108     //scale by 10% so we dont have stuff right on the edge of the screen
109     float width  = bounds.width() * padding;
110     float height = bounds.height() * padding;
111 
112     float aspect_ratio = display.width / (float) display.height;
113 
114     if(aspect_ratio < 1.0) {
115         height /= aspect_ratio;
116     } else {
117         width /= aspect_ratio;
118     }
119 
120     //calc visible width of the opposite wall at a distance of 1 this fov
121     float toa = tan( fov * 0.5f * DEGREES_TO_RADIANS ) * 2.0;
122 
123     float distance;
124 
125     //TOA = tan = opposite/adjacent (distance = adjacent)
126     //use the larger side of the box
127 
128     //cropping: vertical, horizontal or none
129     if(gGourceSettings.crop_vertical) {
130 
131         distance =  width / toa;
132 
133 
134     } else if (gGourceSettings.crop_horizontal) {
135 
136         distance =  height / toa;
137 
138     } else {
139 
140         if(width >= height) {
141             distance =  width / toa;
142         } else {
143             distance =  height / toa;
144         }
145     }
146 
147     //debugLog("toa %.2f, distance %.2f width %.2f height %.2f dratio %.2f\n", toa, distance, width, height, dratio);
148 
149     //check bounds are valid
150     if(distance < min_distance) distance = min_distance;
151     if(distance > max_distance) distance = max_distance;
152 
153     this->dest.z = -distance;
154 }
155 
setDistance(float distance)156 void ZoomCamera::setDistance(float distance) {
157     dest.z = -distance;
158 }
159 
setPos(const vec3 & pos,bool keep_angle)160 void ZoomCamera::setPos(const vec3& pos, bool keep_angle)  {
161     if(keep_angle) {
162         vec3 dir = target - this->pos;
163         this->pos = pos;
164         this->target = pos + dir;
165     } else {
166         this->pos = pos;
167     }
168 }
169 
logic(float dt)170 void ZoomCamera::logic(float dt) {
171     vec3 dp = (dest - pos);
172 
173     vec3 dpt = dp * dt * speed;
174 
175     if(lockon) {
176         dpt = dpt * lockon_time + dp * (1.0f-lockon_time);
177 
178         if(lockon_time>0.0) {
179             lockon_time = std::max(0.0f, lockon_time-dt*0.5f);
180         }
181     }
182 
183     if(glm::length2(dpt) > glm::length2(dp)) dpt = dp;
184 
185     pos += dpt;
186 
187     target = vec3(pos.x, pos.y, 0.0);
188 }
189