mirror of https://github.com/OpenTTD/OpenTTD
Codechange: Move spritelayout preprocessing to a separate class, which owns the heap allocations involved.
parent
d9c43e7fda
commit
8bbfbd0347
|
@ -243,7 +243,8 @@ uint16_t GetAirportTileCallback(CallbackID callback, uint32_t param1, uint32_t p
|
|||
|
||||
static void AirportDrawTileLayout(const TileInfo *ti, const TileLayoutSpriteGroup *group, Colours colour)
|
||||
{
|
||||
auto dts = group->ProcessRegisters(nullptr);
|
||||
auto processor = group->ProcessRegisters(nullptr);
|
||||
auto dts = processor.GetLayout();
|
||||
|
||||
SpriteID image = dts.ground.sprite;
|
||||
SpriteID pal = dts.ground.pal;
|
||||
|
|
|
@ -562,10 +562,6 @@ bool Convert8bitBooleanCallback(const GRFFile *grffile, uint16_t cbid, uint16_t
|
|||
return cb_res != 0;
|
||||
}
|
||||
|
||||
|
||||
/* static */ std::vector<DrawTileSeqStruct> NewGRFSpriteLayout::result_seq;
|
||||
|
||||
|
||||
/**
|
||||
* Allocate a spritelayout for \a num_sprites building sprites.
|
||||
* @param num_sprites Number of building sprites to allocate memory for. (not counting the terminator)
|
||||
|
@ -590,41 +586,38 @@ void NewGRFSpriteLayout::AllocateRegisters()
|
|||
/**
|
||||
* Prepares a sprite layout before resolving action-1-2-3 chains.
|
||||
* Integrates offsets into the layout and determines which chains to resolve.
|
||||
* @note The function uses statically allocated temporary storage, which is reused every time when calling the function.
|
||||
* That means, you have to use the sprite layout before calling #PrepareLayout() the next time.
|
||||
* @param raw_layout Sprite layout in need of preprocessing.
|
||||
* @param orig_offset Offset to apply to non-action-1 sprites.
|
||||
* @param newgrf_ground_offset Offset to apply to action-1 ground sprites.
|
||||
* @param newgrf_offset Offset to apply to action-1 non-ground sprites.
|
||||
* @param constr_stage Construction stage (0-3) to apply to all action-1 sprites.
|
||||
* @param separate_ground Whether the ground sprite shall be resolved by a separate action-1-2-3 chain by default.
|
||||
* @return Bitmask of values for variable 10 to resolve action-1-2-3 chains for.
|
||||
*/
|
||||
uint32_t NewGRFSpriteLayout::PrepareLayout(uint32_t orig_offset, uint32_t newgrf_ground_offset, uint32_t newgrf_offset, uint constr_stage, bool separate_ground) const
|
||||
SpriteLayoutProcessor::SpriteLayoutProcessor(const NewGRFSpriteLayout &raw_layout, uint32_t orig_offset, uint32_t newgrf_ground_offset, uint32_t newgrf_offset, uint constr_stage, bool separate_ground) :
|
||||
raw_layout(&raw_layout), separate_ground(separate_ground)
|
||||
{
|
||||
result_seq.clear();
|
||||
uint32_t var10_values = 0;
|
||||
this->result_seq.reserve(this->raw_layout->seq.size() + 1);
|
||||
|
||||
/* Create a copy of the spritelayout, so we can modify some values.
|
||||
* Also include the groundsprite into the sequence for easier processing. */
|
||||
DrawTileSeqStruct © = result_seq.emplace_back();
|
||||
copy.image = ground;
|
||||
DrawTileSeqStruct © = this->result_seq.emplace_back();
|
||||
copy.image = this->raw_layout->ground;
|
||||
copy.delta_z = static_cast<int8_t>(0x80);
|
||||
|
||||
for (const DrawTileSeqStruct &dtss : this->seq) {
|
||||
result_seq.emplace_back(dtss);
|
||||
}
|
||||
this->result_seq.insert(this->result_seq.end(), this->raw_layout->seq.begin(), this->raw_layout->seq.end());
|
||||
|
||||
/* Determine the var10 values the action-1-2-3 chains needs to be resolved for,
|
||||
* and apply the default sprite offsets (unless disabled). */
|
||||
const TileLayoutRegisters *regs = this->registers.empty() ? nullptr : this->registers.data();
|
||||
const TileLayoutRegisters *regs = this->raw_layout->registers.empty() ? nullptr : this->raw_layout->registers.data();
|
||||
bool ground = true;
|
||||
for (DrawTileSeqStruct &result : result_seq) {
|
||||
for (DrawTileSeqStruct &result : this->result_seq) {
|
||||
TileLayoutFlags flags = TLF_NOTHING;
|
||||
if (regs != nullptr) flags = regs->flags;
|
||||
|
||||
/* Record var10 value for the sprite */
|
||||
if (HasBit(result.image.sprite, SPRITE_MODIFIER_CUSTOM_SPRITE) || (flags & TLF_SPRITE_REG_FLAGS)) {
|
||||
uint8_t var10 = (flags & TLF_SPRITE_VAR10) ? regs->sprite_var10 : (ground && separate_ground ? 1 : 0);
|
||||
SetBit(var10_values, var10);
|
||||
uint8_t var10 = (flags & TLF_SPRITE_VAR10) ? regs->sprite_var10 : (ground && this->separate_ground ? 1 : 0);
|
||||
SetBit(this->var10_values, var10);
|
||||
}
|
||||
|
||||
/* Add default sprite offset, unless there is a custom one */
|
||||
|
@ -639,8 +632,8 @@ uint32_t NewGRFSpriteLayout::PrepareLayout(uint32_t orig_offset, uint32_t newgrf
|
|||
|
||||
/* Record var10 value for the palette */
|
||||
if (HasBit(result.image.pal, SPRITE_MODIFIER_CUSTOM_SPRITE) || (flags & TLF_PALETTE_REG_FLAGS)) {
|
||||
uint8_t var10 = (flags & TLF_PALETTE_VAR10) ? regs->palette_var10 : (ground && separate_ground ? 1 : 0);
|
||||
SetBit(var10_values, var10);
|
||||
uint8_t var10 = (flags & TLF_PALETTE_VAR10) ? regs->palette_var10 : (ground && this->separate_ground ? 1 : 0);
|
||||
SetBit(this->var10_values, var10);
|
||||
}
|
||||
|
||||
/* Add default palette offset, unless there is a custom one */
|
||||
|
@ -654,30 +647,26 @@ uint32_t NewGRFSpriteLayout::PrepareLayout(uint32_t orig_offset, uint32_t newgrf
|
|||
ground = false;
|
||||
if (regs != nullptr) regs++;
|
||||
}
|
||||
|
||||
return var10_values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates the register modifiers and integrates them into the preprocessed sprite layout.
|
||||
* @pre #PrepareLayout() needs calling first.
|
||||
* @param resolved_var10 The value of var10 the action-1-2-3 chain was evaluated for.
|
||||
* @param resolved_sprite Result sprite of the action-1-2-3 chain.
|
||||
* @param separate_ground Whether the ground sprite is resolved by a separate action-1-2-3 chain.
|
||||
* @return Resulting spritelayout after processing the registers.
|
||||
*/
|
||||
void NewGRFSpriteLayout::ProcessRegisters(uint8_t resolved_var10, uint32_t resolved_sprite, bool separate_ground) const
|
||||
void SpriteLayoutProcessor::ProcessRegisters(uint8_t resolved_var10, uint32_t resolved_sprite)
|
||||
{
|
||||
const TileLayoutRegisters *regs = this->registers.empty() ? nullptr : this->registers.data();
|
||||
assert(this->raw_layout != nullptr);
|
||||
const TileLayoutRegisters *regs = this->raw_layout->registers.empty() ? nullptr : this->raw_layout->registers.data();
|
||||
bool ground = true;
|
||||
for (DrawTileSeqStruct &result : result_seq) {
|
||||
for (DrawTileSeqStruct &result : this->result_seq) {
|
||||
TileLayoutFlags flags = TLF_NOTHING;
|
||||
if (regs != nullptr) flags = regs->flags;
|
||||
|
||||
/* Is the sprite or bounding box affected by an action-1-2-3 chain? */
|
||||
if (HasBit(result.image.sprite, SPRITE_MODIFIER_CUSTOM_SPRITE) || (flags & TLF_SPRITE_REG_FLAGS)) {
|
||||
/* Does the var10 value apply to this sprite? */
|
||||
uint8_t var10 = (flags & TLF_SPRITE_VAR10) ? regs->sprite_var10 : (ground && separate_ground ? 1 : 0);
|
||||
uint8_t var10 = (flags & TLF_SPRITE_VAR10) ? regs->sprite_var10 : (ground && this->separate_ground ? 1 : 0);
|
||||
if (var10 == resolved_var10) {
|
||||
/* Apply registers */
|
||||
if ((flags & TLF_DODRAW) && GetRegister(regs->dodraw) == 0) {
|
||||
|
@ -710,7 +699,7 @@ void NewGRFSpriteLayout::ProcessRegisters(uint8_t resolved_var10, uint32_t resol
|
|||
/* Is the palette affected by an action-1-2-3 chain? */
|
||||
if (result.image.sprite != 0 && (HasBit(result.image.pal, SPRITE_MODIFIER_CUSTOM_SPRITE) || (flags & TLF_PALETTE_REG_FLAGS))) {
|
||||
/* Does the var10 value apply to this sprite? */
|
||||
uint8_t var10 = (flags & TLF_PALETTE_VAR10) ? regs->palette_var10 : (ground && separate_ground ? 1 : 0);
|
||||
uint8_t var10 = (flags & TLF_PALETTE_VAR10) ? regs->palette_var10 : (ground && this->separate_ground ? 1 : 0);
|
||||
if (var10 == resolved_var10) {
|
||||
/* Apply registers */
|
||||
if (HasBit(result.image.pal, SPRITE_MODIFIER_CUSTOM_SPRITE)) result.image.pal += resolved_sprite;
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "direction_type.h"
|
||||
#include "company_type.h"
|
||||
#include "cargo_type.h"
|
||||
#include "core/bitmath_func.hpp"
|
||||
|
||||
/** Context for tile accesses */
|
||||
enum TileContext : uint8_t {
|
||||
|
@ -124,9 +125,8 @@ struct NewGRFSpriteLayout : DrawTileSprites {
|
|||
void AllocateRegisters();
|
||||
|
||||
/**
|
||||
* Tests whether this spritelayout needs preprocessing by
|
||||
* #PrepareLayout() and #ProcessRegisters(), or whether it can be
|
||||
* used directly.
|
||||
* Tests whether this spritelayout needs preprocessing by SpriteLayoutProcessor,
|
||||
* or whether it can be used directly.
|
||||
* @return true if preprocessing is needed
|
||||
*/
|
||||
bool NeedsPreprocessing() const
|
||||
|
@ -134,24 +134,48 @@ struct NewGRFSpriteLayout : DrawTileSprites {
|
|||
return !this->registers.empty();
|
||||
}
|
||||
|
||||
uint32_t PrepareLayout(uint32_t orig_offset, uint32_t newgrf_ground_offset, uint32_t newgrf_offset, uint constr_stage, bool separate_ground) const;
|
||||
void ProcessRegisters(uint8_t resolved_var10, uint32_t resolved_sprite, bool separate_ground) const;
|
||||
std::span<const DrawTileSeqStruct> GetSequence() const override { return {this->seq.begin(), this->seq.end()}; }
|
||||
};
|
||||
|
||||
/**
|
||||
* Add dynamic register values to a sprite layout.
|
||||
*/
|
||||
class SpriteLayoutProcessor {
|
||||
const NewGRFSpriteLayout *raw_layout = nullptr;
|
||||
std::vector<DrawTileSeqStruct> result_seq;
|
||||
uint32_t var10_values = 0;
|
||||
bool separate_ground = false;
|
||||
public:
|
||||
SpriteLayoutProcessor() = default;
|
||||
|
||||
/** Constructor for spritelayout, which do not need preprocessing. */
|
||||
SpriteLayoutProcessor(const NewGRFSpriteLayout &raw_layout) : raw_layout(&raw_layout) {}
|
||||
|
||||
SpriteLayoutProcessor(const NewGRFSpriteLayout &raw_layout, uint32_t orig_offset, uint32_t newgrf_ground_offset, uint32_t newgrf_offset, uint constr_stage, bool separate_ground);
|
||||
|
||||
/**
|
||||
* Get values for variable 10 to resolve sprites for.
|
||||
* NewStations only.
|
||||
*/
|
||||
SetBitIterator<uint8_t, uint32_t> Var10Values() const { return this->var10_values; }
|
||||
|
||||
void ProcessRegisters(uint8_t resolved_var10, uint32_t resolved_sprite);
|
||||
|
||||
/**
|
||||
* Returns the result spritelayout after preprocessing.
|
||||
* @pre #PrepareLayout() and #ProcessRegisters() need calling first.
|
||||
* @return result spritelayout
|
||||
* @return result ground sprite and spritelayout
|
||||
*/
|
||||
DrawTileSpriteSpan GetLayout() const
|
||||
{
|
||||
return {result_seq[0].image, {++result_seq.begin(), result_seq.end()}};
|
||||
assert(this->raw_layout != nullptr);
|
||||
if (this->result_seq.empty()) {
|
||||
/* Simple layout without preprocessing. */
|
||||
return {this->raw_layout->ground, this->raw_layout->seq};
|
||||
} else {
|
||||
/* Dynamic layout with preprocessing. */
|
||||
return {this->result_seq[0].image, {++this->result_seq.begin(), this->result_seq.end()}};
|
||||
}
|
||||
}
|
||||
|
||||
std::span<const DrawTileSeqStruct> GetSequence() const override { return {this->seq.begin(), this->seq.end()}; }
|
||||
|
||||
|
||||
private:
|
||||
static std::vector<DrawTileSeqStruct> result_seq; ///< Temporary storage when preprocessing spritelayouts.
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -463,7 +463,8 @@ uint16_t GetHouseCallback(CallbackID callback, uint32_t param1, uint32_t param2,
|
|||
|
||||
static void DrawTileLayout(const TileInfo *ti, const TileLayoutSpriteGroup *group, uint8_t stage, HouseID house_id)
|
||||
{
|
||||
auto dts = group->ProcessRegisters(&stage);
|
||||
auto processor = group->ProcessRegisters(&stage);
|
||||
auto dts = processor.GetLayout();
|
||||
|
||||
const HouseSpec *hs = HouseSpec::Get(house_id);
|
||||
PaletteID palette = GetColourPalette(hs->random_colour[TileHash2Bit(ti->x, ti->y)]);
|
||||
|
@ -528,7 +529,8 @@ void DrawNewHouseTileInGUI(int x, int y, const HouseSpec *spec, HouseID house_id
|
|||
if (group == nullptr) return;
|
||||
|
||||
uint8_t stage = TOWN_HOUSE_COMPLETED;
|
||||
auto dts = group->ProcessRegisters(&stage);
|
||||
auto processor = group->ProcessRegisters(&stage);
|
||||
auto dts = processor.GetLayout();
|
||||
|
||||
PaletteID palette = GetColourPalette(spec->random_colour[0]);
|
||||
if (spec->callback_mask.Test(HouseCallbackMask::Colour)) {
|
||||
|
|
|
@ -160,7 +160,8 @@ uint32_t IndustryTileResolverObject::GetDebugID() const
|
|||
|
||||
static void IndustryDrawTileLayout(const TileInfo *ti, const TileLayoutSpriteGroup *group, Colours rnd_colour, uint8_t stage)
|
||||
{
|
||||
auto dts = group->ProcessRegisters(&stage);
|
||||
auto processor = group->ProcessRegisters(&stage);
|
||||
auto dts = processor.GetLayout();
|
||||
|
||||
SpriteID image = dts.ground.sprite;
|
||||
PaletteID pal = dts.ground.pal;
|
||||
|
|
|
@ -444,7 +444,8 @@ uint16_t GetObjectCallback(CallbackID callback, uint32_t param1, uint32_t param2
|
|||
*/
|
||||
static void DrawTileLayout(const TileInfo *ti, const TileLayoutSpriteGroup *group, const ObjectSpec *spec)
|
||||
{
|
||||
auto dts = group->ProcessRegisters(nullptr);
|
||||
auto processor = group->ProcessRegisters(nullptr);
|
||||
auto dts = processor.GetLayout();
|
||||
PaletteID palette = (spec->flags.Test(ObjectFlag::Uses2CC) ? SPR_2CCMAP_BASE : PALETTE_RECOLOUR_START) + Object::GetByTile(ti->tile)->colour;
|
||||
|
||||
SpriteID image = dts.ground.sprite;
|
||||
|
@ -492,7 +493,8 @@ void DrawNewObjectTileInGUI(int x, int y, const ObjectSpec *spec, uint8_t view)
|
|||
const auto *group = object.Resolve<TileLayoutSpriteGroup>();
|
||||
if (group == nullptr) return;
|
||||
|
||||
auto dts = group->ProcessRegisters(nullptr);
|
||||
auto processor = group->ProcessRegisters(nullptr);
|
||||
auto dts = processor.GetLayout();
|
||||
|
||||
PaletteID palette;
|
||||
if (Company::IsValidID(_local_company)) {
|
||||
|
|
|
@ -293,7 +293,8 @@ void DrawRoadStopTile(int x, int y, RoadType roadtype, const RoadStopSpec *spec,
|
|||
RoadStopResolverObject object(spec, nullptr, INVALID_TILE, roadtype, type, view);
|
||||
const auto *group = object.Resolve<TileLayoutSpriteGroup>();
|
||||
if (group == nullptr) return;
|
||||
auto dts = group->ProcessRegisters(nullptr);
|
||||
auto processor = group->ProcessRegisters(nullptr);
|
||||
auto dts = processor.GetLayout();
|
||||
|
||||
PaletteID palette = GetCompanyPalette(_local_company);
|
||||
|
||||
|
|
|
@ -287,19 +287,19 @@ static bool RangeHighComparator(const DeterministicSpriteGroupRange &range, uint
|
|||
* @param[in,out] stage Construction stage (0-3), or nullptr if not applicable.
|
||||
* @return sprite layout to draw.
|
||||
*/
|
||||
DrawTileSpriteSpan TileLayoutSpriteGroup::ProcessRegisters(uint8_t *stage) const
|
||||
SpriteLayoutProcessor TileLayoutSpriteGroup::ProcessRegisters(uint8_t *stage) const
|
||||
{
|
||||
if (!this->dts.NeedsPreprocessing()) {
|
||||
if (stage != nullptr && this->dts.consistent_max_offset > 0) *stage = GetConstructionStageOffset(*stage, this->dts.consistent_max_offset);
|
||||
return {this->dts.ground, this->dts.seq};
|
||||
return SpriteLayoutProcessor(this->dts);
|
||||
}
|
||||
|
||||
uint8_t actual_stage = stage != nullptr ? *stage : 0;
|
||||
this->dts.PrepareLayout(0, 0, 0, actual_stage, false);
|
||||
this->dts.ProcessRegisters(0, 0, false);
|
||||
SpriteLayoutProcessor result(this->dts, 0, 0, 0, actual_stage, false);
|
||||
result.ProcessRegisters(0, 0);
|
||||
|
||||
/* Stage has been processed by PrepareLayout(), set it to zero. */
|
||||
if (stage != nullptr) *stage = 0;
|
||||
|
||||
return this->dts.GetLayout();
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -260,7 +260,7 @@ struct TileLayoutSpriteGroup : SpriteGroup {
|
|||
|
||||
NewGRFSpriteLayout dts{};
|
||||
|
||||
DrawTileSpriteSpan ProcessRegisters(uint8_t *stage) const;
|
||||
SpriteLayoutProcessor ProcessRegisters(uint8_t *stage) const;
|
||||
};
|
||||
|
||||
struct IndustryProductionSpriteGroup : SpriteGroup {
|
||||
|
|
|
@ -803,6 +803,7 @@ bool DrawStationTile(int x, int y, RailType railtype, Axis axis, StationClassID
|
|||
uint32_t relocation = 0;
|
||||
uint32_t ground_relocation = 0;
|
||||
const NewGRFSpriteLayout *layout = nullptr;
|
||||
SpriteLayoutProcessor processor; // owns heap, borrowed by tmp_rail_layout and sprites
|
||||
DrawTileSpriteSpan tmp_rail_layout;
|
||||
|
||||
if (statspec->renderdata.empty()) {
|
||||
|
@ -818,13 +819,12 @@ bool DrawStationTile(int x, int y, RailType railtype, Axis axis, StationClassID
|
|||
if (layout != nullptr) {
|
||||
/* Sprite layout which needs preprocessing */
|
||||
bool separate_ground = statspec->flags.Test(StationSpecFlag::SeparateGround);
|
||||
uint32_t var10_values = layout->PrepareLayout(total_offset, rti->fallback_railtype, 0, 0, separate_ground);
|
||||
for (uint8_t var10 : SetBitIterator(var10_values)) {
|
||||
processor = SpriteLayoutProcessor(*layout, total_offset, rti->fallback_railtype, 0, 0, separate_ground);
|
||||
for (uint8_t var10 : processor.Var10Values()) {
|
||||
uint32_t var10_relocation = GetCustomStationRelocation(statspec, nullptr, INVALID_TILE, var10);
|
||||
layout->ProcessRegisters(var10, var10_relocation, separate_ground);
|
||||
processor.ProcessRegisters(var10, var10_relocation);
|
||||
}
|
||||
|
||||
tmp_rail_layout = layout->GetLayout();
|
||||
tmp_rail_layout = processor.GetLayout();
|
||||
sprites = &tmp_rail_layout;
|
||||
total_offset = 0;
|
||||
} else {
|
||||
|
|
|
@ -3076,6 +3076,7 @@ bool SplitGroundSpriteForOverlay(const TileInfo *ti, SpriteID *ground, RailTrack
|
|||
static void DrawTile_Station(TileInfo *ti)
|
||||
{
|
||||
const NewGRFSpriteLayout *layout = nullptr;
|
||||
SpriteLayoutProcessor processor; // owns heap, borrowed by tmp_layout and t
|
||||
DrawTileSpriteSpan tmp_layout;
|
||||
const DrawTileSprites *t = nullptr;
|
||||
int32_t total_offset;
|
||||
|
@ -3268,12 +3269,12 @@ draw_default_foundation:
|
|||
if (layout != nullptr) {
|
||||
/* Sprite layout which needs preprocessing */
|
||||
bool separate_ground = statspec->flags.Test(StationSpecFlag::SeparateGround);
|
||||
uint32_t var10_values = layout->PrepareLayout(total_offset, rti->fallback_railtype, 0, 0, separate_ground);
|
||||
for (uint8_t var10 : SetBitIterator(var10_values)) {
|
||||
processor = SpriteLayoutProcessor(*layout, total_offset, rti->fallback_railtype, 0, 0, separate_ground);
|
||||
for (uint8_t var10 : processor.Var10Values()) {
|
||||
uint32_t var10_relocation = GetCustomStationRelocation(statspec, st, ti->tile, var10);
|
||||
layout->ProcessRegisters(var10, var10_relocation, separate_ground);
|
||||
processor.ProcessRegisters(var10, var10_relocation);
|
||||
}
|
||||
tmp_layout = layout->GetLayout();
|
||||
tmp_layout = processor.GetLayout();
|
||||
t = &tmp_layout;
|
||||
total_offset = 0;
|
||||
} else if (statspec != nullptr) {
|
||||
|
@ -3337,7 +3338,8 @@ draw_default_foundation:
|
|||
if (type == StationType::RoadWaypoint && stop_draw_mode.Test(RoadStopDrawMode::WaypGround)) {
|
||||
draw_ground = true;
|
||||
}
|
||||
tmp_layout = group->ProcessRegisters(nullptr);
|
||||
processor = group->ProcessRegisters(nullptr);
|
||||
tmp_layout = processor.GetLayout();
|
||||
t = &tmp_layout;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue