Fix sprite bound issues for vehicles which vary bounds with curvature

If a vehicle uses curvature vars 0x45 or 0x62, cache the directions
of its 4 nearest neighbours, and check them in UpdateViewport along
with the vehicle's own direction.
pull/212/head
Jonathan G Rennison 3 years ago
parent bf313338c0
commit 204f8e173f

@ -11,5 +11,6 @@
#define NEWGRF_CACHE_CHECK_H
extern bool _sprite_group_resolve_check_veh_check;
extern bool _sprite_group_resolve_check_veh_curvature_check;
#endif /* NEWGRF_CACHE_CHECK_H */

@ -28,6 +28,7 @@
#include "safeguards.h"
bool _sprite_group_resolve_check_veh_check = false;
bool _sprite_group_resolve_check_veh_curvature_check = false;
struct WagonOverride {
EngineID *train_id;
@ -692,6 +693,8 @@ static uint32 VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *object,
*/
if (!v->IsGroundVehicle()) return 0;
_sprite_group_resolve_check_veh_curvature_check = false;
const Vehicle *u_p = v->Previous();
const Vehicle *u_n = v->Next();
DirDiff f = (u_p == nullptr) ? DIRDIFF_SAME : DirDifference(u_p->direction, v->direction);
@ -812,6 +815,8 @@ static uint32 VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *object,
const Vehicle *u = v->Move((int8)parameter);
if (u == nullptr) return 0;
_sprite_group_resolve_check_veh_curvature_check = false;
/* Get direction difference. */
bool prev = (int8)parameter < 0;
uint32 ret = prev ? DirDifference(u->direction, v->direction) : DirDifference(v->direction, u->direction);

@ -3811,6 +3811,7 @@ char *Vehicle::DumpVehicleFlags(char *b, const char *last, bool include_tile) co
dump('s', HasBit(this->vcache.cached_veh_flags, VCF_REDRAW_ON_SPEED_CHANGE));
dump('R', HasBit(this->vcache.cached_veh_flags, VCF_IMAGE_REFRESH));
dump('N', HasBit(this->vcache.cached_veh_flags, VCF_IMAGE_REFRESH_NEXT));
dump('c', HasBit(this->vcache.cached_veh_flags, VCF_IMAGE_CURVATURE));
if (this->IsGroundVehicle()) {
uint16 gv_flags = this->GetGroundVehicleFlags();
b += seprintf(b, last, ", gvf:");

@ -142,12 +142,14 @@ enum VehicleCacheFlags {
VCF_REDRAW_ON_SPEED_CHANGE = 4, ///< Clear cur_image_valid_dir on changes to cur_speed (ground vehicles) or aircraft movement state (aircraft) (valid only for the first engine)
VCF_IMAGE_REFRESH = 5, ///< Image should be refreshed before drawing
VCF_IMAGE_REFRESH_NEXT = 6, ///< Set VCF_IMAGE_REFRESH in next UpdateViewport call, if the image is not updated there
VCF_IMAGE_CURVATURE = 7, ///< Image should be refreshed if cached curvature in cached_image_curvature no longer matches curvature of neighbours
};
/** Cached often queried values common to all vehicles. */
struct VehicleCache {
uint16 cached_max_speed; ///< Maximum speed of the consist (minimum of the max speed of all vehicles in the consist).
uint16 cached_cargo_age_period; ///< Number of ticks before carried cargo is aged.
uint16 cached_image_curvature; ///< Cached neighbour curvature, see: VCF_IMAGE_CURVATURE
byte cached_vis_effect; ///< Visual effect to show (see #VisualEffect)
byte cached_veh_flags; ///< Vehicle cache flags (see #VehicleCacheFlags)
@ -524,6 +526,7 @@ public:
{
ClrBit(this->vcache.cached_veh_flags, VCF_REDRAW_ON_SPEED_CHANGE);
ClrBit(this->vcache.cached_veh_flags, VCF_REDRAW_ON_TRIGGER);
ClrBit(this->vcache.cached_veh_flags, VCF_IMAGE_CURVATURE);
for (Vehicle *u = this; u != nullptr; u = u->Next()) {
u->InvalidateImageCache();
}
@ -1274,17 +1277,42 @@ struct SpecializedVehicle : public Vehicle {
/* Skip updating sprites on dedicated servers without screen */
if (_network_dedicated) return;
auto get_vehicle_curvature = [&]() -> uint16 {
uint16 curvature = 0;
if (this->Previous() != nullptr) {
SB(curvature, 0, 4, this->Previous()->direction);
if (this->Previous()->Previous() != nullptr) SB(curvature, 4, 4, this->Previous()->Previous()->direction);
}
if (this->Next() != nullptr) {
SB(curvature, 8, 4, this->Next()->direction);
if (this->Next()->Next() != nullptr) SB(curvature, 12, 4, this->Next()->Next()->direction);
}
return curvature;
};
auto check_vehicle_curvature = [&]() -> bool {
if (!(EXPECTED_TYPE == VEH_TRAIN || EXPECTED_TYPE == VEH_ROAD)) return false;
if (likely(!HasBit(this->vcache.cached_veh_flags, VCF_IMAGE_CURVATURE))) return false;
return this->vcache.cached_image_curvature != get_vehicle_curvature();
};
/* 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();
const Direction current_direction = ((T *)this)->GetMapImageDirection();
if (this->cur_image_valid_dir != current_direction) {
if (this->cur_image_valid_dir != current_direction || check_vehicle_curvature()) {
_sprite_group_resolve_check_veh_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);
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 || _settings_client.gui.disable_vehicle_image_update) ? 0 : 1);
if (unlikely(!_sprite_group_resolve_check_veh_curvature_check)) {
SetBit(this->vcache.cached_veh_flags, VCF_IMAGE_CURVATURE);
this->vcache.cached_image_curvature = get_vehicle_curvature();
}
_sprite_group_resolve_check_veh_curvature_check = false;
this->cur_image_valid_dir = current_direction;
} else {
this->cur_image_valid_dir = (_sprite_group_resolve_check_veh_check || _settings_client.gui.disable_vehicle_image_update) ? current_direction : INVALID_DIR;

Loading…
Cancel
Save