1 /*********************************
2 ** Tsunagari Tile Engine **
4 ** Copyright 2011-2012 OmegaSDG **
5 *********************************/
8 // Permission is hereby granted, free of charge, to any person obtaining a copy
9 // of this software and associated documentation files (the "Software"), to
10 // deal in the Software without restriction, including without limitation the
11 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
12 // sell copies of the Software, and to permit persons to whom the Software is
13 // furnished to do so, subject to the following conditions:
15 // The above copyright notice and this permission notice shall be included in
16 // all copies or substantial portions of the Software.
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
27 #include <Gosu/Graphics.hpp> // for Gosu::screenWidth/Height()
28 #include <Gosu/Math.hpp>
36 Viewport::Viewport(icoord vsize
)
38 virtRes(vsize
.x
, vsize
.y
),
42 double width
= (double)Gosu::screenWidth();
43 double height
= (double)Gosu::screenHeight();
44 aspectRatio
= width
/ height
;
52 void Viewport::tick(unsigned long)
62 rvec2
Viewport::getMapOffset() const
67 rvec2
Viewport::getLetterboxOffset() const
69 return addLetterboxOffset(rvec2(0.0, 0.0));
72 rvec2
Viewport::getScale() const
74 const GameWindow
& window
= GameWindow::instance();
75 rvec2 letterbox
= getLetterbox();
76 rvec2 physRes
= rvec2(
77 (double)window
.width(),
78 (double)window
.height()
82 physRes
.x
/ virtRes
.x
* (1 - letterbox
.x
),
83 physRes
.y
/ virtRes
.y
* (1 - letterbox
.y
)
87 rvec2
Viewport::getPhysRes() const
89 const GameWindow
& window
= GameWindow::instance();
91 (double)window
.width(),
92 (double)window
.height()
96 rvec2
Viewport::getVirtRes() const
101 // Immediatly center render offset. Stop any tracking.
102 void Viewport::jumpToPt(ivec2 pt
)
104 jumpToPt(rvec2((double)pt
.x
, (double)pt
.y
));
107 void Viewport::jumpToPt(rvec2 pt
)
110 off
= offsetForPt(pt
);
113 void Viewport::jumpToEntity(const Entity
* e
)
115 mode
= TM_MANUAL
; // API implies mode change.
120 // Continuously follow.
121 void Viewport::trackEntity(const Entity
* e
)
123 mode
= TM_FOLLOW_ENTITY
;
128 void Viewport::setArea(const Area
* a
)
134 void Viewport::update()
140 case TM_FOLLOW_ENTITY
:
141 _jumpToEntity(targete
);
146 void Viewport::_jumpToEntity(const Entity
* e
)
148 rcoord pos
= e
->getPixelCoord();
149 ivec2 td
= area
->getTileDimensions();
150 rvec2 center
= rvec2(
154 off
= offsetForPt(center
);
158 rvec2
Viewport::getLetterbox() const
160 rvec2 physRes
= getPhysRes();
161 double physAspect
= physRes
.x
/ physRes
.y
;
162 double virtAspect
= virtRes
.x
/ virtRes
.y
;
164 if (physAspect
> virtAspect
) {
165 // Letterbox cuts off left-right.
166 double cut
= 1 - virtAspect
/ physAspect
;
167 return rvec2(cut
, 0);
170 // Letterbox cuts off top-bottom.
171 double cut
= 1 - physAspect
/ virtAspect
;
172 return rvec2(0, cut
);
176 rvec2
Viewport::offsetForPt(rvec2 pt
) const
178 return boundToArea(centerOn(pt
));
181 rvec2
Viewport::centerOn(rvec2 pt
) const
183 return pt
- virtRes
/ 2;
186 rvec2
Viewport::boundToArea(rvec2 pt
) const
188 icoord ad
= area
->getDimensions();
189 ivec2 td
= area
->getTileDimensions();
190 double areaWidth
= ad
.x
* td
.x
;
191 double areaHeight
= ad
.y
* td
.y
;
192 bool loopX
= area
->loopsInX();
193 bool loopY
= area
->loopsInY();
196 boundDimension(virtRes
.x
, areaWidth
, pt
.x
, loopX
),
197 boundDimension(virtRes
.y
, areaHeight
, pt
.y
, loopY
)
201 double Viewport::boundDimension(double screen
, double area
, double pt
,
204 // Since looping areas continue without bound, this is a no-op.
208 // If the Area is smaller than the screen, center the Area. Otherwise,
209 // allow the screen to move to the edge of the Area, but not past.
210 double wiggleRoom
= area
- screen
;
211 return wiggleRoom
<= 0 ?
213 Gosu::boundBy(pt
, 0.0, wiggleRoom
);
216 rvec2
Viewport::addLetterboxOffset(rvec2 pt
) const
218 rvec2 physRes
= getPhysRes();
219 rvec2 letterbox
= getLetterbox();
220 return pt
- letterbox
* physRes
/ 2;