diff options
author | rubidium <rubidium@openttd.org> | 2010-04-25 16:27:30 +0000 |
---|---|---|
committer | rubidium <rubidium@openttd.org> | 2010-04-25 16:27:30 +0000 |
commit | c72e2dde603fe9ba0d57d2e6f259f32398b75a15 (patch) | |
tree | a4245990af5d20004a918d8b0131bd3a96e88613 /src | |
parent | 4868fb988ff7373ac0b436511464434a310273fd (diff) | |
download | openttd-c72e2dde603fe9ba0d57d2e6f259f32398b75a15.tar.xz |
(svn r19723) -Add: a simple sprite alignment helper. It does not store the new offsets anywhere so as soon as the sprite is reloaded the offsets are gone (use a bigger sprite cache if this happens). Also anything that reloads NewGRFs (new games, loading games or (re)applying NewGRFs) clears the sprite cache and as such resets the offsets.
Diffstat (limited to 'src')
-rw-r--r-- | src/lang/english.txt | 15 | ||||
-rw-r--r-- | src/newgrf_debug.h | 5 | ||||
-rw-r--r-- | src/newgrf_debug_gui.cpp | 200 | ||||
-rw-r--r-- | src/spritecache.cpp | 35 | ||||
-rw-r--r-- | src/spritecache.h | 5 | ||||
-rw-r--r-- | src/toolbar_gui.cpp | 4 | ||||
-rw-r--r-- | src/window_type.h | 1 |
7 files changed, 264 insertions, 1 deletions
diff --git a/src/lang/english.txt b/src/lang/english.txt index 3f2bec04a..fd175c3ad 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -442,6 +442,7 @@ STR_ABOUT_MENU_AI_DEBUG :AI debug STR_ABOUT_MENU_SCREENSHOT :Screenshot (Ctrl+S) STR_ABOUT_MENU_GIANT_SCREENSHOT :Giant screenshot (Ctrl+G) STR_ABOUT_MENU_ABOUT_OPENTTD :About 'OpenTTD' +STR_ABOUT_MENU_SPRITE_ALIGNER :Sprite aligner ############ range ends here ############ range for days starts (also used for the place in the highscore window) @@ -2375,6 +2376,20 @@ STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_RAIL_TYPE :Rail 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_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 at the end +STR_SPRITE_ALIGNER_GOTO_BUTTON :{BLACK}Go to sprite +STR_SPRITE_ALIGNER_GOTO_TOOLTIP :{BLACK}Go to the given sprite. If the sprite is not a normal sprite, proceed to the next normal sprite +STR_SPRITE_ALIGNER_PREVIOUS_BUTTON :{BLACK}Previous sprite +STR_SPRITE_ALIGNER_PREVIOUS_TOOLTIP :{BLACK}Proceed to the previous normal sprite, skipping any pseudo/recolour/font sprites and wrapping around at the begin +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 +STR_SPRITE_ALIGNER_OFFSETS :{BLACK}X offset: {NUM}, Y offset: {NUM} + +STR_SPRITE_ALIGNER_GOTO_CAPTION :{WHITE}Go to sprite + # NewGRF (self) generated warnings/errors STR_NEWGRF_ERROR_MSG_INFO :{SILVER}{RAW_STRING} STR_NEWGRF_ERROR_MSG_WARNING :{RED}Warning: {SILVER}{RAW_STRING} diff --git a/src/newgrf_debug.h b/src/newgrf_debug.h index 91f504a93..81af478ed 100644 --- a/src/newgrf_debug.h +++ b/src/newgrf_debug.h @@ -57,4 +57,9 @@ GrfSpecFeature GetGrfSpecFeature(TileIndex tile); */ GrfSpecFeature GetGrfSpecFeature(VehicleType type); +/** + * Show the window for aligning sprites. + */ +void ShowSpriteAlignerWindow(); + #endif /* NEWGRF_DEBUG_H */ diff --git a/src/newgrf_debug_gui.cpp b/src/newgrf_debug_gui.cpp index f40a11e54..637c5042d 100644 --- a/src/newgrf_debug_gui.cpp +++ b/src/newgrf_debug_gui.cpp @@ -13,7 +13,9 @@ #include <stdarg.h> #include "window_gui.h" #include "window_func.h" +#include "fileio_func.h" #include "gfx_func.h" +#include "spritecache.h" #include "string_func.h" #include "strings_func.h" #include "textbuf_gui.h" @@ -528,3 +530,201 @@ GrfSpecFeature GetGrfSpecFeature(VehicleType type) default: return GSF_INVALID; } } + + + +/**** Sprite Aligner ****/ + +/** Widgets we want (some) influence over. */ +enum SpriteAlignerWidgets { + SAW_CAPTION, ///< Caption of the window + SAW_PREVIOUS, ///< Skip to the previous sprite + SAW_GOTO, ///< Go to a given sprite + SAW_NEXT, ///< Skip to the next sprite + SAW_UP, ///< Move the sprite up + SAW_LEFT, ///< Move the sprite to the left + SAW_RIGHT, ///< Move the sprite to the right + SAW_DOWN, ///< Move the sprite down + SAW_SPRITE, ///< The actual sprite + SAW_OFFSETS, ///< The sprite offsets +}; + +/** Window used for aligning sprites. */ +struct SpriteAlignerWindow : Window { + SpriteID current_sprite; ///< The currently shown sprite + + SpriteAlignerWindow(const WindowDesc *desc, WindowNumber wno) : Window() + { + this->InitNested(desc, wno); + + /* Oh yes, we assume there is at least one normal sprite! */ + while (GetSpriteType(this->current_sprite) != ST_NORMAL) this->current_sprite++; + } + + virtual void SetStringParameters(int widget) const + { + switch (widget) { + case SAW_CAPTION: + SetDParam(0, this->current_sprite); + SetDParamStr(1, FioGetFilename(GetOriginFileSlot(this->current_sprite))); + break; + + case SAW_OFFSETS: { + const Sprite *spr = GetSprite(this->current_sprite, ST_NORMAL); + SetDParam(0, spr->x_offs); + SetDParam(1, spr->y_offs); + } break; + + default: + break; + } + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + if (widget != SAW_SPRITE) return; + + /* Center the sprite ourselves */ + const Sprite *spr = GetSprite(this->current_sprite, ST_NORMAL); + int width = r.right - r.left + 1; + int height = r.bottom - r.top + 1; + int x = r.left - spr->x_offs + (width - spr->width) / 2; + int y = r.top - spr->y_offs + (height - spr->height) / 2; + + /* And draw only the part within the sprite area */ + SubSprite subspr = { + spr->x_offs + (spr->width - width) / 2 + 1, + spr->y_offs + (spr->height - height) / 2 + 1, + spr->x_offs + (spr->width + width) / 2 - 1, + spr->y_offs + (spr->height + height) / 2 - 1, + }; + + DrawSprite(this->current_sprite, PAL_NONE, x, y, &subspr); + } + + virtual void OnPaint() + { + this->DrawWidgets(); + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + switch (widget) { + case SAW_PREVIOUS: + do { + this->current_sprite = (this->current_sprite == 0 ? GetMaxSpriteID() : this->current_sprite) - 1; + } while (GetSpriteType(this->current_sprite) != ST_NORMAL); + this->SetDirty(); + break; + + case SAW_GOTO: + ShowQueryString(STR_EMPTY, STR_SPRITE_ALIGNER_GOTO_CAPTION, 7, 150, this, CS_NUMERAL, QSF_NONE); + break; + + case SAW_NEXT: + do { + this->current_sprite = (this->current_sprite + 1) % GetMaxSpriteID(); + } while (GetSpriteType(this->current_sprite) != ST_NORMAL); + this->SetDirty(); + break; + + case SAW_UP: + case SAW_DOWN: + case SAW_LEFT: + case SAW_RIGHT: { + /* + * Yes... this is a hack. + * + * No... I don't think it is useful to make this less of a hack. + * + * If you want to align sprites, you just need the number. Generally + * the sprite caches are big enough to not remove the sprite from the + * cache. If that's not the case, just let the NewGRF developer + * increase the cache size instead of storing thousands of offsets + * for the incredibly small chance that it's actually going to be + * used by someone and the sprite cache isn't big enough for that + * particular NewGRF developer. + */ + Sprite *spr = const_cast<Sprite *>(GetSprite(this->current_sprite, ST_NORMAL)); + switch (widget) { + case SAW_UP: spr->y_offs--; break; + case SAW_DOWN: spr->y_offs++; break; + case SAW_LEFT: spr->x_offs--; break; + case SAW_RIGHT: spr->x_offs++; break; + } + /* Ofcourse, we need to redraw the sprite, but where is it used? + * Everywhere is a safe bet. */ + MarkWholeScreenDirty(); + } break; + } + } + + virtual void OnQueryTextFinished(char *str) + { + if (StrEmpty(str)) return; + + this->current_sprite = atoi(str); + if (this->current_sprite >= GetMaxSpriteID()) this->current_sprite = 0; + while (GetSpriteType(this->current_sprite) != ST_NORMAL) { + this->current_sprite = (this->current_sprite + 1) % GetMaxSpriteID(); + } + this->SetDirty(); + } +}; + +static const NWidgetPart _nested_sprite_aligner_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_GREY), + NWidget(WWT_CAPTION, COLOUR_GREY, SAW_CAPTION), SetDataTip(STR_SPRITE_ALIGNER_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_SHADEBOX, COLOUR_GREY), + NWidget(WWT_STICKYBOX, COLOUR_GREY), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY), + NWidget(NWID_VERTICAL), SetPIP(10, 5, 10), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(10, 5, 10), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, SAW_PREVIOUS), SetDataTip(STR_SPRITE_ALIGNER_PREVIOUS_BUTTON, STR_SPRITE_ALIGNER_PREVIOUS_TOOLTIP), SetFill(1, 0), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, SAW_GOTO), SetDataTip(STR_SPRITE_ALIGNER_GOTO_BUTTON, STR_SPRITE_ALIGNER_GOTO_TOOLTIP), SetFill(1, 0), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, SAW_NEXT), SetDataTip(STR_SPRITE_ALIGNER_NEXT_BUTTON, STR_SPRITE_ALIGNER_NEXT_TOOLTIP), SetFill(1, 0), + EndContainer(), + NWidget(NWID_HORIZONTAL), SetPIP(10, 5, 10), + NWidget(NWID_SPACER), SetFill(1, 1), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, SAW_UP), SetDataTip(SPR_ARROW_UP, STR_SPRITE_ALIGNER_MOVE_TOOLTIP), SetResize(0, 0), + NWidget(NWID_SPACER), SetFill(1, 1), + EndContainer(), + NWidget(NWID_HORIZONTAL_LTR), SetPIP(10, 5, 10), + NWidget(NWID_VERTICAL), + NWidget(NWID_SPACER), SetFill(1, 1), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, SAW_LEFT), SetDataTip(SPR_ARROW_LEFT, STR_SPRITE_ALIGNER_MOVE_TOOLTIP), SetResize(0, 0), + NWidget(NWID_SPACER), SetFill(1, 1), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_DARK_BLUE, SAW_SPRITE), SetDataTip(STR_NULL, STR_SPRITE_ALIGNER_SPRITE_TOOLTIP), SetMinimalSize(200, 200), + EndContainer(), + NWidget(NWID_VERTICAL), + NWidget(NWID_SPACER), SetFill(1, 1), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, SAW_RIGHT), SetDataTip(SPR_ARROW_RIGHT, STR_SPRITE_ALIGNER_MOVE_TOOLTIP), SetResize(0, 0), + NWidget(NWID_SPACER), SetFill(1, 1), + EndContainer(), + EndContainer(), + NWidget(NWID_HORIZONTAL), SetPIP(10, 5, 10), + NWidget(NWID_SPACER), SetFill(1, 1), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, SAW_DOWN), SetDataTip(SPR_ARROW_DOWN, STR_SPRITE_ALIGNER_MOVE_TOOLTIP), SetResize(0, 0), + NWidget(NWID_SPACER), SetFill(1, 1), + EndContainer(), + NWidget(NWID_HORIZONTAL), SetPIP(10, 5, 10), + NWidget(WWT_LABEL, COLOUR_GREY, SAW_OFFSETS), SetDataTip(STR_SPRITE_ALIGNER_OFFSETS, STR_NULL), SetFill(1, 0), + EndContainer(), + EndContainer(), + EndContainer(), +}; + +static const WindowDesc _sprite_aligner_desc( + WDP_AUTO, 400, 300, + WC_SPRITE_ALIGNER, WC_NONE, + WDF_UNCLICK_BUTTONS, + _nested_sprite_aligner_widgets, lengthof(_nested_sprite_aligner_widgets) +); + +void ShowSpriteAlignerWindow() +{ + AllocateWindowDescFront<SpriteAlignerWindow>(&_sprite_aligner_desc, 0); +} diff --git a/src/spritecache.cpp b/src/spritecache.cpp index 65b640c49..973150427 100644 --- a/src/spritecache.cpp +++ b/src/spritecache.cpp @@ -140,6 +140,41 @@ bool SpriteExists(SpriteID id) return !(GetSpriteCache(id)->file_pos == 0 && GetSpriteCache(id)->file_slot == 0); } +/** + * Get the sprite type of a given sprite. + * @param sprite The sprite to look at. + * @return the type of sprite. + */ +SpriteType GetSpriteType(SpriteID sprite) +{ + if (!SpriteExists(sprite)) return ST_INVALID; + return GetSpriteCache(sprite)->type; +} + +/** + * Get the (FIOS) file slot of a given sprite. + * @param sprite The sprite to look at. + * @return the FIOS file slot + */ +uint GetOriginFileSlot(SpriteID sprite) +{ + if (!SpriteExists(sprite)) return 0; + return GetSpriteCache(sprite)->file_slot; +} + +/** + * Get a reasonable (upper bound) estimate of the maximum + * SpriteID used in OpenTTD; there will be no sprites with + * a higher SpriteID, although there might be up to roughly + * a thousand unused SpriteIDs below this number. + * @note It's actually the number of spritecache items. + * @return maximum SpriteID + */ +uint GetMaxSpriteID() +{ + return _spritecache_items; +} + static void *AllocSprite(size_t); static void *ReadSprite(SpriteCache *sc, SpriteID id, SpriteType sprite_type) diff --git a/src/spritecache.h b/src/spritecache.h index 172702500..7801f5609 100644 --- a/src/spritecache.h +++ b/src/spritecache.h @@ -28,6 +28,11 @@ extern uint _sprite_cache_size; void *GetRawSprite(SpriteID sprite, SpriteType type); bool SpriteExists(SpriteID sprite); +SpriteType GetSpriteType(SpriteID sprite); +uint GetOriginFileSlot(SpriteID sprite); +uint GetMaxSpriteID(); + + static inline const Sprite *GetSprite(SpriteID sprite, SpriteType type) { assert(type != ST_RECOLOUR); diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp index 700310c2f..a0d4427fa 100644 --- a/src/toolbar_gui.cpp +++ b/src/toolbar_gui.cpp @@ -44,6 +44,7 @@ #include "smallmap_gui.h" #include "graph_gui.h" #include "textbuf_gui.h" +#include "newgrf_debug.h" #include "network/network.h" #include "network/network_gui.h" @@ -759,7 +760,7 @@ static void MenuClickNewspaper(int index) static void ToolbarHelpClick(Window *w) { - PopupMainToolbMenu(w, TBN_HELP, STR_ABOUT_MENU_LAND_BLOCK_INFO, 7); + PopupMainToolbMenu(w, TBN_HELP, STR_ABOUT_MENU_LAND_BLOCK_INFO, _settings_client.gui.newgrf_developer_tools ? 8 : 7); } static void MenuClickSmallScreenshot() @@ -781,6 +782,7 @@ static void MenuClickHelp(int index) case 4: MenuClickSmallScreenshot(); break; case 5: MenuClickWorldScreenshot(); break; case 6: ShowAboutWindow(); break; + case 7: ShowSpriteAlignerWindow(); break; } } diff --git a/src/window_type.h b/src/window_type.h index dd6982909..8cd45c64f 100644 --- a/src/window_type.h +++ b/src/window_type.h @@ -107,6 +107,7 @@ enum WindowClass { WC_AI_LIST, WC_AI_SETTINGS, WC_NEWGRF_INSPECT, + WC_SPRITE_ALIGNER, WC_INVALID = 0xFFFF }; |