diff options
Diffstat (limited to 'src/newgrf_commons.cpp')
-rw-r--r-- | src/newgrf_commons.cpp | 170 |
1 files changed, 170 insertions, 0 deletions
diff --git a/src/newgrf_commons.cpp b/src/newgrf_commons.cpp index ce4a6807a..d0d1c1c5f 100644 --- a/src/newgrf_commons.cpp +++ b/src/newgrf_commons.cpp @@ -23,6 +23,7 @@ #include "tunnelbridge_map.h" #include "newgrf_object.h" #include "genworld.h" +#include "newgrf_spritegroup.h" /** * Constructor of generic class @@ -435,6 +436,8 @@ uint32 GetNearbyTileInformation(TileIndex tile) return tile_type << 24 | z << 16 | terrain_type << 8 | tileh; } +/* static */ SmallVector<DrawTileSeqStruct, 8> NewGRFSpriteLayout::result_seq; + /** * Clone the building sprites of a spritelayout. * @param source The building sprites to copy. @@ -454,6 +457,26 @@ void NewGRFSpriteLayout::Clone(const DrawTileSeqStruct *source) } /** + * Clone a spritelayout. + * @param source The spritelayout to copy. + */ +void NewGRFSpriteLayout::Clone(const NewGRFSpriteLayout *source) +{ + this->Clone((const DrawTileSprites*)source); + + if (source->registers != NULL) { + size_t count = 1; // 1 for the ground sprite + const DrawTileSeqStruct *element; + foreach_draw_tile_seq(element, source->seq) count++; + + TileLayoutRegisters *regs = MallocT<TileLayoutRegisters>(count); + MemCpyT(regs, source->registers, count); + this->registers = regs; + } +} + + +/** * Allocate a spritelayout for \a num_sprites building sprites. * @param num_sprites Number of building sprites to allocate memory for. (not counting the terminator) */ @@ -465,3 +488,150 @@ void NewGRFSpriteLayout::Allocate(uint num_sprites) sprites[num_sprites].MakeTerminator(); this->seq = sprites; } + +/** + * Allocate memory for register modifiers. + */ +void NewGRFSpriteLayout::AllocateRegisters() +{ + assert(this->seq != NULL); + assert(this->registers == NULL); + + size_t count = 1; // 1 for the ground sprite + const DrawTileSeqStruct *element; + foreach_draw_tile_seq(element, this->seq) count++; + + this->registers = CallocT<TileLayoutRegisters>(count); +} + +/** + * 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 everytime when calling the function. + * That means, you have to use the sprite layout before calling #PrepareLayout() the next time. + * @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 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 NewGRFSpriteLayout::PrepareLayout(uint32 orig_offset, uint32 newgrf_ground_offset, uint32 newgrf_offset, bool separate_ground) const +{ + result_seq.Clear(); + uint32 var10_values = 0; + + /* Create a copy of the spritelayout, so we can modify some values. + * Also include the groundsprite into the sequence for easier processing. */ + DrawTileSeqStruct *result = result_seq.Append(); + result->image = ground; + result->delta_x = 0; + result->delta_y = 0; + result->delta_z = 0x80; + + const DrawTileSeqStruct *dtss; + foreach_draw_tile_seq(dtss, this->seq) { + *result_seq.Append() = *dtss; + } + result_seq.Append()->MakeTerminator(); + + /* 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; + bool ground = true; + foreach_draw_tile_seq(result, result_seq.Begin()) { + TileLayoutFlags flags = TLF_NOTHING; + if (regs != NULL) flags = regs->flags; + + /* Record var10 value for the sprite */ + if (HasBit(result->image.sprite, SPRITE_MODIFIER_CUSTOM_SPRITE) || (flags & TLF_SPRITE_REG_FLAGS)) { + uint8 var10 = (flags & TLF_SPRITE_VAR10) ? regs->sprite_var10 : (ground && separate_ground ? 1 : 0); + SetBit(var10_values, var10); + } + + /* Add default sprite offset, unless there is a custom one */ + if (!(flags & TLF_SPRITE)) { + if (HasBit(result->image.sprite, SPRITE_MODIFIER_CUSTOM_SPRITE)) { + result->image.sprite += ground ? newgrf_ground_offset : newgrf_offset; + } else { + result->image.sprite += orig_offset; + } + } + + /* Record var10 value for the palette */ + if (HasBit(result->image.pal, SPRITE_MODIFIER_CUSTOM_SPRITE) || (flags & TLF_PALETTE_REG_FLAGS)) { + uint8 var10 = (flags & TLF_PALETTE_VAR10) ? regs->palette_var10 : (ground && separate_ground ? 1 : 0); + SetBit(var10_values, var10); + } + + /* Add default palette offset, unless there is a custom one */ + if (!(flags & TLF_PALETTE)) { + if (HasBit(result->image.pal, SPRITE_MODIFIER_CUSTOM_SPRITE)) { + result->image.sprite += ground ? newgrf_ground_offset : newgrf_offset; + } + } + + ground = false; + if (regs != NULL) 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 resolved_var10, uint32 resolved_sprite, bool separate_ground) const +{ + DrawTileSeqStruct *result; + const TileLayoutRegisters *regs = this->registers; + bool ground = true; + foreach_draw_tile_seq(result, result_seq.Begin()) { + TileLayoutFlags flags = TLF_NOTHING; + if (regs != NULL) 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 var10 = (flags & TLF_SPRITE_VAR10) ? regs->sprite_var10 : (ground && separate_ground ? 1 : 0); + if (var10 == resolved_var10) { + /* Apply registers */ + if ((flags & TLF_DODRAW) && GetRegister(regs->dodraw) == 0) { + result->image.sprite = 0; + continue; + } + if (HasBit(result->image.sprite, SPRITE_MODIFIER_CUSTOM_SPRITE)) result->image.sprite += resolved_sprite; + if (flags & TLF_SPRITE) result->image.sprite += (int16)GetRegister(regs->sprite); // mask to 16 bits to avoid trouble + + if (result->IsParentSprite()) { + if (flags & TLF_BB_XY_OFFSET) { + result->delta_x += (int32)GetRegister(regs->delta.parent[0]); + result->delta_y += (int32)GetRegister(regs->delta.parent[1]); + } + if (flags & TLF_BB_Z_OFFSET) result->delta_z += (int32)GetRegister(regs->delta.parent[2]); + } else { + if (flags & TLF_CHILD_X_OFFSET) result->delta_x += (int32)GetRegister(regs->delta.child[0]); + if (flags & TLF_CHILD_Y_OFFSET) result->delta_y += (int32)GetRegister(regs->delta.child[1]); + } + } + } + + /* Is the palette affected by an action-1-2-3 chain? */ + if (HasBit(result->image.pal, SPRITE_MODIFIER_CUSTOM_SPRITE) || (flags & TLF_PALETTE_REG_FLAGS)) { + /* Does the var10 value apply to this sprite? */ + uint8 var10 = (flags & TLF_PALETTE_VAR10) ? regs->palette_var10 : (ground && separate_ground ? 1 : 0); + if (var10 == resolved_var10) { + /* Apply registers */ + if (HasBit(result->image.pal, SPRITE_MODIFIER_CUSTOM_SPRITE)) result->image.pal += resolved_sprite; + if (flags & TLF_PALETTE) result->image.pal += (int16)GetRegister(regs->palette); // mask to 16 bits to avoid trouble + } + } + + ground = false; + if (regs != NULL) regs++; + } +} |