Only update vehicle image when in the vicinity of a viewport
This reduces the performance impact of expensive NewGRF graphics chains.
This commit is contained in:
127
src/vehicle.cpp
127
src/vehicle.cpp
@@ -890,6 +890,49 @@ static void UpdateVehicleViewportHash(Vehicle *v, int x, int y)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ViewportHashDeferredItem {
|
||||||
|
Vehicle *v;
|
||||||
|
int new_hash;
|
||||||
|
int old_hash;
|
||||||
|
};
|
||||||
|
static std::vector<ViewportHashDeferredItem> _viewport_hash_deferred;
|
||||||
|
|
||||||
|
static void UpdateVehicleViewportHashDeferred(Vehicle *v, int x, int y)
|
||||||
|
{
|
||||||
|
int old_x = v->coord.left;
|
||||||
|
int old_y = v->coord.top;
|
||||||
|
|
||||||
|
int new_hash = (x == INVALID_COORD) ? INVALID_COORD : GEN_HASH(x, y);
|
||||||
|
int old_hash = (old_x == INVALID_COORD) ? INVALID_COORD : GEN_HASH(old_x, old_y);
|
||||||
|
|
||||||
|
if (new_hash != old_hash) {
|
||||||
|
_viewport_hash_deferred.push_back({ v, new_hash, old_hash });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ProcessDeferredUpdateVehicleViewportHashes()
|
||||||
|
{
|
||||||
|
for (const ViewportHashDeferredItem &item : _viewport_hash_deferred) {
|
||||||
|
Vehicle *v = item.v;
|
||||||
|
|
||||||
|
/* remove from hash table? */
|
||||||
|
if (item.old_hash != INVALID_COORD) {
|
||||||
|
if (v->hash_viewport_next != nullptr) v->hash_viewport_next->hash_viewport_prev = v->hash_viewport_prev;
|
||||||
|
*v->hash_viewport_prev = v->hash_viewport_next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* insert into hash table? */
|
||||||
|
if (item.new_hash != INVALID_COORD) {
|
||||||
|
Vehicle **new_hash = &_vehicle_viewport_hash[item.new_hash];
|
||||||
|
v->hash_viewport_next = *new_hash;
|
||||||
|
if (v->hash_viewport_next != nullptr) v->hash_viewport_next->hash_viewport_prev = &v->hash_viewport_next;
|
||||||
|
v->hash_viewport_prev = new_hash;
|
||||||
|
*new_hash = v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_viewport_hash_deferred.clear();
|
||||||
|
}
|
||||||
|
|
||||||
void ResetVehicleHash()
|
void ResetVehicleHash()
|
||||||
{
|
{
|
||||||
for (Vehicle *v : Vehicle::Iterate()) { v->hash_tile_current = nullptr; }
|
for (Vehicle *v : Vehicle::Iterate()) { v->hash_tile_current = nullptr; }
|
||||||
@@ -1686,9 +1729,11 @@ struct ViewportHashBound {
|
|||||||
int xl, xu, yl, yu;
|
int xl, xu, yl, yu;
|
||||||
};
|
};
|
||||||
|
|
||||||
static ViewportHashBound GetViewportHashBound(int l, int r, int t, int b) {
|
static const int VHB_BASE_MARGIN = 70;
|
||||||
int xl = (l - (70 * ZOOM_LVL_BASE)) >> (7 + ZOOM_LVL_SHIFT);
|
|
||||||
int xu = (r ) >> (7 + ZOOM_LVL_SHIFT);
|
static ViewportHashBound GetViewportHashBound(int l, int r, int t, int b, int x_margin, int y_margin) {
|
||||||
|
int xl = (l - ((VHB_BASE_MARGIN + x_margin) * ZOOM_LVL_BASE)) >> (7 + ZOOM_LVL_SHIFT);
|
||||||
|
int xu = (r + (x_margin * ZOOM_LVL_BASE)) >> (7 + ZOOM_LVL_SHIFT);
|
||||||
/* compare after shifting instead of before, so that lower bits don't affect comparison result */
|
/* compare after shifting instead of before, so that lower bits don't affect comparison result */
|
||||||
if (xu - xl < (1 << 6)) {
|
if (xu - xl < (1 << 6)) {
|
||||||
xl &= 0x3F;
|
xl &= 0x3F;
|
||||||
@@ -1699,8 +1744,8 @@ static ViewportHashBound GetViewportHashBound(int l, int r, int t, int b) {
|
|||||||
xu = 0x3F;
|
xu = 0x3F;
|
||||||
}
|
}
|
||||||
|
|
||||||
int yl = (t - (70 * ZOOM_LVL_BASE)) >> (6 + ZOOM_LVL_SHIFT);
|
int yl = (t - ((VHB_BASE_MARGIN + y_margin) * ZOOM_LVL_BASE)) >> (6 + ZOOM_LVL_SHIFT);
|
||||||
int yu = (b ) >> (6 + ZOOM_LVL_SHIFT);
|
int yu = (b + (y_margin * ZOOM_LVL_BASE)) >> (6 + ZOOM_LVL_SHIFT);
|
||||||
/* compare after shifting instead of before, so that lower bits don't affect comparison result */
|
/* compare after shifting instead of before, so that lower bits don't affect comparison result */
|
||||||
if (yu - yl < (1 << 6)) {
|
if (yu - yl < (1 << 6)) {
|
||||||
yl = (yl & 0x3F) << 6;
|
yl = (yl & 0x3F) << 6;
|
||||||
@@ -1713,11 +1758,8 @@ static ViewportHashBound GetViewportHashBound(int l, int r, int t, int b) {
|
|||||||
return { xl, xu, yl, yu };
|
return { xl, xu, yl, yu };
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
template <bool update_vehicles>
|
||||||
* Add the vehicle sprites that should be drawn at a part of the screen.
|
void ViewportAddVehiclesIntl(DrawPixelInfo *dpi)
|
||||||
* @param dpi Rectangle being drawn.
|
|
||||||
*/
|
|
||||||
void ViewportAddVehicles(DrawPixelInfo *dpi)
|
|
||||||
{
|
{
|
||||||
/* The bounding rectangle */
|
/* The bounding rectangle */
|
||||||
const int l = dpi->left;
|
const int l = dpi->left;
|
||||||
@@ -1726,20 +1768,46 @@ void ViewportAddVehicles(DrawPixelInfo *dpi)
|
|||||||
const int b = dpi->top + dpi->height;
|
const int b = dpi->top + dpi->height;
|
||||||
|
|
||||||
/* The hash area to scan */
|
/* The hash area to scan */
|
||||||
const ViewportHashBound vhb = GetViewportHashBound(l, r, t, b);
|
const ViewportHashBound vhb = GetViewportHashBound(l, r, t, b,
|
||||||
|
update_vehicles ? MAX_VEHICLE_PIXEL_X - VHB_BASE_MARGIN : 0, update_vehicles ? MAX_VEHICLE_PIXEL_Y - VHB_BASE_MARGIN : 0);
|
||||||
|
|
||||||
|
const int ul = l - (MAX_VEHICLE_PIXEL_X * ZOOM_LVL_BASE);
|
||||||
|
const int ur = r + (MAX_VEHICLE_PIXEL_X * ZOOM_LVL_BASE);
|
||||||
|
const int ut = t - (MAX_VEHICLE_PIXEL_Y * ZOOM_LVL_BASE);
|
||||||
|
const int ub = b + (MAX_VEHICLE_PIXEL_Y * ZOOM_LVL_BASE);
|
||||||
|
|
||||||
for (int y = vhb.yl;; y = (y + (1 << 6)) & (0x3F << 6)) {
|
for (int y = vhb.yl;; y = (y + (1 << 6)) & (0x3F << 6)) {
|
||||||
for (int x = vhb.xl;; x = (x + 1) & 0x3F) {
|
for (int x = vhb.xl;; x = (x + 1) & 0x3F) {
|
||||||
const Vehicle *v = _vehicle_viewport_hash[x + y]; // already masked & 0xFFF
|
const Vehicle *v = _vehicle_viewport_hash[x + y]; // already masked & 0xFFF
|
||||||
|
|
||||||
while (v != nullptr) {
|
while (v != nullptr) {
|
||||||
if (v->IsDrawn() &&
|
if (v->IsDrawn()) {
|
||||||
l <= v->coord.right &&
|
if (update_vehicles &&
|
||||||
|
HasBit(v->vcache.cached_veh_flags, VCF_IMAGE_REFRESH) &&
|
||||||
|
ul <= v->coord.right &&
|
||||||
|
ut <= v->coord.bottom &&
|
||||||
|
ur >= v->coord.left &&
|
||||||
|
ub >= v->coord.top) {
|
||||||
|
Vehicle *v_mutable = const_cast<Vehicle *>(v);
|
||||||
|
Direction current_direction = v_mutable->GetMapImageDirection();
|
||||||
|
switch (v->type) {
|
||||||
|
case VEH_TRAIN: Train::From(v_mutable)->UpdateImageState(current_direction, v_mutable->sprite_seq); break;
|
||||||
|
case VEH_ROAD: RoadVehicle::From(v_mutable)->UpdateImageState(current_direction, v_mutable->sprite_seq); break;
|
||||||
|
case VEH_SHIP: Ship::From(v_mutable)->UpdateImageState(current_direction, v_mutable->sprite_seq); break;
|
||||||
|
case VEH_AIRCRAFT: Aircraft::From(v_mutable)->UpdateImageState(current_direction, v_mutable->sprite_seq); break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
v_mutable->UpdateSpriteSeqBound();
|
||||||
|
v_mutable->UpdateViewportDeferred();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (l <= v->coord.right &&
|
||||||
t <= v->coord.bottom &&
|
t <= v->coord.bottom &&
|
||||||
r >= v->coord.left &&
|
r >= v->coord.left &&
|
||||||
b >= v->coord.top) {
|
b >= v->coord.top) {
|
||||||
DoDrawVehicle(v);
|
DoDrawVehicle(v);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
v = v->hash_viewport_next;
|
v = v->hash_viewport_next;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1748,6 +1816,22 @@ void ViewportAddVehicles(DrawPixelInfo *dpi)
|
|||||||
|
|
||||||
if (y == vhb.yu) break;
|
if (y == vhb.yu) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (update_vehicles) ProcessDeferredUpdateVehicleViewportHashes();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the vehicle sprites that should be drawn at a part of the screen.
|
||||||
|
* @param dpi Rectangle being drawn.
|
||||||
|
* @param update_vehicles Whether to update vehicles around drawing rectangle.
|
||||||
|
*/
|
||||||
|
void ViewportAddVehicles(DrawPixelInfo *dpi, bool update_vehicles)
|
||||||
|
{
|
||||||
|
if (update_vehicles) {
|
||||||
|
ViewportAddVehiclesIntl<true>(dpi);
|
||||||
|
} else {
|
||||||
|
ViewportAddVehiclesIntl<false>(dpi);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewportMapDrawVehicles(DrawPixelInfo *dpi, Viewport *vp)
|
void ViewportMapDrawVehicles(DrawPixelInfo *dpi, Viewport *vp)
|
||||||
@@ -1759,7 +1843,7 @@ void ViewportMapDrawVehicles(DrawPixelInfo *dpi, Viewport *vp)
|
|||||||
const int b = vp->virtual_top + vp->virtual_height;
|
const int b = vp->virtual_top + vp->virtual_height;
|
||||||
|
|
||||||
/* The hash area to scan */
|
/* The hash area to scan */
|
||||||
const ViewportHashBound vhb = GetViewportHashBound(l, r, t, b);
|
const ViewportHashBound vhb = GetViewportHashBound(l, r, t, b, 0, 0);
|
||||||
|
|
||||||
Blitter *blitter = BlitterFactory::GetCurrentBlitter();
|
Blitter *blitter = BlitterFactory::GetCurrentBlitter();
|
||||||
for (int y = vhb.yl;; y = (y + (1 << 6)) & (0x3F << 6)) {
|
for (int y = vhb.yl;; y = (y + (1 << 6)) & (0x3F << 6)) {
|
||||||
@@ -2489,6 +2573,21 @@ void Vehicle::UpdateViewport(bool dirty)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Vehicle::UpdateViewportDeferred()
|
||||||
|
{
|
||||||
|
Rect new_coord = ConvertRect<Rect16, Rect>(this->sprite_seq_bounds);
|
||||||
|
|
||||||
|
Point pt = RemapCoords(this->x_pos + this->x_offs, this->y_pos + this->y_offs, this->z_pos);
|
||||||
|
new_coord.left += pt.x;
|
||||||
|
new_coord.top += pt.y;
|
||||||
|
new_coord.right += pt.x + 2 * ZOOM_LVL_BASE;
|
||||||
|
new_coord.bottom += pt.y + 2 * ZOOM_LVL_BASE;
|
||||||
|
|
||||||
|
UpdateVehicleViewportHashDeferred(this, new_coord.left, new_coord.top);
|
||||||
|
|
||||||
|
this->coord = new_coord;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the position of the vehicle, and update the viewport.
|
* Update the position of the vehicle, and update the viewport.
|
||||||
*/
|
*/
|
||||||
|
@@ -23,6 +23,7 @@
|
|||||||
#include "timetable.h"
|
#include "timetable.h"
|
||||||
#include "base_consist.h"
|
#include "base_consist.h"
|
||||||
#include "newgrf_cache_check.h"
|
#include "newgrf_cache_check.h"
|
||||||
|
#include "landscape.h"
|
||||||
#include "network/network.h"
|
#include "network/network.h"
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <map>
|
#include <map>
|
||||||
@@ -882,6 +883,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void UpdateViewport(bool dirty);
|
void UpdateViewport(bool dirty);
|
||||||
|
void UpdateViewportDeferred();
|
||||||
void UpdatePositionAndViewport();
|
void UpdatePositionAndViewport();
|
||||||
void MarkAllViewportsDirty() const;
|
void MarkAllViewportsDirty() const;
|
||||||
|
|
||||||
@@ -1185,6 +1187,19 @@ public:
|
|||||||
IterateWrapper Orders() const { return IterateWrapper(this->orders.list); }
|
IterateWrapper Orders() const { return IterateWrapper(this->orders.list); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline bool IsPointInViewportVehicleRedrawArea(const std::vector<Rect> &viewport_redraw_rects, const Point &pt)
|
||||||
|
{
|
||||||
|
for (const Rect &r : viewport_redraw_rects) {
|
||||||
|
if (pt.x >= r.left &&
|
||||||
|
pt.x <= r.right &&
|
||||||
|
pt.y >= r.top &&
|
||||||
|
pt.y <= r.bottom) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class defining several overloaded accessors so we don't
|
* Class defining several overloaded accessors so we don't
|
||||||
* have to cast vehicle types that often
|
* have to cast vehicle types that often
|
||||||
@@ -1327,17 +1342,9 @@ struct SpecializedVehicle : public Vehicle {
|
|||||||
return (const T *)v;
|
return (const T *)v;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private:
|
||||||
* Update vehicle sprite- and position caches
|
inline uint16 GetVehicleCurvature() const
|
||||||
* @param force_update Force updating the vehicle on the viewport.
|
|
||||||
* @param update_delta Also update the delta?
|
|
||||||
*/
|
|
||||||
inline void UpdateViewport(bool force_update, bool update_delta)
|
|
||||||
{
|
{
|
||||||
/* Skip updating sprites on dedicated servers without screen */
|
|
||||||
if (_network_dedicated) return;
|
|
||||||
|
|
||||||
auto get_vehicle_curvature = [&]() -> uint16 {
|
|
||||||
uint16 curvature = 0;
|
uint16 curvature = 0;
|
||||||
if (this->Previous() != nullptr) {
|
if (this->Previous() != nullptr) {
|
||||||
SB(curvature, 0, 4, this->Previous()->direction);
|
SB(curvature, 0, 4, this->Previous()->direction);
|
||||||
@@ -1348,29 +1355,26 @@ struct SpecializedVehicle : public Vehicle {
|
|||||||
if (this->Next()->Next() != nullptr) SB(curvature, 12, 4, this->Next()->Next()->direction);
|
if (this->Next()->Next() != nullptr) SB(curvature, 12, 4, this->Next()->Next()->direction);
|
||||||
}
|
}
|
||||||
return curvature;
|
return curvature;
|
||||||
};
|
}
|
||||||
|
|
||||||
auto check_vehicle_curvature = [&]() -> bool {
|
inline bool CheckVehicleCurvature() const {
|
||||||
if (!(EXPECTED_TYPE == VEH_TRAIN || EXPECTED_TYPE == VEH_ROAD)) return false;
|
if (!(EXPECTED_TYPE == VEH_TRAIN || EXPECTED_TYPE == VEH_ROAD)) return false;
|
||||||
if (likely(!HasBit(this->vcache.cached_veh_flags, VCF_IMAGE_CURVATURE))) return false;
|
if (likely(!HasBit(this->vcache.cached_veh_flags, VCF_IMAGE_CURVATURE))) return false;
|
||||||
return this->vcache.cached_image_curvature != get_vehicle_curvature();
|
return this->vcache.cached_image_curvature != this->GetVehicleCurvature();
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Explicitly choose method to call to prevent vtable dereference -
|
public:
|
||||||
* it gives ~3% runtime improvements in games with many vehicles */
|
inline void UpdateImageState(Direction current_direction, VehicleSpriteSeq &seq)
|
||||||
if (update_delta) ((T *)this)->T::UpdateDeltaXY();
|
{
|
||||||
const Direction current_direction = ((T *)this)->GetMapImageDirection();
|
ClrBit(this->vcache.cached_veh_flags, VCF_IMAGE_REFRESH);
|
||||||
if (this->cur_image_valid_dir != current_direction || check_vehicle_curvature()) {
|
|
||||||
_sprite_group_resolve_check_veh_check = true;
|
_sprite_group_resolve_check_veh_check = true;
|
||||||
if (EXPECTED_TYPE == VEH_TRAIN || EXPECTED_TYPE == VEH_ROAD) _sprite_group_resolve_check_veh_curvature_check = true;
|
if (EXPECTED_TYPE == VEH_TRAIN || EXPECTED_TYPE == VEH_ROAD) _sprite_group_resolve_check_veh_curvature_check = true;
|
||||||
VehicleSpriteSeq seq;
|
|
||||||
((T *)this)->T::GetImage(current_direction, EIT_ON_MAP, &seq);
|
((T *)this)->T::GetImage(current_direction, EIT_ON_MAP, &seq);
|
||||||
if (EXPECTED_TYPE == VEH_TRAIN || EXPECTED_TYPE == VEH_ROAD) {
|
if (EXPECTED_TYPE == VEH_TRAIN || EXPECTED_TYPE == VEH_ROAD) {
|
||||||
ClrBit(this->vcache.cached_veh_flags, VCF_IMAGE_REFRESH);
|
|
||||||
SB(this->vcache.cached_veh_flags, VCF_IMAGE_REFRESH_NEXT, 1, _sprite_group_resolve_check_veh_check ? 0 : 1);
|
SB(this->vcache.cached_veh_flags, VCF_IMAGE_REFRESH_NEXT, 1, _sprite_group_resolve_check_veh_check ? 0 : 1);
|
||||||
if (unlikely(!_sprite_group_resolve_check_veh_curvature_check)) {
|
if (unlikely(!_sprite_group_resolve_check_veh_curvature_check)) {
|
||||||
SetBit(this->vcache.cached_veh_flags, VCF_IMAGE_CURVATURE);
|
SetBit(this->vcache.cached_veh_flags, VCF_IMAGE_CURVATURE);
|
||||||
this->vcache.cached_image_curvature = get_vehicle_curvature();
|
this->vcache.cached_image_curvature = this->GetVehicleCurvature();
|
||||||
}
|
}
|
||||||
_sprite_group_resolve_check_veh_curvature_check = false;
|
_sprite_group_resolve_check_veh_curvature_check = false;
|
||||||
this->cur_image_valid_dir = current_direction;
|
this->cur_image_valid_dir = current_direction;
|
||||||
@@ -1378,6 +1382,15 @@ struct SpecializedVehicle : public Vehicle {
|
|||||||
this->cur_image_valid_dir = _sprite_group_resolve_check_veh_check ? current_direction : INVALID_DIR;
|
this->cur_image_valid_dir = _sprite_group_resolve_check_veh_check ? current_direction : INVALID_DIR;
|
||||||
}
|
}
|
||||||
_sprite_group_resolve_check_veh_check = false;
|
_sprite_group_resolve_check_veh_check = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
inline void UpdateViewportNormalViewportMode(bool force_update, Point pt)
|
||||||
|
{
|
||||||
|
const Direction current_direction = ((T *)this)->GetMapImageDirection();
|
||||||
|
if (this->cur_image_valid_dir != current_direction || this->CheckVehicleCurvature()) {
|
||||||
|
VehicleSpriteSeq seq;
|
||||||
|
this->UpdateImageState(current_direction, seq);
|
||||||
if (force_update || this->sprite_seq != seq) {
|
if (force_update || this->sprite_seq != seq) {
|
||||||
this->sprite_seq = seq;
|
this->sprite_seq = seq;
|
||||||
this->UpdateSpriteSeqBound();
|
this->UpdateSpriteSeqBound();
|
||||||
@@ -1393,6 +1406,37 @@ struct SpecializedVehicle : public Vehicle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Update vehicle sprite- and position caches
|
||||||
|
* @param force_update Force updating the vehicle on the viewport.
|
||||||
|
* @param update_delta Also update the delta?
|
||||||
|
*/
|
||||||
|
inline void UpdateViewport(bool force_update, bool update_delta)
|
||||||
|
{
|
||||||
|
/* Skip updating sprites on dedicated servers without screen */
|
||||||
|
if (_network_dedicated) return;
|
||||||
|
|
||||||
|
/* Explicitly choose method to call to prevent vtable dereference -
|
||||||
|
* it gives ~3% runtime improvements in games with many vehicles */
|
||||||
|
if (update_delta) ((T *)this)->T::UpdateDeltaXY();
|
||||||
|
|
||||||
|
extern std::vector<Rect> _viewport_vehicle_normal_redraw_rects;
|
||||||
|
extern std::vector<Rect> _viewport_vehicle_map_redraw_rects;
|
||||||
|
|
||||||
|
Point pt = RemapCoords(this->x_pos + this->x_offs, this->y_pos + this->y_offs, this->z_pos);
|
||||||
|
if (EXPECTED_TYPE >= VEH_COMPANY_END || IsPointInViewportVehicleRedrawArea(_viewport_vehicle_normal_redraw_rects, pt)) {
|
||||||
|
UpdateViewportNormalViewportMode(force_update, pt);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetBit(this->vcache.cached_veh_flags, VCF_IMAGE_REFRESH);
|
||||||
|
|
||||||
|
if (force_update) {
|
||||||
|
this->Vehicle::UpdateViewport(IsPointInViewportVehicleRedrawArea(_viewport_vehicle_map_redraw_rects, pt));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an iterable ensemble of all valid vehicles of type T
|
* Returns an iterable ensemble of all valid vehicles of type T
|
||||||
* @param from index of the first vehicle to consider
|
* @param from index of the first vehicle to consider
|
||||||
|
@@ -127,7 +127,7 @@ void ResetVehicleColourMap();
|
|||||||
|
|
||||||
byte GetBestFittingSubType(Vehicle *v_from, Vehicle *v_for, CargoID dest_cargo_type);
|
byte GetBestFittingSubType(Vehicle *v_from, Vehicle *v_for, CargoID dest_cargo_type);
|
||||||
|
|
||||||
void ViewportAddVehicles(DrawPixelInfo *dpi);
|
void ViewportAddVehicles(DrawPixelInfo *dpi, bool update_vehicles);
|
||||||
void ViewportMapDrawVehicles(DrawPixelInfo *dpi, Viewport *vp);
|
void ViewportMapDrawVehicles(DrawPixelInfo *dpi, Viewport *vp);
|
||||||
|
|
||||||
void ShowNewGrfVehicleError(EngineID engine, StringID part1, StringID part2, GRFBugs bug_type, bool critical);
|
void ShowNewGrfVehicleError(EngineID engine, StringID part1, StringID part2, GRFBugs bug_type, bool critical);
|
||||||
|
@@ -272,6 +272,8 @@ static ViewportDrawer _vd;
|
|||||||
|
|
||||||
static std::vector<Viewport *> _viewport_window_cache;
|
static std::vector<Viewport *> _viewport_window_cache;
|
||||||
static std::vector<Rect> _viewport_coverage_rects;
|
static std::vector<Rect> _viewport_coverage_rects;
|
||||||
|
std::vector<Rect> _viewport_vehicle_normal_redraw_rects;
|
||||||
|
std::vector<Rect> _viewport_vehicle_map_redraw_rects;
|
||||||
|
|
||||||
RouteStepsMap _vp_route_steps;
|
RouteStepsMap _vp_route_steps;
|
||||||
RouteStepsMap _vp_route_steps_last_mark_dirty;
|
RouteStepsMap _vp_route_steps_last_mark_dirty;
|
||||||
@@ -347,6 +349,8 @@ static Point MapXYZToViewport(const Viewport *vp, int x, int y, int z)
|
|||||||
static void FillViewportCoverageRect()
|
static void FillViewportCoverageRect()
|
||||||
{
|
{
|
||||||
_viewport_coverage_rects.resize(_viewport_window_cache.size());
|
_viewport_coverage_rects.resize(_viewport_window_cache.size());
|
||||||
|
_viewport_vehicle_normal_redraw_rects.clear();
|
||||||
|
_viewport_vehicle_map_redraw_rects.clear();
|
||||||
|
|
||||||
for (uint i = 0; i < _viewport_window_cache.size(); i++) {
|
for (uint i = 0; i < _viewport_window_cache.size(); i++) {
|
||||||
const Viewport *vp = _viewport_window_cache[i];
|
const Viewport *vp = _viewport_window_cache[i];
|
||||||
@@ -355,6 +359,17 @@ static void FillViewportCoverageRect()
|
|||||||
r.top = vp->virtual_top;
|
r.top = vp->virtual_top;
|
||||||
r.right = vp->virtual_left + vp->virtual_width + (1 << vp->zoom) - 1;
|
r.right = vp->virtual_left + vp->virtual_width + (1 << vp->zoom) - 1;
|
||||||
r.bottom = vp->virtual_top + vp->virtual_height + (1 << vp->zoom) - 1;
|
r.bottom = vp->virtual_top + vp->virtual_height + (1 << vp->zoom) - 1;
|
||||||
|
|
||||||
|
if (vp->zoom >= ZOOM_LVL_DRAW_MAP) {
|
||||||
|
_viewport_vehicle_map_redraw_rects.push_back(r);
|
||||||
|
} else {
|
||||||
|
_viewport_vehicle_normal_redraw_rects.push_back({
|
||||||
|
r.left - (MAX_VEHICLE_PIXEL_X * ZOOM_LVL_BASE),
|
||||||
|
r.top - (MAX_VEHICLE_PIXEL_Y * ZOOM_LVL_BASE),
|
||||||
|
r.right + (MAX_VEHICLE_PIXEL_X * ZOOM_LVL_BASE),
|
||||||
|
r.bottom + (MAX_VEHICLE_PIXEL_Y * ZOOM_LVL_BASE),
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -716,6 +731,8 @@ static void SetViewportPosition(Window *w, int x, int y, bool force_update_overl
|
|||||||
SCOPE_INFO_FMT([&], "DoSetViewportPosition: %d, %d, %d, %d, %d, %d, %s", left, top, width, height, _vp_move_offs.x, _vp_move_offs.y, scope_dumper().WindowInfo(w));
|
SCOPE_INFO_FMT([&], "DoSetViewportPosition: %d, %d, %d, %d, %d, %d, %s", left, top, width, height, _vp_move_offs.x, _vp_move_offs.y, scope_dumper().WindowInfo(w));
|
||||||
DoSetViewportPosition((Window *) w->z_front, left, top, width, height);
|
DoSetViewportPosition((Window *) w->z_front, left, top, width, height);
|
||||||
ClearViewportCache(w->viewport);
|
ClearViewportCache(w->viewport);
|
||||||
|
FillViewportCoverageRect();
|
||||||
|
w->viewport->update_vehicles = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3281,7 +3298,7 @@ void ViewportDoDraw(Viewport *vp, int left, int top, int right, int bottom)
|
|||||||
} else {
|
} else {
|
||||||
/* Classic rendering. */
|
/* Classic rendering. */
|
||||||
ViewportAddLandscape();
|
ViewportAddLandscape();
|
||||||
ViewportAddVehicles(&_vd.dpi);
|
ViewportAddVehicles(&_vd.dpi, vp->update_vehicles);
|
||||||
|
|
||||||
ViewportAddKdtreeSigns(&_vd.dpi, false);
|
ViewportAddKdtreeSigns(&_vd.dpi, false);
|
||||||
|
|
||||||
@@ -3473,7 +3490,6 @@ void UpdateViewportPosition(Window *w)
|
|||||||
|
|
||||||
SetViewportPosition(w, w->viewport->scrollpos_x, w->viewport->scrollpos_y, update_overlay);
|
SetViewportPosition(w, w->viewport->scrollpos_x, w->viewport->scrollpos_y, update_overlay);
|
||||||
}
|
}
|
||||||
FillViewportCoverageRect();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateViewportSizeZoom(Viewport *vp)
|
void UpdateViewportSizeZoom(Viewport *vp)
|
||||||
@@ -3497,6 +3513,7 @@ void UpdateViewportSizeZoom(Viewport *vp)
|
|||||||
vp->land_pixel_cache.clear();
|
vp->land_pixel_cache.clear();
|
||||||
vp->land_pixel_cache.shrink_to_fit();
|
vp->land_pixel_cache.shrink_to_fit();
|
||||||
}
|
}
|
||||||
|
vp->update_vehicles = true;
|
||||||
FillViewportCoverageRect();
|
FillViewportCoverageRect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -60,6 +60,7 @@ struct Viewport {
|
|||||||
uint8 dirty_block_left_margin;
|
uint8 dirty_block_left_margin;
|
||||||
bool is_dirty = false;
|
bool is_dirty = false;
|
||||||
bool is_drawn = false;
|
bool is_drawn = false;
|
||||||
|
bool update_vehicles = false;
|
||||||
ViewPortMapDrawVehiclesCache map_draw_vehicles_cache;
|
ViewPortMapDrawVehiclesCache map_draw_vehicles_cache;
|
||||||
std::vector<byte> land_pixel_cache;
|
std::vector<byte> land_pixel_cache;
|
||||||
|
|
||||||
@@ -75,6 +76,7 @@ struct Viewport {
|
|||||||
this->is_dirty = false;
|
this->is_dirty = false;
|
||||||
}
|
}
|
||||||
this->is_drawn = false;
|
this->is_drawn = false;
|
||||||
|
this->update_vehicles = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Reference in New Issue
Block a user