summaryrefslogtreecommitdiff
path: root/src/newgrf.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/newgrf.cpp')
-rw-r--r--src/newgrf.cpp59
1 files changed, 52 insertions, 7 deletions
diff --git a/src/newgrf.cpp b/src/newgrf.cpp
index 704892e5c..41d719591 100644
--- a/src/newgrf.cpp
+++ b/src/newgrf.cpp
@@ -12,6 +12,7 @@
#include "stdafx.h"
#include <stdarg.h>
+#include <algorithm>
#include "debug.h"
#include "fileio_func.h"
@@ -4687,16 +4688,60 @@ static void NewSpriteGroup(ByteReader *buf)
group->adjusts = MallocT<DeterministicSpriteGroupAdjust>(group->num_adjusts);
MemCpyT(group->adjusts, adjusts.Begin(), group->num_adjusts);
- group->num_ranges = buf->ReadByte();
- if (group->num_ranges > 0) group->ranges = CallocT<DeterministicSpriteGroupRange>(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<DeterministicSpriteGroupRange> 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<uint32> 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<const SpriteGroup *> 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<DeterministicSpriteGroupRange> 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<DeterministicSpriteGroupRange>(group->num_ranges);
+ MemCpyT(group->ranges, &optimised.front(), group->num_ranges);
+ }
break;
}