1 /*
2  * Copyright (c) 2013 The Simutrans Community
3  *
4  * This file is part of the Simutrans project under the artistic license.
5  */
6 
7 #ifndef simviewport_h
8 #define simviewport_h
9 
10 #include "../simtypes.h"
11 #include "scr_coord.h"
12 #include "../dataobj/koord.h"
13 #include "../dataobj/koord3d.h"
14 #include "../dataobj/rect.h"
15 #include "../convoihandle_t.h"
16 
17 class karte_t;
18 class grund_t;
19 
20 /**
21  * @brief Map viewing camera.
22  * Describes a camera, looking at our world. Contains various routines to handle the coordinates conversion.
23  *
24  * We handle four level of coordinates, described here:
25  * - map_coord: It's a three dimensional coordinate, located in the simulated world. Implemented with koord3d, most game objects are positioned like this.
26  * - map2d_coord: Two-dimensional coordinate, located in the simulated world, they are assumed z=0. Implemented with koord.
27  * - viewport_coord: Two-dimensional coordinate, with our camera transformations applied, where 0,0 is the center of screen.
28  * - screen_coord: Final transformation, exact coordinate on the output frame buffer.
29  *
30  * Diagram of a viewport screen, each viewport_coord corresponds to one of the diamonds:
31  * --------------------
32  * |\/\/\/\/\/\/\/\/\/|
33  * |/\/\/\/\/\/\/\/\/\|
34  * |\/\/\/\/\/\/\/\/\/|
35  * |/\/\/\/\/\/\/\/\/\|
36  * |\/\/\/\/\/\/\/\/\/|
37  * |/\/\/\/\/\/\/\/\/\|
38  * |\/\/\/\/\/\/\/\/\/|
39  * --------------------
40  */
41 class viewport_t
42 {
43 public:
44 	/**
45 	 * @brief The prepared area of the view port.
46 	 *
47 	 * The area that has already been prepared for this view port. When the view
48 	 * port is moved then only the new area not already prepared will be
49 	 * prepared. If the view port is stationary no area will be prepared.
50 	 */
51 	rect_t prepared_rect;
52 
53 private:
54 	/// The simulated world this view is associated to.
55 	karte_t *world;
56 	/**
57 	 * @name Camera position
58 	 *       This variables are related to the view camera position.
59 	 * @{
60 	 */
61 
62 	/**
63 	 * Current view position, expressed in 2D map coordinates.
64 	 * @see x_off
65 	 * @see y_off
66 	 */
67 	koord ij_off;
68 
69 	sint16 x_off; //!< Fine scrolling x offset. Units in pixels.
70 	sint16 y_off; //!< Fine scrolling y offset. Units in pixels.
71 
72 	/**
73 	 * This is the current offset for getting from tile to screen.
74 	 * @note Extra offset, if added to ij_off it will give us the 2D coordinate of the tile on the *BOTTOM-RIGHT* of screen.
75 	 */
76 	koord view_ij_off;
77 
78 	/**
79 	 * For performance reasons, we cache ( (0,0)-ij_off-view_ij_off ) here
80 	 */
81 	koord cached_aggregated_off;
82 
83 	/**
84 	 * @}
85 	 */
86 
87 	sint16 cached_disp_width;	//!< Cached window width
88 	sint16 cached_disp_height;	//!< Cached window height
89 	sint16 cached_img_size;		//!< Cached base raster image size
90 
91 	/**
92 	 * Sets current ij offsets of this viewport, depends of its proportions and the zoom level.
93 	 */
94 	void set_viewport_ij_offset( const koord &k );
95 
96 	/*
97 	 * The current convoi to follow.
98 	 * @author prissi
99 	 */
100 	convoihandle_t follow_convoi;
101 
102 	/**
103 	 * Converts map_coord to map2d_coord actually used for main view.
104 	 */
105 	koord get_map2d_coord( const koord3d& ) const;
106 
107 	/**
108 	 * Returns the viewport_coord coordinates of the requested map2d_coord coordinate.
109 	 */
110 	koord get_viewport_coord( const koord& coord ) const;
111 
112 	/**
113 	 * Updates the transformation vector we have cached.
114 	 */
update_cached_values()115 	void update_cached_values() {
116 		cached_aggregated_off = -ij_off-view_ij_off;
117 	};
118 
119 public:
120 
121 	/**
122 	 * @name Coordinate transformations.
123 	 *       This methods handle the projection from the map coordinates, to 2D, screen coordinates.
124 	 * @{
125 	 */
126 
127 	/**
128 	 * Takes a in-game 3D coordinates and returns which coordinate in screen corresponds to it.
129 	 * @param pos 3D in-map coordinate.
130 	 * @param off offset to add to the final coordinates, in pixels (will be scaled to zoom level).
131 	 */
132 	scr_coord get_screen_coord( const koord3d& pos, const koord& off = koord(0,0) ) const;
133 
134 	/**
135 	 * Scales the 2D dimensions, expressed on base raster size pixels, to the current viewport.
136 	 */
137 	scr_coord scale_offset(const koord &value);
138 
139 	/**
140 	 * Checks a 3d in-map coordinate, to know if it's centered on the current viewport.
141 	 * @param pos 3D map coordinate to check.
142 	 * @return true if the requested map coordinates are on the center of the viewport, false otherwise.
143 	 */
is_on_center(const koord3d & pos)144 	bool is_on_center(const koord3d &pos) const {
145 		return ( (get_x_off() | get_y_off()) == 0  &&
146 			get_world_position() == get_map2d_coord( pos ) );
147 	}
148 
149 	/**
150 	 * @}
151 	 */
152 
153 	/**
154 	 * @name Camera position
155 	 *       This methods are related to the view camera position.
156 	 * @{
157 	 */
158 
159 	/**
160 	 * Viewpoint in tile coordinates. i,j coordinate of the tile in center of screen.
161 	 */
get_world_position()162 	koord get_world_position() const { return ij_off; }
163 
164 	/**
165 	 * Offset from tile on center to tile in top-left corner of screen.
166 	 */
get_viewport_ij_offset()167 	koord get_viewport_ij_offset() const { return view_ij_off; }
168 
169 	/**
170 	 * Set center viewport position.
171 	 * @author prissi
172 	 */
173 	void change_world_position( koord ij, sint16 x=0, sint16 y=0 );
174 
175 	/**
176 	 * Set center viewport position, taking height into account
177 	 */
178 	void change_world_position( const koord3d& ij );
179 
180 	/**
181 	 * Set center viewport position, placing a in-game koord3d under the desired screen position.
182 	 * @param pos map position to consider.
183 	 * @param off extra offset.
184 	 * @param sc screen position "pos" should be under.
185 	 */
186 	void change_world_position(const koord3d& pos, const koord& off, scr_coord sc);
187 
188 	/**
189 	 * Fine offset within the viewport tile.
190 	 */
get_x_off()191 	int get_x_off() const {return x_off;}
192 
193 	/**
194 	 * Fine offset within the viewport tile.
195 	 */
set_x_off(sint16 value)196 	void set_x_off(sint16 value) {x_off = value;}
197 
198 	/**
199 	 * Fine offset within the viewport tile.
200 	 */
get_y_off()201 	int get_y_off() const {return y_off;}
202 
203 	/**
204 	 * Fine offset within the viewport tile.
205 	 */
set_y_off(sint16 value)206 	void set_y_off(sint16 value) {y_off = value;}
207 
208 	/**
209 	 * @}
210 	 */
211 
212 	/**
213 	 * @name Ray tracing
214 	 *       This methods are related to the act of finding a in-map entity, given a screen_cord. Used for player interaction, mainly.
215 	 * @{
216 	 */
217 
218 	/**
219 	 * Searches for the ground_t that's under the requested screen position.
220 	 * @param screen_pos Screen coordinates to check for.
221 	 * @param intersect_grid Special case for the lower/raise tool, will return a limit border tile if we are on the south/east border of screen.
222 	 * @param found_i out parameter, i-coordinate of the found tile. It's necessary because it might point to a grid position that doesn't map to a real in-map coordinate, on border tiles (south and east border).
223 	 * @param found_j out parameter, j-coordinate of the found tile. It's necessary because it might point to a grid position that doesn't map to a real in-map coordinate, on border tiles (south and east border).
224 	 * @return the grund_t that's under the desired screen coordinate. NULL if we are outside map or we can't find it.
225 	 */
226 	grund_t* get_ground_on_screen_coordinate(scr_coord screen_pos, sint32 &found_i, sint32 &found_j, const bool intersect_grid=false) const;
227 
228 	/**
229 	 * Gets a new world position, under the requested screen coordinates. Used to move the cursor.
230 	 * @param screen_pos Screen position to check. Input parameter.
231 	 * @param grid_coordinates indicates if this function is to check against the map tiles, or the grid of heights. Input parameter.
232 	 * @return koord3d::invalid if no position exists under the requested coordinate, a 3d koord directly under it otherwise.
233 	 */
234 	koord3d get_new_cursor_position(const scr_coord &screen_pos, bool grid_coordinates);
235 
236 	/**
237 	 * @}
238 	 */
239 
240 	/**
241 	 * @name Convoi following
242 	 *       This methods are related to the mechanics of a viewport follow a vehicle.
243 	 * @{
244 	 */
245 
246 	/**
247 	 * Function for following a convoi on the map give an unbound handle to unset.
248 	 */
set_follow_convoi(convoihandle_t cnv)249 	void set_follow_convoi(convoihandle_t cnv) { follow_convoi = cnv; }
250 
251 	/**
252 	 * Returns the convoi this viewport is following (if any).
253 	 */
get_follow_convoi()254 	convoihandle_t get_follow_convoi() const { return follow_convoi; }
255 
256 	/**
257 	 * @}
258 	 */
259 
260 	/**
261 	 * This class caches the viewport dimensions, and the base image size. On zoom or viewport resize, call this
262 	 * method to force its recalculation.
263 	 */
264 	void metrics_updated();
265 
266 	/**
267 	 * (A better description is needed here)
268 	 * Operations needed on map rotation.
269 	 */
270 	void rotate90( sint16 y_size );
271 
272 	viewport_t( karte_t *world, const koord ij_off = koord::invalid, sint16 x_off = 0, sint16 y_off = 0 );
273 };
274 
275 #endif
276