mirror of https://github.com/OpenTTD/OpenTTD
(svn r27985) -Codechange: Convert VA2 switches into ones with non-overlapping ranges, sort them and resolve them using binary search. Speedup sprite resolving by about 7 percent.
parent
d9d669dcf8
commit
07d841d0ef
|
@ -12,6 +12,7 @@
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "fileio_func.h"
|
#include "fileio_func.h"
|
||||||
|
@ -4687,16 +4688,60 @@ static void NewSpriteGroup(ByteReader *buf)
|
||||||
group->adjusts = MallocT<DeterministicSpriteGroupAdjust>(group->num_adjusts);
|
group->adjusts = MallocT<DeterministicSpriteGroupAdjust>(group->num_adjusts);
|
||||||
MemCpyT(group->adjusts, adjusts.Begin(), group->num_adjusts);
|
MemCpyT(group->adjusts, adjusts.Begin(), group->num_adjusts);
|
||||||
|
|
||||||
group->num_ranges = buf->ReadByte();
|
std::vector<DeterministicSpriteGroupRange> ranges;
|
||||||
if (group->num_ranges > 0) group->ranges = CallocT<DeterministicSpriteGroupRange>(group->num_ranges);
|
ranges.resize(buf->ReadByte());
|
||||||
|
for (uint i = 0; i < ranges.size(); i++) {
|
||||||
for (uint i = 0; i < group->num_ranges; i++) {
|
ranges[i].group = GetGroupFromGroupID(setid, type, buf->ReadWord());
|
||||||
group->ranges[i].group = GetGroupFromGroupID(setid, type, buf->ReadWord());
|
ranges[i].low = buf->ReadVarSize(varsize);
|
||||||
group->ranges[i].low = buf->ReadVarSize(varsize);
|
ranges[i].high = buf->ReadVarSize(varsize);
|
||||||
group->ranges[i].high = buf->ReadVarSize(varsize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
group->default_group = GetGroupFromGroupID(setid, type, buf->ReadWord());
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
/** @file newgrf_spritegroup.cpp Handling of primarily NewGRF action 2. */
|
/** @file newgrf_spritegroup.cpp Handling of primarily NewGRF action 2. */
|
||||||
|
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
|
#include <algorithm>
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "newgrf_spritegroup.h"
|
#include "newgrf_spritegroup.h"
|
||||||
#include "core/pool_func.hpp"
|
#include "core/pool_func.hpp"
|
||||||
|
@ -201,6 +202,11 @@ static U EvalAdjustT(const DeterministicSpriteGroupAdjust *adjust, ScopeResolver
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool RangeHighComparator(const DeterministicSpriteGroupRange& range, uint32 value)
|
||||||
|
{
|
||||||
|
return range.high < value;
|
||||||
|
}
|
||||||
|
|
||||||
const SpriteGroup *DeterministicSpriteGroup::Resolve(ResolverObject &object) const
|
const SpriteGroup *DeterministicSpriteGroup::Resolve(ResolverObject &object) const
|
||||||
{
|
{
|
||||||
uint32 last_value = 0;
|
uint32 last_value = 0;
|
||||||
|
@ -232,7 +238,7 @@ const SpriteGroup *DeterministicSpriteGroup::Resolve(ResolverObject &object) con
|
||||||
if (!available) {
|
if (!available) {
|
||||||
/* Unsupported variable: skip further processing and return either
|
/* Unsupported variable: skip further processing and return either
|
||||||
* the group from the first range or the default group. */
|
* the group from the first range or the default group. */
|
||||||
return SpriteGroup::Resolve(this->num_ranges > 0 ? this->ranges[0].group : this->default_group, object, false);
|
return SpriteGroup::Resolve(this->error_group, object, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (this->size) {
|
switch (this->size) {
|
||||||
|
@ -254,11 +260,19 @@ const SpriteGroup *DeterministicSpriteGroup::Resolve(ResolverObject &object) con
|
||||||
return &nvarzero;
|
return &nvarzero;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this->num_ranges > 4) {
|
||||||
|
DeterministicSpriteGroupRange *lower = std::lower_bound(this->ranges + 0, this->ranges + this->num_ranges, value, RangeHighComparator);
|
||||||
|
if (lower != this->ranges + this->num_ranges && lower->low <= value) {
|
||||||
|
assert(lower->low <= value && value <= lower->high);
|
||||||
|
return SpriteGroup::Resolve(lower->group, object, false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
for (i = 0; i < this->num_ranges; i++) {
|
for (i = 0; i < this->num_ranges; i++) {
|
||||||
if (this->ranges[i].low <= value && value <= this->ranges[i].high) {
|
if (this->ranges[i].low <= value && value <= this->ranges[i].high) {
|
||||||
return SpriteGroup::Resolve(this->ranges[i].group, object, false);
|
return SpriteGroup::Resolve(this->ranges[i].group, object, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return SpriteGroup::Resolve(this->default_group, object, false);
|
return SpriteGroup::Resolve(this->default_group, object, false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -181,6 +181,8 @@ struct DeterministicSpriteGroup : SpriteGroup {
|
||||||
/* Dynamically allocated, this is the sole owner */
|
/* Dynamically allocated, this is the sole owner */
|
||||||
const SpriteGroup *default_group;
|
const SpriteGroup *default_group;
|
||||||
|
|
||||||
|
const SpriteGroup *error_group; // was first range, before sorting ranges
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
const SpriteGroup *Resolve(ResolverObject &object) const;
|
const SpriteGroup *Resolve(ResolverObject &object) const;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue