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