1 /*********************************
2 ** Tsunagari Tile Engine **
4 ** Copyright 2011-2012 OmegaSDG **
5 *********************************/
7 #include <Gosu/Graphics.hpp> // for Gosu::screenWidth/Height()
8 #include <Gosu/Math.hpp>
16 Viewport::Viewport(icoord vsize
)
18 virtRes(vsize
.x
, vsize
.y
),
22 double width
= (double)Gosu::screenWidth();
23 double height
= (double)Gosu::screenHeight();
24 aspectRatio
= width
/ height
;
32 void Viewport::tick(unsigned long)
42 rvec2
Viewport::getMapOffset() const
47 rvec2
Viewport::getLetterboxOffset() const
49 return addLetterboxOffset(rvec2(0.0, 0.0));
52 rvec2
Viewport::getScale() const
54 const GameWindow
& window
= GameWindow::instance();
55 rvec2 letterbox
= getLetterbox();
56 rvec2 physRes
= rvec2(
57 (double)window
.width(),
58 (double)window
.height()
62 physRes
.x
/ virtRes
.x
* (1 - letterbox
.x
),
63 physRes
.y
/ virtRes
.y
* (1 - letterbox
.y
)
67 rvec2
Viewport::getPhysRes() const
69 const GameWindow
& window
= GameWindow::instance();
71 (double)window
.width(),
72 (double)window
.height()
76 rvec2
Viewport::getVirtRes() const
81 // Immediatly center render offset. Stop any tracking.
82 void Viewport::jumpToPt(ivec2 pt
)
84 jumpToPt(rvec2((double)pt
.x
, (double)pt
.y
));
87 void Viewport::jumpToPt(rvec2 pt
)
90 off
= offsetForPt(pt
);
93 void Viewport::jumpToEntity(const Entity
* e
)
95 mode
= TM_MANUAL
; // API implies mode change.
100 // Continuously follow.
101 void Viewport::trackEntity(const Entity
* e
)
103 mode
= TM_FOLLOW_ENTITY
;
108 void Viewport::setArea(const Area
* a
)
114 void Viewport::update()
120 case TM_FOLLOW_ENTITY
:
121 _jumpToEntity(targete
);
126 void Viewport::_jumpToEntity(const Entity
* e
)
128 rcoord pos
= e
->getPixelCoord();
129 ivec2 td
= area
->getTileDimensions();
130 rvec2 center
= rvec2(
134 off
= offsetForPt(center
);
138 rvec2
Viewport::getLetterbox() const
140 rvec2 physRes
= getPhysRes();
141 double physAspect
= physRes
.x
/ physRes
.y
;
142 double virtAspect
= virtRes
.x
/ virtRes
.y
;
144 if (physAspect
> virtAspect
) {
145 // Letterbox cuts off left-right.
146 double cut
= 1 - virtAspect
/ physAspect
;
147 return rvec2(cut
, 0);
150 // Letterbox cuts off top-bottom.
151 double cut
= 1 - physAspect
/ virtAspect
;
152 return rvec2(0, cut
);
156 rvec2
Viewport::offsetForPt(rvec2 pt
) const
158 return boundToArea(centerOn(pt
));
161 rvec2
Viewport::centerOn(rvec2 pt
) const
163 return pt
- virtRes
/ 2;
166 rvec2
Viewport::boundToArea(rvec2 pt
) const
168 icoord ad
= area
->getDimensions();
169 ivec2 td
= area
->getTileDimensions();
170 double areaWidth
= ad
.x
* td
.x
;
171 double areaHeight
= ad
.y
* td
.y
;
172 bool loopX
= area
->loopsInX();
173 bool loopY
= area
->loopsInY();
176 boundDimension(virtRes
.x
, areaWidth
, pt
.x
, loopX
),
177 boundDimension(virtRes
.y
, areaHeight
, pt
.y
, loopY
)
181 double Viewport::boundDimension(double screen
, double area
, double pt
,
184 // Since looping areas continue without bound, this is a no-op.
188 // If the Area is smaller than the screen, center the Area. Otherwise,
189 // allow the screen to move to the edge of the Area, but not past.
190 double wiggleRoom
= area
- screen
;
191 return wiggleRoom
<= 0 ?
193 Gosu::boundBy(pt
, 0.0, wiggleRoom
);
196 rvec2
Viewport::addLetterboxOffset(rvec2 pt
) const
198 rvec2 physRes
= getPhysRes();
199 rvec2 letterbox
= getLetterbox();
200 return pt
- letterbox
* physRes
/ 2;