From 55a503e6f225a3c1dba3dbc1effa7e0d6942dd96 Mon Sep 17 00:00:00 2001 From: frosch Date: Sun, 11 Mar 2018 15:08:51 +0000 Subject: (svn r27989) -Fix (r27985): VA2 optimisation failed in various special cases: - nvar=0 is meant to return the calculated result. - Missing references resolve to NULL and got identified with the default result. - Missing 'break' broke overlapping cases. - Splitting into non-overlapping cases could result in more than 256 cases. --- src/newgrf.cpp | 7 +++++-- src/newgrf_spritegroup.cpp | 2 +- src/newgrf_spritegroup.h | 3 ++- 3 files changed, 8 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 41d719591..d06d1c40a 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -4698,6 +4698,8 @@ static void NewSpriteGroup(ByteReader *buf) group->default_group = GetGroupFromGroupID(setid, type, buf->ReadWord()); group->error_group = ranges.size() > 0 ? ranges[0].group : group->default_group; + /* nvar == 0 is a special case -- we turn our value into a callback result */ + group->calculated_result = ranges.size() == 0; /* Sort ranges ascending. When ranges overlap, this may required clamping or splitting them */ std::vector bounds; @@ -4711,10 +4713,11 @@ static void NewSpriteGroup(ByteReader *buf) std::vector target; for (uint j = 0; j < bounds.size(); ++j) { uint32 v = bounds[j]; - const SpriteGroup *t = NULL; + const SpriteGroup *t = group->default_group; for (uint i = 0; i < ranges.size(); i++) { if (ranges[i].low <= v && v <= ranges[i].high) { t = ranges[i].group; + break; } } target.push_back(t); @@ -4723,7 +4726,7 @@ static void NewSpriteGroup(ByteReader *buf) std::vector optimised; for (uint j = 0; j < bounds.size(); ) { - if (target[j]) { + if (target[j] != group->default_group) { DeterministicSpriteGroupRange r; r.group = target[j]; r.low = bounds[j]; diff --git a/src/newgrf_spritegroup.cpp b/src/newgrf_spritegroup.cpp index 8f44ef9c5..a5d689bbf 100644 --- a/src/newgrf_spritegroup.cpp +++ b/src/newgrf_spritegroup.cpp @@ -252,7 +252,7 @@ const SpriteGroup *DeterministicSpriteGroup::Resolve(ResolverObject &object) con object.last_value = last_value; - if (this->num_ranges == 0) { + if (this->calculated_result) { /* nvar == 0 is a special case -- we turn our value into a callback result */ if (value != CALLBACK_FAILED) value = GB(value, 0, 15); static CallbackResultSpriteGroup nvarzero(0, true); diff --git a/src/newgrf_spritegroup.h b/src/newgrf_spritegroup.h index b2e764599..6adf7c2ac 100644 --- a/src/newgrf_spritegroup.h +++ b/src/newgrf_spritegroup.h @@ -174,7 +174,8 @@ struct DeterministicSpriteGroup : SpriteGroup { VarSpriteGroupScope var_scope; DeterministicSpriteGroupSize size; uint num_adjusts; - byte num_ranges; + uint num_ranges; + bool calculated_result; DeterministicSpriteGroupAdjust *adjusts; DeterministicSpriteGroupRange *ranges; // Dynamically allocated -- cgit v1.2.3-54-g00ecf