Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change: Display more useful information in sprite aligner than sprite ID. #12439

Merged
merged 1 commit into from
Apr 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ add_files(
music_gui.cpp
newgrf.cpp
newgrf.h
newgrf_act5.h
newgrf_airport.cpp
newgrf_airport.h
newgrf_airporttiles.cpp
Expand Down
6 changes: 5 additions & 1 deletion src/lang/english.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3488,7 +3488,9 @@ STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_ROAD_TYPE :Road type
STR_NEWGRF_INSPECT_QUERY_CAPTION :{WHITE}NewGRF variable 60+x parameter (hexadecimal)

# Sprite aligner window
STR_SPRITE_ALIGNER_CAPTION :{WHITE}Aligning sprite {COMMA} ({RAW_STRING})
STR_SPRITE_ALIGNER_CAPTION_NO_ACTION :{WHITE}Aligning sprite: ({RAW_STRING}:{NUM})
STR_SPRITE_ALIGNER_CAPTION_ACTIONA :{WHITE}Aligning sprite: Action 0xA, {COMMA} ({RAW_STRING}:{NUM})
STR_SPRITE_ALIGNER_CAPTION_ACTION5 :{WHITE}Aligning sprite: Action 0x5, type {HEX}, {COMMA} ({RAW_STRING}:{NUM})
STR_SPRITE_ALIGNER_NEXT_BUTTON :{BLACK}Next sprite
STR_SPRITE_ALIGNER_NEXT_TOOLTIP :{BLACK}Proceed to the next normal sprite, skipping any pseudo/recolour/font sprites and wrapping around from the last sprite to the first
STR_SPRITE_ALIGNER_GOTO_BUTTON :{BLACK}Go to sprite
Expand All @@ -3497,6 +3499,7 @@ STR_SPRITE_ALIGNER_PREVIOUS_BUTTON :{BLACK}Previous
STR_SPRITE_ALIGNER_PREVIOUS_TOOLTIP :{BLACK}Proceed to the previous normal sprite, skipping any pseudo/recolour/font sprites and wrapping around from the first sprite to the last
STR_SPRITE_ALIGNER_SPRITE_TOOLTIP :{BLACK}Representation of the currently selected sprite. The alignment is ignored when drawing this sprite
STR_SPRITE_ALIGNER_MOVE_TOOLTIP :{BLACK}Move the sprite around, changing the X and Y offsets. Ctrl+Click to move the sprite eight units at a time
STR_SPRITE_ALIGNER_SPRITE :{RAW_STRING}:{NUM}

###length 2
STR_SPRITE_ALIGNER_CENTRE_OFFSET :{BLACK}Offset centred
Expand Down Expand Up @@ -5833,6 +5836,7 @@ STR_JUST_DATE_ISO :{DATE_ISO}
STR_JUST_STRING :{STRING}
STR_JUST_STRING1 :{STRING1}
STR_JUST_STRING2 :{STRING2}
STR_JUST_STRING4 :{STRING4}
STR_JUST_STRING_STRING :{STRING}{STRING}
STR_JUST_RAW_STRING :{RAW_STRING}
STR_JUST_BIG_RAW_STRING :{BIG_FONT}{RAW_STRING}
Expand Down
33 changes: 14 additions & 19 deletions src/newgrf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "newgrf_station.h"
#include "industrytype.h"
#include "industry_map.h"
#include "newgrf_act5.h"
#include "newgrf_canal.h"
#include "newgrf_townname.h"
#include "newgrf_industries.h"
Expand Down Expand Up @@ -6369,7 +6370,7 @@ static void FeatureNewName(ByteReader *buf)
* @param name Used for error warnings.
* @return The number of sprites that is going to be skipped.
*/
static uint16_t SanitizeSpriteOffset(uint16_t &num, uint16_t offset, int max_sprites, const char *name)
static uint16_t SanitizeSpriteOffset(uint16_t &num, uint16_t offset, int max_sprites, const std::string_view name)
{

if (offset >= max_sprites) {
Expand All @@ -6390,23 +6391,8 @@ static uint16_t SanitizeSpriteOffset(uint16_t &num, uint16_t offset, int max_spr
}


/** The type of action 5 type. */
enum Action5BlockType {
A5BLOCK_FIXED, ///< Only allow replacing a whole block of sprites. (TTDP compatible)
A5BLOCK_ALLOW_OFFSET, ///< Allow replacing any subset by specifiing an offset.
A5BLOCK_INVALID, ///< unknown/not-implemented type
};
/** Information about a single action 5 type. */
struct Action5Type {
Action5BlockType block_type; ///< How is this Action5 type processed?
SpriteID sprite_base; ///< Load the sprites starting from this sprite.
uint16_t min_sprites; ///< If the Action5 contains less sprites, the whole block will be ignored.
uint16_t max_sprites; ///< If the Action5 contains more sprites, only the first max_sprites sprites will be used.
const char *name; ///< Name for error messages.
};

/** The information about action 5 types. */
static const Action5Type _action5_types[] = {
static constexpr auto _action5_types = std::to_array<Action5Type>({
/* Note: min_sprites should not be changed. Therefore these constants are directly here and not in sprites.h */
/* 0x00 */ { A5BLOCK_INVALID, 0, 0, 0, "Type 0x00" },
/* 0x01 */ { A5BLOCK_INVALID, 0, 0, 0, "Type 0x01" },
Expand All @@ -6433,7 +6419,16 @@ static const Action5Type _action5_types[] = {
/* 0x16 */ { A5BLOCK_ALLOW_OFFSET, SPR_AIRPORT_PREVIEW_BASE, 1, SPR_AIRPORT_PREVIEW_COUNT, "Airport preview graphics" },
/* 0x17 */ { A5BLOCK_ALLOW_OFFSET, SPR_RAILTYPE_TUNNEL_BASE, 1, RAILTYPE_TUNNEL_BASE_COUNT, "Railtype tunnel base" },
/* 0x18 */ { A5BLOCK_ALLOW_OFFSET, SPR_PALETTE_BASE, 1, PALETTE_SPRITE_COUNT, "Palette" },
};
});

/**
* Get list of all action 5 types
* @return Read-only span of action 5 type information.
*/
std::span<const Action5Type> GetAction5Types()
{
return _action5_types;
}

/* Action 0x05 */
static void GraphicsNew(ByteReader *buf)
Expand Down Expand Up @@ -6468,7 +6463,7 @@ static void GraphicsNew(ByteReader *buf)
}

/* Supported type? */
if ((type >= lengthof(_action5_types)) || (_action5_types[type].block_type == A5BLOCK_INVALID)) {
if ((type >= std::size(_action5_types)) || (_action5_types[type].block_type == A5BLOCK_INVALID)) {
GrfMsg(2, "GraphicsNew: Custom graphics (type 0x{:02X}) sprite block of length {} (unimplemented, ignoring)", type, num);
_cur.skip_sprites = num;
return;
Expand Down
31 changes: 31 additions & 0 deletions src/newgrf_act5.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/

/** @file newgrf_act5.h Information about NewGRF Action 5. */

#ifndef NEWGRF_ACT5_H
#define NEWGRF_ACT5_H

/** The type of action 5 type. */
enum Action5BlockType {
A5BLOCK_FIXED, ///< Only allow replacing a whole block of sprites. (TTDP compatible)
A5BLOCK_ALLOW_OFFSET, ///< Allow replacing any subset by specifiing an offset.
A5BLOCK_INVALID, ///< unknown/not-implemented type
};

/** Information about a single action 5 type. */
struct Action5Type {
Action5BlockType block_type; ///< How is this Action5 type processed?
SpriteID sprite_base; ///< Load the sprites starting from this sprite.
uint16_t min_sprites; ///< If the Action5 contains less sprites, the whole block will be ignored.
uint16_t max_sprites; ///< If the Action5 contains more sprites, only the first max_sprites sprites will be used.
const std::string_view name; ///< Name for error messages.
};

std::span<const Action5Type> GetAction5Types();

#endif /* NEWGRF_ACT5_H */
75 changes: 62 additions & 13 deletions src/newgrf_debug_gui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include "stdafx.h"
#include "core/backup_type.hpp"
#include "core/geometry_func.hpp"
#include "window_gui.h"
#include "window_func.h"
#include "random_access_file_type.h"
Expand All @@ -28,6 +29,7 @@
#include "train.h"
#include "roadveh.h"

#include "newgrf_act5.h"
#include "newgrf_airport.h"
#include "newgrf_airporttiles.h"
#include "newgrf_debug.h"
Expand Down Expand Up @@ -808,7 +810,6 @@ GrfSpecFeature GetGrfSpecFeature(VehicleType type)
}



/**** Sprite Aligner ****/

/** Window used for aligning sprites. */
Expand All @@ -822,13 +823,18 @@ struct SpriteAlignerWindow : Window {
static inline ZoomLevel zoom = ZOOM_LVL_END;
static bool centre;
static bool crosshair;
const Action5Type *act5_type = nullptr; ///< Sprite Area of current selected sprite.

SpriteAlignerWindow(WindowDesc *desc, WindowNumber wno) : Window(desc)
{
/* On first opening, set initial zoom to current zoom level. */
if (SpriteAlignerWindow::zoom == ZOOM_LVL_END) SpriteAlignerWindow::zoom = _gui_zoom;
SpriteAlignerWindow::zoom = Clamp(SpriteAlignerWindow::zoom, _settings_client.gui.zoom_min, _settings_client.gui.zoom_max);

/* Oh yes, we assume there is at least one normal sprite! */
while (GetSpriteType(this->current_sprite) != SpriteType::Normal) this->current_sprite++;
this->SelectAction5Type();

this->CreateNestedTree();
this->vscroll = this->GetScrollbar(WID_SA_SCROLLBAR);
this->vscroll->SetCount(_newgrf_debug_sprite_picker.sprites.size());
Expand All @@ -837,9 +843,6 @@ struct SpriteAlignerWindow : Window {
this->SetWidgetLoweredState(WID_SA_CENTRE, SpriteAlignerWindow::centre);
this->SetWidgetLoweredState(WID_SA_CROSSHAIR, SpriteAlignerWindow::crosshair);

/* Oh yes, we assume there is at least one normal sprite! */
while (GetSpriteType(this->current_sprite) != SpriteType::Normal) this->current_sprite++;

this->InvalidateData(0, true);
}

Expand All @@ -848,8 +851,22 @@ struct SpriteAlignerWindow : Window {
const Sprite *spr = GetSprite(this->current_sprite, SpriteType::Normal);
switch (widget) {
case WID_SA_CAPTION:
SetDParam(0, this->current_sprite);
SetDParamStr(1, GetOriginFile(this->current_sprite)->GetSimplifiedFilename());
if (this->act5_type != nullptr) {
SetDParam(0, STR_SPRITE_ALIGNER_CAPTION_ACTION5);
SetDParam(1, this->act5_type - GetAction5Types().data());
SetDParam(2, this->current_sprite - this->act5_type->sprite_base);
SetDParamStr(3, GetOriginFile(this->current_sprite)->GetSimplifiedFilename());
SetDParam(4, GetSpriteLocalID(this->current_sprite));
} else if (this->current_sprite < SPR_OPENTTD_BASE) {
SetDParam(0, STR_SPRITE_ALIGNER_CAPTION_ACTIONA);
SetDParam(1, this->current_sprite);
SetDParamStr(2, GetOriginFile(this->current_sprite)->GetSimplifiedFilename());
SetDParam(3, GetSpriteLocalID(this->current_sprite));
} else {
SetDParam(0, STR_SPRITE_ALIGNER_CAPTION_NO_ACTION);
SetDParamStr(1, GetOriginFile(this->current_sprite)->GetSimplifiedFilename());
SetDParam(2, GetSpriteLocalID(this->current_sprite));
}
break;

case WID_SA_OFFSETS_ABS:
Expand Down Expand Up @@ -883,13 +900,21 @@ struct SpriteAlignerWindow : Window {
case WID_SA_SPRITE:
size->height = ScaleGUITrad(200);
break;
case WID_SA_LIST:
SetDParamMaxDigits(0, 6);
size->width = GetStringBoundingBox(STR_JUST_COMMA).width + padding.width;

case WID_SA_LIST: {
Dimension d = {};
for (const auto &spritefile : GetCachedSpriteFiles()) {
SetDParamStr(0, spritefile->GetSimplifiedFilename());
SetDParamMaxDigits(1, 6);
d = maxdim(d, GetStringBoundingBox(STR_SPRITE_ALIGNER_SPRITE));
}
size->width = d.width + padding.width;
resize->height = GetCharacterHeight(FS_NORMAL) + padding.height;
resize->width = 1;
resize->width = 1;
fill->height = resize->height;
break;
}

default:
break;
}
Expand Down Expand Up @@ -941,8 +966,15 @@ struct SpriteAlignerWindow : Window {
Rect ir = r.Shrink(WidgetDimensions::scaled.matrix);
auto [first, last] = this->vscroll->GetVisibleRangeIterators(list);
for (auto it = first; it != last; ++it) {
SetDParam(0, *it);
DrawString(ir, STR_JUST_COMMA, *it == this->current_sprite ? TC_WHITE : TC_BLACK, SA_RIGHT | SA_FORCE);
const SpriteFile *file = GetOriginFile(*it);
if (file == nullptr) {
SetDParam(0, *it);
DrawString(ir, STR_JUST_COMMA, *it == this->current_sprite ? TC_WHITE : (TC_GREY | TC_NO_SHADE), SA_RIGHT | SA_FORCE);
} else {
SetDParamStr(0, file->GetSimplifiedFilename());
SetDParam(1, GetSpriteLocalID(*it));
DrawString(ir, STR_SPRITE_ALIGNER_SPRITE, *it == this->current_sprite ? TC_WHITE : TC_BLACK);
}
ir.top += step_size;
}
break;
Expand All @@ -957,6 +989,7 @@ struct SpriteAlignerWindow : Window {
do {
this->current_sprite = (this->current_sprite == 0 ? GetMaxSpriteID() : this->current_sprite) - 1;
} while (GetSpriteType(this->current_sprite) != SpriteType::Normal);
this->SelectAction5Type();
this->SetDirty();
break;

Expand All @@ -968,6 +1001,7 @@ struct SpriteAlignerWindow : Window {
do {
this->current_sprite = (this->current_sprite + 1) % GetMaxSpriteID();
} while (GetSpriteType(this->current_sprite) != SpriteType::Normal);
this->SelectAction5Type();
this->SetDirty();
break;

Expand All @@ -983,6 +1017,7 @@ struct SpriteAlignerWindow : Window {
SpriteID spr = *it;
if (GetSpriteType(spr) == SpriteType::Normal) this->current_sprite = spr;
}
this->SelectAction5Type();
this->SetDirty();
break;
}
Expand Down Expand Up @@ -1060,6 +1095,7 @@ struct SpriteAlignerWindow : Window {
while (GetSpriteType(this->current_sprite) != SpriteType::Normal) {
this->current_sprite = (this->current_sprite + 1) % GetMaxSpriteID();
}
this->SelectAction5Type();
this->SetDirty();
}

Expand Down Expand Up @@ -1088,6 +1124,19 @@ struct SpriteAlignerWindow : Window {
{
this->vscroll->SetCapacityFromWidget(this, WID_SA_LIST);
}

private:
void SelectAction5Type()
{
const auto act5types = GetAction5Types();
for (auto it = std::begin(act5types); it != std::end(act5types); ++it) {
if (it->sprite_base <= this->current_sprite && this->current_sprite < it->sprite_base + it->max_sprites) {
this->act5_type = &*it;
return;
}
}
this->act5_type = nullptr;
}
};

bool SpriteAlignerWindow::centre = true;
Expand All @@ -1096,7 +1145,7 @@ bool SpriteAlignerWindow::crosshair = true;
static constexpr NWidgetPart _nested_sprite_aligner_widgets[] = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_GREY),
NWidget(WWT_CAPTION, COLOUR_GREY, WID_SA_CAPTION), SetDataTip(STR_SPRITE_ALIGNER_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
NWidget(WWT_CAPTION, COLOUR_GREY, WID_SA_CAPTION), SetDataTip(STR_JUST_STRING4, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
NWidget(WWT_SHADEBOX, COLOUR_GREY),
NWidget(WWT_STICKYBOX, COLOUR_GREY),
EndContainer(),
Expand Down
9 changes: 9 additions & 0 deletions src/spritecache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,15 @@ static SpriteFile *GetCachedSpriteFileByName(const std::string &filename)
return nullptr;
}

/**
* Get the list of cached SpriteFiles.
* @return Read-only list of cache SpriteFiles.
*/
std::span<const std::unique_ptr<SpriteFile>> GetCachedSpriteFiles()
{
return _sprite_files;
}

/**
* Open/get the SpriteFile that is cached for use in the sprite cache.
* @param filename Name of the file at the disk.
Expand Down
1 change: 1 addition & 0 deletions src/spritecache.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ void GfxClearFontSpriteCache();
void IncreaseSpriteLRU();

SpriteFile &OpenCachedSpriteFile(const std::string &filename, Subdirectory subdir, bool palette_remap);
std::span<const std::unique_ptr<SpriteFile>> GetCachedSpriteFiles();

void ReadGRFSpriteOffsets(SpriteFile &file);
size_t GetGRFSpriteOffset(uint32_t id);
Expand Down