diff --git a/src/newgrf.cpp b/src/newgrf.cpp --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -12,6 +12,7 @@ #include "stdafx.h" #include +#include #include "debug.h" #include "fileio_func.h" @@ -4687,16 +4688,60 @@ static void NewSpriteGroup(ByteReader *b group->adjusts = MallocT(group->num_adjusts); MemCpyT(group->adjusts, adjusts.Begin(), group->num_adjusts); - group->num_ranges = buf->ReadByte(); - if (group->num_ranges > 0) group->ranges = CallocT(group->num_ranges); - - for (uint i = 0; i < group->num_ranges; i++) { - group->ranges[i].group = GetGroupFromGroupID(setid, type, buf->ReadWord()); - group->ranges[i].low = buf->ReadVarSize(varsize); - group->ranges[i].high = buf->ReadVarSize(varsize); + std::vector ranges; + ranges.resize(buf->ReadByte()); + for (uint i = 0; i < ranges.size(); i++) { + ranges[i].group = GetGroupFromGroupID(setid, type, buf->ReadWord()); + ranges[i].low = buf->ReadVarSize(varsize); + ranges[i].high = buf->ReadVarSize(varsize); } group->default_group = GetGroupFromGroupID(setid, type, buf->ReadWord()); + group->error_group = ranges.size() > 0 ? ranges[0].group : group->default_group; + + /* Sort ranges ascending. When ranges overlap, this may required clamping or splitting them */ + std::vector bounds; + for (uint i = 0; i < ranges.size(); i++) { + bounds.push_back(ranges[i].low); + if (ranges[i].high != UINT32_MAX) bounds.push_back(ranges[i].high + 1); + } + std::sort(bounds.begin(), bounds.end()); + bounds.erase(std::unique(bounds.begin(), bounds.end()), bounds.end()); + + std::vector target; + for (uint j = 0; j < bounds.size(); ++j) { + uint32 v = bounds[j]; + const SpriteGroup *t = NULL; + for (uint i = 0; i < ranges.size(); i++) { + if (ranges[i].low <= v && v <= ranges[i].high) { + t = ranges[i].group; + } + } + target.push_back(t); + } + assert(target.size() == bounds.size()); + + std::vector optimised; + for (uint j = 0; j < bounds.size(); ) { + if (target[j]) { + DeterministicSpriteGroupRange r; + r.group = target[j]; + r.low = bounds[j]; + while (j < bounds.size() && target[j] == r.group) { + j++; + } + r.high = j < bounds.size() ? bounds[j] - 1 : UINT32_MAX; + optimised.push_back(r); + } else { + j++; + } + } + + group->num_ranges = optimised.size(); + if (group->num_ranges > 0) { + group->ranges = MallocT(group->num_ranges); + MemCpyT(group->ranges, &optimised.front(), group->num_ranges); + } break; }