Changeset - r15087:eb029334c019
[Not reviewed]
master
0 7 0
rubidium - 14 years ago 2010-04-25 16:27:30
rubidium@openttd.org
(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.
7 files changed with 264 insertions and 1 deletions:
0 comments (0 inline, 0 general)
src/lang/english.txt
Show inline comments
 
@@ -442,6 +442,7 @@ STR_ABOUT_MENU_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_RAI
 

	
 
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}
src/newgrf_debug.h
Show inline comments
 
@@ -57,4 +57,9 @@ GrfSpecFeature GetGrfSpecFeature(TileInd
 
 */
 
GrfSpecFeature GetGrfSpecFeature(VehicleType type);
 

	
 
/**
 
 * Show the window for aligning sprites.
 
 */
 
void ShowSpriteAlignerWindow();
 

	
 
#endif /* NEWGRF_DEBUG_H */
src/newgrf_debug_gui.cpp
Show inline comments
 
@@ -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(Vehicle
 
		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);
 
}
src/spritecache.cpp
Show inline comments
 
@@ -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)
src/spritecache.h
Show inline comments
 
@@ -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);
src/toolbar_gui.cpp
Show inline comments
 
@@ -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;
 
	}
 
}
 

	
src/window_type.h
Show inline comments
 
@@ -107,6 +107,7 @@ enum WindowClass {
 
	WC_AI_LIST,
 
	WC_AI_SETTINGS,
 
	WC_NEWGRF_INSPECT,
 
	WC_SPRITE_ALIGNER,
 

	
 
	WC_INVALID = 0xFFFF
 
};
0 comments (0 inline, 0 general)