Debug: Add mode to sprite dump window to show unoptimised
This commit is contained in:
@@ -3056,6 +3056,7 @@ DEF_CONSOLE_CMD(ConMiscDebug)
|
||||
IConsoleHelp(" 2: MDF_ZONING_RS_WATER_FLOOD_STATE");
|
||||
IConsoleHelp(" 4: MDF_ZONING_RS_TROPIC_ZONE");
|
||||
IConsoleHelp(" 8: MDF_ZONING_RS_ANIMATED_TILE");
|
||||
IConsoleHelp(" 10: MDF_NEWGRF_SG_SAVE_RAW");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@@ -45,6 +45,7 @@ enum MiscDebugFlags {
|
||||
MDF_ZONING_RS_WATER_FLOOD_STATE,
|
||||
MDF_ZONING_RS_TROPIC_ZONE,
|
||||
MDF_ZONING_RS_ANIMATED_TILE,
|
||||
MDF_NEWGRF_SG_SAVE_RAW,
|
||||
};
|
||||
extern uint32 _misc_debug_flags;
|
||||
|
||||
|
@@ -4216,6 +4216,8 @@ STR_NEWGRF_INSPECT_DUPLICATE :{BLACK}D
|
||||
STR_NEWGRF_INSPECT_DUPLICATE_TOOLTIP :{BLACK}Duplicate this window
|
||||
STR_NEWGRF_INSPECT_SPRITE_DUMP :{BLACK}S
|
||||
STR_NEWGRF_INSPECT_SPRITE_DUMP_TOOLTIP :{BLACK}Display current sprite chain
|
||||
STR_NEWGRF_INSPECT_SPRITE_DUMP_UNOPT :{BLACK}U
|
||||
STR_NEWGRF_INSPECT_SPRITE_DUMP_UNOPT_TOOLTIP :{BLACK}Display sprite groups without any optimisations applied.{}{}Requires reloading NewGRFs if not previously enabled (misc_debug 10).
|
||||
STR_NEWGRF_INSPECT_SPRITE_DUMP_PANEL_TOOLTIP :{BLACK}Click to highlight sprite group{}Shift+Click to collapse sprite group{}Ctrl+Click to highlight temporary storage register
|
||||
|
||||
STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT :{STRING1} at {HEX}
|
||||
|
144
src/newgrf.cpp
144
src/newgrf.cpp
@@ -5544,20 +5544,8 @@ static const CallbackResultSpriteGroup *NewCallbackResultSpriteGroup(uint16 grou
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/* Helper function to either create a callback or link to a previously
|
||||
* defined spritegroup. */
|
||||
static const SpriteGroup *GetGroupFromGroupID(byte setid, byte type, uint16 groupid)
|
||||
static const SpriteGroup *PruneTargetSpriteGroup(const SpriteGroup *result)
|
||||
{
|
||||
if (HasBit(groupid, 15)) {
|
||||
return NewCallbackResultSpriteGroup(groupid);
|
||||
}
|
||||
|
||||
if (groupid > MAX_SPRITEGROUP || _cur.spritegroups[groupid] == nullptr) {
|
||||
grfmsg(1, "GetGroupFromGroupID(0x%02X:0x%02X): Groupid 0x%04X does not exist, leaving empty", setid, type, groupid);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const SpriteGroup *result = _cur.spritegroups[groupid];
|
||||
if (HasGrfOptimiserFlag(NGOF_NO_OPT_VARACT2) || HasGrfOptimiserFlag(NGOF_NO_OPT_VARACT2_GROUP_PRUNE)) return result;
|
||||
while (result != nullptr) {
|
||||
if (result->type == SGT_DETERMINISTIC) {
|
||||
@@ -5580,6 +5568,24 @@ static const SpriteGroup *GetGroupFromGroupID(byte setid, byte type, uint16 grou
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Helper function to either create a callback or link to a previously
|
||||
* defined spritegroup. */
|
||||
static const SpriteGroup *GetGroupFromGroupID(byte setid, byte type, uint16 groupid)
|
||||
{
|
||||
if (HasBit(groupid, 15)) {
|
||||
return NewCallbackResultSpriteGroup(groupid);
|
||||
}
|
||||
|
||||
if (groupid > MAX_SPRITEGROUP || _cur.spritegroups[groupid] == nullptr) {
|
||||
grfmsg(1, "GetGroupFromGroupID(0x%02X:0x%02X): Groupid 0x%04X does not exist, leaving empty", setid, type, groupid);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const SpriteGroup *result = _cur.spritegroups[groupid];
|
||||
if (likely(!HasBit(_misc_debug_flags, MDF_NEWGRF_SG_SAVE_RAW))) result = PruneTargetSpriteGroup(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
static const SpriteGroup *GetGroupByID(uint16 groupid)
|
||||
{
|
||||
const SpriteGroup *result = _cur.spritegroups[groupid];
|
||||
@@ -6793,6 +6799,46 @@ static void HandleVarAction2OptimisationPasses()
|
||||
}
|
||||
}
|
||||
|
||||
static void ProcessDeterministicSpriteGroupRanges(const std::vector<DeterministicSpriteGroupRange> &ranges, std::vector<DeterministicSpriteGroupRange> &ranges_out, const SpriteGroup *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 = default_group;
|
||||
for (uint i = 0; i < ranges.size(); i++) {
|
||||
if (ranges[i].low <= v && v <= ranges[i].high) {
|
||||
t = ranges[i].group;
|
||||
break;
|
||||
}
|
||||
}
|
||||
target.push_back(t);
|
||||
}
|
||||
assert(target.size() == bounds.size());
|
||||
|
||||
for (uint j = 0; j < bounds.size(); ) {
|
||||
if (target[j] != default_group) {
|
||||
DeterministicSpriteGroupRange &r = ranges_out.emplace_back();
|
||||
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;
|
||||
} else {
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Action 0x02 */
|
||||
static void NewSpriteGroup(ByteReader *buf)
|
||||
{
|
||||
@@ -6849,6 +6895,11 @@ static void NewSpriteGroup(ByteReader *buf)
|
||||
case 2: group->size = DSG_SIZE_DWORD; varsize = 4; break;
|
||||
}
|
||||
|
||||
DeterministicSpriteGroupShadowCopy *shadow = nullptr;
|
||||
if (unlikely(HasBit(_misc_debug_flags, MDF_NEWGRF_SG_SAVE_RAW))) {
|
||||
shadow = &(_deterministic_sg_shadows[group]);
|
||||
}
|
||||
|
||||
VarAction2OptimiseState va2_opt_state;
|
||||
/* The initial value is always the constant 0 */
|
||||
va2_opt_state.inference = VA2AIF_SIGNED_NON_NEGATIVE | VA2AIF_ONE_OR_ZERO | VA2AIF_HAVE_CONSTANT;
|
||||
@@ -6904,6 +6955,11 @@ static void NewSpriteGroup(ByteReader *buf)
|
||||
adjust.add_val = 0;
|
||||
adjust.divmod_val = 0;
|
||||
}
|
||||
if (unlikely(shadow != nullptr)) {
|
||||
shadow->adjusts.push_back(adjust);
|
||||
/* Pruning was turned off so that the unpruned target could be saved in the shadow, prune now */
|
||||
if (adjust.subroutine != nullptr) adjust.subroutine = PruneTargetSpriteGroup(adjust.subroutine);
|
||||
}
|
||||
|
||||
OptimiseVarAction2Adjust(va2_opt_state, feature, varsize, group, adjust);
|
||||
|
||||
@@ -6919,46 +6975,23 @@ static void NewSpriteGroup(ByteReader *buf)
|
||||
}
|
||||
|
||||
group->default_group = GetGroupFromGroupID(setid, type, buf->ReadWord());
|
||||
|
||||
if (unlikely(shadow != nullptr)) {
|
||||
ProcessDeterministicSpriteGroupRanges(ranges, shadow->ranges, group->default_group);
|
||||
shadow->default_group = group->default_group;
|
||||
|
||||
/* Pruning was turned off so that the unpruned targets could be saved in the shadow ranges, prune now */
|
||||
for (DeterministicSpriteGroupRange &range : ranges) {
|
||||
range.group = PruneTargetSpriteGroup(range.group);
|
||||
}
|
||||
group->default_group = PruneTargetSpriteGroup(group->default_group);
|
||||
}
|
||||
|
||||
group->error_group = ranges.size() > 0 ? ranges[0].group : group->default_group;
|
||||
/* nvar == 0 is a special case -- we turn our value into a callback result */
|
||||
group->calculated_result = ranges.size() == 0;
|
||||
|
||||
/* 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 = group->default_group;
|
||||
for (uint i = 0; i < ranges.size(); i++) {
|
||||
if (ranges[i].low <= v && v <= ranges[i].high) {
|
||||
t = ranges[i].group;
|
||||
break;
|
||||
}
|
||||
}
|
||||
target.push_back(t);
|
||||
}
|
||||
assert(target.size() == bounds.size());
|
||||
|
||||
for (uint j = 0; j < bounds.size(); ) {
|
||||
if (target[j] != group->default_group) {
|
||||
DeterministicSpriteGroupRange &r = group->ranges.emplace_back();
|
||||
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;
|
||||
} else {
|
||||
j++;
|
||||
}
|
||||
}
|
||||
ProcessDeterministicSpriteGroupRanges(ranges, group->ranges, group->default_group);
|
||||
|
||||
OptimiseVarAction2DeterministicSpriteGroup(va2_opt_state, feature, varsize, group);
|
||||
break;
|
||||
@@ -6994,6 +7027,16 @@ static void NewSpriteGroup(ByteReader *buf)
|
||||
group->groups.push_back(GetGroupFromGroupID(setid, type, buf->ReadWord()));
|
||||
}
|
||||
|
||||
if (unlikely(HasBit(_misc_debug_flags, MDF_NEWGRF_SG_SAVE_RAW))) {
|
||||
RandomizedSpriteGroupShadowCopy *shadow = &(_randomized_sg_shadows[group]);
|
||||
shadow->groups = group->groups;
|
||||
|
||||
/* Pruning was turned off so that the unpruned targets could be saved in the shadow groups, prune now */
|
||||
for (const SpriteGroup *&group : group->groups) {
|
||||
group = PruneTargetSpriteGroup(group);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -11289,6 +11332,9 @@ void ResetNewGRFData()
|
||||
InitializeSoundPool();
|
||||
_spritegroup_pool.CleanPool();
|
||||
_callback_result_cache.clear();
|
||||
_deterministic_sg_shadows.clear();
|
||||
_randomized_sg_shadows.clear();
|
||||
_grfs_loaded_with_sg_shadow_enable = HasBit(_misc_debug_flags, MDF_NEWGRF_SG_SAVE_RAW);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -20,6 +20,7 @@
|
||||
#include "vehicle_gui.h"
|
||||
#include "zoom_func.h"
|
||||
#include "scope.h"
|
||||
#include "debug_settings.h"
|
||||
|
||||
#include "engine_base.h"
|
||||
#include "industry.h"
|
||||
@@ -317,6 +318,7 @@ struct NewGRFInspectWindow : Window {
|
||||
bool auto_refresh = false;
|
||||
bool log_console = false;
|
||||
bool sprite_dump = false;
|
||||
bool sprite_dump_unopt = false;
|
||||
|
||||
uint32 extra_info_flags = 0;
|
||||
btree::btree_map<int, uint> extra_info_click_flag_toggles;
|
||||
@@ -389,7 +391,10 @@ struct NewGRFInspectWindow : Window {
|
||||
{
|
||||
this->CreateNestedTree();
|
||||
this->vscroll = this->GetScrollbar(WID_NGRFI_SCROLLBAR);
|
||||
this->GetWidget<NWidgetStacked>(WID_NGRFI_SPRITE_DUMP_SEL)->SetDisplayedPlane(GetFeatureHelper(wno)->ShowSpriteDumpButton(::GetFeatureIndex(wno)) ? 0 : SZSP_NONE);
|
||||
bool show_sprite_dump_button = GetFeatureHelper(wno)->ShowSpriteDumpButton(::GetFeatureIndex(wno));
|
||||
this->GetWidget<NWidgetStacked>(WID_NGRFI_SPRITE_DUMP_SEL)->SetDisplayedPlane(show_sprite_dump_button ? 0 : SZSP_NONE);
|
||||
this->GetWidget<NWidgetStacked>(WID_NGRFI_SPRITE_DUMP_UNOPT_SEL)->SetDisplayedPlane(show_sprite_dump_button ? 0 : SZSP_NONE);
|
||||
this->SetWidgetDisabledState(WID_NGRFI_SPRITE_DUMP_UNOPT, true);
|
||||
this->FinishInitNested(wno);
|
||||
|
||||
this->vscroll->SetCount(0);
|
||||
@@ -535,6 +540,7 @@ struct NewGRFInspectWindow : Window {
|
||||
};
|
||||
const_cast<NewGRFInspectWindow *>(this)->sprite_group_lines.clear();
|
||||
if (this->sprite_dump) {
|
||||
SpriteGroupDumper::use_shadows = this->sprite_dump_unopt;
|
||||
bool collapsed = false;
|
||||
const SpriteGroup *collapse_group = nullptr;
|
||||
uint collapse_lines = 0;
|
||||
@@ -572,6 +578,7 @@ struct NewGRFInspectWindow : Window {
|
||||
if (highlight_tag != 0 && this->selected_highlight_tag == highlight_tag) colour = TC_YELLOW;
|
||||
::DrawString(r.left + LEFT_OFFSET, r.right - RIGHT_OFFSET, r.top + TOP_OFFSET + (scroll_offset * this->resize.step_height), buf, colour);
|
||||
});
|
||||
SpriteGroupDumper::use_shadows = false;
|
||||
return;
|
||||
} else {
|
||||
NewGRFInspectWindow *this_mutable = const_cast<NewGRFInspectWindow *>(this);
|
||||
@@ -731,6 +738,20 @@ struct NewGRFInspectWindow : Window {
|
||||
}
|
||||
}
|
||||
|
||||
bool UnOptimisedSpriteDumpOK() const
|
||||
{
|
||||
if (_grfs_loaded_with_sg_shadow_enable) return true;
|
||||
|
||||
if (_networking && !_network_server) return false;
|
||||
|
||||
extern uint NetworkClientCount();
|
||||
if (_networking && NetworkClientCount() > 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void OnClick(Point pt, int widget, int click_count) override
|
||||
{
|
||||
switch (widget) {
|
||||
@@ -847,8 +868,34 @@ struct NewGRFInspectWindow : Window {
|
||||
case WID_NGRFI_SPRITE_DUMP: {
|
||||
this->sprite_dump = !this->sprite_dump;
|
||||
this->SetWidgetLoweredState(WID_NGRFI_SPRITE_DUMP, this->sprite_dump);
|
||||
this->SetWidgetDisabledState(WID_NGRFI_SPRITE_DUMP_UNOPT, !this->sprite_dump || !UnOptimisedSpriteDumpOK());
|
||||
this->GetWidget<NWidgetCore>(WID_NGRFI_MAINPANEL)->SetToolTip(this->sprite_dump ? STR_NEWGRF_INSPECT_SPRITE_DUMP_PANEL_TOOLTIP : STR_NULL);
|
||||
this->SetWidgetDirty(WID_NGRFI_SPRITE_DUMP);
|
||||
this->SetWidgetDirty(WID_NGRFI_SPRITE_DUMP_UNOPT);
|
||||
this->SetWidgetDirty(WID_NGRFI_MAINPANEL);
|
||||
this->SetWidgetDirty(WID_NGRFI_SCROLLBAR);
|
||||
break;
|
||||
}
|
||||
|
||||
case WID_NGRFI_SPRITE_DUMP_UNOPT: {
|
||||
if (!this->sprite_dump_unopt) {
|
||||
if (!UnOptimisedSpriteDumpOK()) {
|
||||
this->SetWidgetDisabledState(WID_NGRFI_SPRITE_DUMP_UNOPT, true);
|
||||
this->SetWidgetDirty(WID_NGRFI_SPRITE_DUMP_UNOPT);
|
||||
return;
|
||||
}
|
||||
if (!_grfs_loaded_with_sg_shadow_enable) {
|
||||
SetBit(_misc_debug_flags, MDF_NEWGRF_SG_SAVE_RAW);
|
||||
|
||||
ReloadNewGRFData();
|
||||
|
||||
extern void PostCheckNewGRFLoadWarnings();
|
||||
PostCheckNewGRFLoadWarnings();
|
||||
}
|
||||
}
|
||||
this->sprite_dump_unopt = !this->sprite_dump_unopt;
|
||||
this->SetWidgetLoweredState(WID_NGRFI_SPRITE_DUMP_UNOPT, this->sprite_dump_unopt);
|
||||
this->SetWidgetDirty(WID_NGRFI_SPRITE_DUMP_UNOPT);
|
||||
this->SetWidgetDirty(WID_NGRFI_MAINPANEL);
|
||||
this->SetWidgetDirty(WID_NGRFI_SCROLLBAR);
|
||||
break;
|
||||
@@ -904,6 +951,9 @@ static const NWidgetPart _nested_newgrf_inspect_chain_widgets[] = {
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(WWT_CLOSEBOX, COLOUR_GREY),
|
||||
NWidget(WWT_CAPTION, COLOUR_GREY, WID_NGRFI_CAPTION), SetDataTip(STR_NEWGRF_INSPECT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
|
||||
NWidget(NWID_SELECTION, INVALID_COLOUR, WID_NGRFI_SPRITE_DUMP_UNOPT_SEL),
|
||||
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_NGRFI_SPRITE_DUMP_UNOPT), SetDataTip(STR_NEWGRF_INSPECT_SPRITE_DUMP_UNOPT, STR_NEWGRF_INSPECT_SPRITE_DUMP_UNOPT_TOOLTIP),
|
||||
EndContainer(),
|
||||
NWidget(NWID_SELECTION, INVALID_COLOUR, WID_NGRFI_SPRITE_DUMP_SEL),
|
||||
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_NGRFI_SPRITE_DUMP), SetDataTip(STR_NEWGRF_INSPECT_SPRITE_DUMP, STR_NEWGRF_INSPECT_SPRITE_DUMP_TOOLTIP),
|
||||
EndContainer(),
|
||||
@@ -935,6 +985,9 @@ static const NWidgetPart _nested_newgrf_inspect_widgets[] = {
|
||||
NWidget(WWT_CLOSEBOX, COLOUR_GREY),
|
||||
NWidget(WWT_CAPTION, COLOUR_GREY, WID_NGRFI_CAPTION), SetDataTip(STR_NEWGRF_INSPECT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_NGRFI_PARENT), SetDataTip(STR_NEWGRF_INSPECT_PARENT_BUTTON, STR_NEWGRF_INSPECT_PARENT_TOOLTIP),
|
||||
NWidget(NWID_SELECTION, INVALID_COLOUR, WID_NGRFI_SPRITE_DUMP_UNOPT_SEL),
|
||||
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_NGRFI_SPRITE_DUMP_UNOPT), SetDataTip(STR_NEWGRF_INSPECT_SPRITE_DUMP_UNOPT, STR_NEWGRF_INSPECT_SPRITE_DUMP_UNOPT_TOOLTIP),
|
||||
EndContainer(),
|
||||
NWidget(NWID_SELECTION, INVALID_COLOUR, WID_NGRFI_SPRITE_DUMP_SEL),
|
||||
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_NGRFI_SPRITE_DUMP), SetDataTip(STR_NEWGRF_INSPECT_SPRITE_DUMP, STR_NEWGRF_INSPECT_SPRITE_DUMP_TOOLTIP),
|
||||
EndContainer(),
|
||||
|
@@ -26,6 +26,10 @@ INSTANTIATE_POOL_METHODS(SpriteGroup)
|
||||
|
||||
TemporaryStorageArray<int32, 0x110> _temp_store;
|
||||
|
||||
std::map<const DeterministicSpriteGroup *, DeterministicSpriteGroupShadowCopy> _deterministic_sg_shadows;
|
||||
std::map<const RandomizedSpriteGroup *, RandomizedSpriteGroupShadowCopy> _randomized_sg_shadows;
|
||||
bool _grfs_loaded_with_sg_shadow_enable = false;
|
||||
|
||||
|
||||
/**
|
||||
* ResolverObject (re)entry point.
|
||||
@@ -702,6 +706,8 @@ static char *GetAdjustOperationName(char *str, const char *last, DeterministicSp
|
||||
return str + seprintf(str, last, "\?\?\?(0x%X)", operation);
|
||||
}
|
||||
|
||||
bool SpriteGroupDumper::use_shadows = false;
|
||||
|
||||
void SpriteGroupDumper::DumpSpriteGroup(const SpriteGroup *sg, int padding, uint flags)
|
||||
{
|
||||
uint32 highlight_tag = 0;
|
||||
@@ -748,8 +754,22 @@ void SpriteGroupDumper::DumpSpriteGroup(const SpriteGroup *sg, int padding, uint
|
||||
}
|
||||
case SGT_DETERMINISTIC: {
|
||||
const DeterministicSpriteGroup *dsg = (const DeterministicSpriteGroup*)sg;
|
||||
if (padding == 0 && !dsg->calculated_result && dsg->default_group != nullptr) {
|
||||
this->top_default_group = dsg->default_group;
|
||||
|
||||
const SpriteGroup *default_group = dsg->default_group;
|
||||
const std::vector<DeterministicSpriteGroupAdjust> *adjusts = &(dsg->adjusts);
|
||||
const std::vector<DeterministicSpriteGroupRange> *ranges = &(dsg->ranges);
|
||||
|
||||
if (SpriteGroupDumper::use_shadows) {
|
||||
auto iter = _deterministic_sg_shadows.find(dsg);
|
||||
if (iter != _deterministic_sg_shadows.end()) {
|
||||
default_group = iter->second.default_group;
|
||||
adjusts = &(iter->second.adjusts);
|
||||
ranges = &(iter->second.ranges);
|
||||
}
|
||||
}
|
||||
|
||||
if (padding == 0 && !dsg->calculated_result && default_group != nullptr) {
|
||||
this->top_default_group = default_group;
|
||||
}
|
||||
if (dsg == this->top_default_group && !(padding == 4 && (flags & SGDF_DEFAULT))) {
|
||||
seprintf(this->buffer, lastof(this->buffer), "%*sTOP LEVEL DEFAULT GROUP: Deterministic (%s, %s), [%u]",
|
||||
@@ -769,7 +789,7 @@ void SpriteGroupDumper::DumpSpriteGroup(const SpriteGroup *sg, int padding, uint
|
||||
print();
|
||||
emit_start();
|
||||
padding += 2;
|
||||
for (const auto &adjust : dsg->adjusts) {
|
||||
for (const auto &adjust : (*adjusts)) {
|
||||
char *p = this->buffer;
|
||||
if (adjust.variable == 0x7D) {
|
||||
/* Temp storage load */
|
||||
@@ -832,27 +852,37 @@ void SpriteGroupDumper::DumpSpriteGroup(const SpriteGroup *sg, int padding, uint
|
||||
seprintf(this->buffer, lastof(this->buffer), "%*scalculated_result", padding, "");
|
||||
print();
|
||||
} else {
|
||||
for (const auto &range : dsg->ranges) {
|
||||
for (const auto &range : (*ranges)) {
|
||||
seprintf(this->buffer, lastof(this->buffer), "%*srange: %X -> %X", padding, "", range.low, range.high);
|
||||
print();
|
||||
this->DumpSpriteGroup(range.group, padding + 2, 0);
|
||||
}
|
||||
if (dsg->default_group != nullptr) {
|
||||
if (default_group != nullptr) {
|
||||
seprintf(this->buffer, lastof(this->buffer), "%*sdefault", padding, "");
|
||||
print();
|
||||
this->DumpSpriteGroup(dsg->default_group, padding + 2, SGDF_DEFAULT);
|
||||
this->DumpSpriteGroup(default_group, padding + 2, SGDF_DEFAULT);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SGT_RANDOMIZED: {
|
||||
const RandomizedSpriteGroup *rsg = (const RandomizedSpriteGroup*)sg;
|
||||
|
||||
const std::vector<const SpriteGroup *> *groups = &(rsg->groups);
|
||||
|
||||
if (SpriteGroupDumper::use_shadows) {
|
||||
auto iter = _randomized_sg_shadows.find(rsg);
|
||||
if (iter != _randomized_sg_shadows.end()) {
|
||||
groups = &(iter->second.groups);
|
||||
}
|
||||
}
|
||||
|
||||
seprintf(this->buffer, lastof(this->buffer), "%*sRandom (%s, %s, triggers: %X, count: %X, lowest_randbit: %X, groups: %u) [%u]",
|
||||
padding, "", _sg_scope_names[rsg->var_scope], rsg->cmp_mode == RSG_CMP_ANY ? "ANY" : "ALL",
|
||||
rsg->triggers, rsg->count, rsg->lowest_randbit, (uint)rsg->groups.size(), rsg->nfo_line);
|
||||
print();
|
||||
emit_start();
|
||||
for (const auto &group : rsg->groups) {
|
||||
for (const auto &group : (*groups)) {
|
||||
this->DumpSpriteGroup(group, padding + 2, 0);
|
||||
}
|
||||
break;
|
||||
|
@@ -22,6 +22,8 @@
|
||||
|
||||
#include "3rdparty/cpp-btree/btree_set.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
/**
|
||||
* Gets the value of a so-called newgrf "register".
|
||||
* @param i index of the register
|
||||
@@ -360,6 +362,12 @@ enum DeterministicSpriteGroupFlags : uint8 {
|
||||
};
|
||||
DECLARE_ENUM_AS_BIT_SET(DeterministicSpriteGroupFlags)
|
||||
|
||||
struct DeterministicSpriteGroupShadowCopy {
|
||||
std::vector<DeterministicSpriteGroupAdjust> adjusts;
|
||||
std::vector<DeterministicSpriteGroupRange> ranges;
|
||||
const SpriteGroup *default_group;
|
||||
};
|
||||
|
||||
struct DeterministicSpriteGroup : SpriteGroup {
|
||||
DeterministicSpriteGroup() : SpriteGroup(SGT_DETERMINISTIC) {}
|
||||
|
||||
@@ -387,6 +395,10 @@ enum RandomizedSpriteGroupCompareMode {
|
||||
RSG_CMP_ALL,
|
||||
};
|
||||
|
||||
struct RandomizedSpriteGroupShadowCopy {
|
||||
std::vector<const SpriteGroup *> groups;
|
||||
};
|
||||
|
||||
struct RandomizedSpriteGroup : SpriteGroup {
|
||||
RandomizedSpriteGroup() : SpriteGroup(SGT_RANDOMIZED) {}
|
||||
|
||||
@@ -406,6 +418,9 @@ protected:
|
||||
const SpriteGroup *Resolve(ResolverObject &object) const override;
|
||||
};
|
||||
|
||||
extern std::map<const DeterministicSpriteGroup *, DeterministicSpriteGroupShadowCopy> _deterministic_sg_shadows;
|
||||
extern std::map<const RandomizedSpriteGroup *, RandomizedSpriteGroupShadowCopy> _randomized_sg_shadows;
|
||||
extern bool _grfs_loaded_with_sg_shadow_enable;
|
||||
|
||||
/* This contains a callback result. A failed callback has a value of
|
||||
* CALLBACK_FAILED */
|
||||
@@ -631,6 +646,8 @@ enum DumpSpriteGroupPrintOp {
|
||||
using DumpSpriteGroupPrinter = std::function<void(const SpriteGroup *, DumpSpriteGroupPrintOp, uint32, const char *)>;
|
||||
|
||||
struct SpriteGroupDumper {
|
||||
static bool use_shadows;
|
||||
|
||||
private:
|
||||
char buffer[1024];
|
||||
DumpSpriteGroupPrinter print_fn;
|
||||
|
@@ -24,6 +24,8 @@ enum NewGRFInspectWidgets {
|
||||
WID_NGRFI_DUPLICATE, ///< Duplicate window
|
||||
WID_NGRFI_SPRITE_DUMP, ///< Dump current sprite group
|
||||
WID_NGRFI_SPRITE_DUMP_SEL, ///< Selection widget for WID_NGRFI_SPRITE_DUMP
|
||||
WID_NGRFI_SPRITE_DUMP_UNOPT, ///< Dump unoptimised sprite group
|
||||
WID_NGRFI_SPRITE_DUMP_UNOPT_SEL, ///< Selection widget for WID_NGRFI_SPRITE_DUMP_UNOPT
|
||||
};
|
||||
|
||||
/** Widgets of the #SpriteAlignerWindow class. */
|
||||
|
Reference in New Issue
Block a user