Add documentation on placing tiles.
[Tsunagari.git] / src / viewport.cpp
blob9a0cfa1e8e1bb037fad7f992c10cb0d2549d08ca
1 /*********************************
2 ** Tsunagari Tile Engine **
3 ** viewport.cpp **
4 ** Copyright 2011-2012 OmegaSDG **
5 *********************************/
7 // **********
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
24 // IN THE SOFTWARE.
25 // **********
27 #include <Gosu/Graphics.hpp> // for Gosu::screenWidth/Height()
28 #include <Gosu/Math.hpp>
30 #include "area.h"
31 #include "vec.h"
32 #include "viewport.h"
33 #include "window.h"
36 Viewport::Viewport(icoord vsize)
37 : off(0, 0),
38 virtRes(vsize.x, vsize.y),
39 mode(TM_MANUAL),
40 area(NULL)
42 double width = (double)Gosu::screenWidth();
43 double height = (double)Gosu::screenHeight();
44 aspectRatio = width / height;
47 Viewport::~Viewport()
52 void Viewport::tick(unsigned long)
54 update();
57 void Viewport::turn()
59 update();
62 rvec2 Viewport::getMapOffset() const
64 return off;
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()
81 return rvec2(
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();
90 return rvec2(
91 (double)window.width(),
92 (double)window.height()
96 rvec2 Viewport::getVirtRes() const
98 return virtRes;
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)
109 mode = TM_MANUAL;
110 off = offsetForPt(pt);
113 void Viewport::jumpToEntity(const Entity* e)
115 mode = TM_MANUAL; // API implies mode change.
116 _jumpToEntity(e);
120 // Continuously follow.
121 void Viewport::trackEntity(const Entity* e)
123 mode = TM_FOLLOW_ENTITY;
124 targete = e;
128 void Viewport::setArea(const Area* a)
130 area = a;
134 void Viewport::update()
136 switch (mode) {
137 case TM_MANUAL:
138 // Do nothing.
139 break;
140 case TM_FOLLOW_ENTITY:
141 _jumpToEntity(targete);
142 break;
146 void Viewport::_jumpToEntity(const Entity* e)
148 rcoord pos = e->getPixelCoord();
149 ivec2 td = area->getTileDimensions();
150 rvec2 center = rvec2(
151 pos.x + td.x/2,
152 pos.y + td.y/2
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);
169 else {
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();
195 return rvec2(
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,
202 bool loop) const
204 // Since looping areas continue without bound, this is a no-op.
205 if (loop)
206 return pt;
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 ?
212 wiggleRoom/2 :
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;