changeset 654:5d6b1820b953

* Added the ability to change screen modes on the fly. This works both in OpenGL and SDL modes. * Added IEngineChangeListener so the client can update the cameras viewport if the screen mode has been changed. I chose to do it this way because the engine has no way to know which camera it should update. It will be up to the client to do it. * The cursor surface is now correctly freed when exiting. * Added DeviceCaps::getNearestScreenMode() for the client to request a supported screen mode. closes[t:315]
author prock@33b003aa-7bff-0310-803a-e67f0ece8222
date Thu, 21 Oct 2010 18:50:50 +0000
parents 01acc9fc35ea
children cdebc30c9c4a
files engine/core/controller/engine.cpp engine/core/controller/engine.h engine/core/controller/engine.i engine/core/gui/base/gui_font.cpp engine/core/gui/base/gui_font.h engine/core/gui/guimanager.cpp engine/core/gui/guimanager.h engine/core/util/resource/pool.h engine/core/video/cursor.cpp engine/core/video/cursor.h engine/core/video/devicecaps.cpp engine/core/video/fonts/abstractfont.h engine/core/video/fonts/fontbase.cpp engine/core/video/fonts/fontbase.h engine/core/video/fonts/textrenderpool.cpp engine/core/video/fonts/textrenderpool.h engine/core/video/image.h engine/core/video/imagepool.h engine/core/video/opengl/glimage.cpp engine/core/video/opengl/glimage.h engine/core/video/opengl/renderbackendopengl.cpp engine/core/video/opengl/renderbackendopengl.h engine/core/video/renderbackend.h engine/core/video/sdl/renderbackendsdl.cpp engine/core/video/sdl/renderbackendsdl.h engine/core/video/sdl/sdlimage.h engine/core/video/video.i
diffstat 27 files changed, 320 insertions(+), 158 deletions(-) [+]
line wrap: on
line diff
--- a/engine/core/controller/engine.cpp	Fri Oct 15 18:54:34 2010 +0000
+++ b/engine/core/controller/engine.cpp	Thu Oct 21 18:50:50 2010 +0000
@@ -74,6 +74,8 @@
 #include "view/renderers/cellselectionrenderer.h"
 #include "view/renderers/blockinginforenderer.h"
 #include "view/renderers/genericrenderer.h"
+#include "video/image.h"
+#include "gui/console/console.h"
 #include "engine.h"
 
 #ifdef USE_COCOA
@@ -105,7 +107,8 @@
 		m_logmanager(0),
 		m_cursor(0),
 		m_settings(),
-		m_devcaps(){
+		m_devcaps(),
+		m_changelisteners() {
 #ifdef USE_COCOA
 		// The next lines ensure that Cocoa is initialzed correctly.
 		// This is needed for SDL to function properly on MAC OS X.
@@ -131,6 +134,26 @@
 		return m_devcaps;
 	}
 
+	Image* Engine::changeScreenMode(const ScreenMode& mode){
+		m_cursor->invalidate();
+		m_imagepool->invalidateLoadedImages();
+		m_defaultfont->invalidate();
+		m_guimanager->invalidateFonts();
+
+		Image* screen = m_renderbackend->setScreenMode(mode);
+
+		m_guimanager->resizeTopContainer(0,0,mode.getWidth(), mode.getHeight());
+		m_guimanager->getConsole()->reLayout();
+
+		std::vector<IEngineChangeListener*>::iterator i = m_changelisteners.begin();
+		while (i != m_changelisteners.end()) {
+			(*i)->onScreenModeChanged(mode);
+			++i;
+		}
+
+		return screen;
+	}
+
 	void Engine::preInit() {
 		m_logmanager = LogManager::instance();
 
@@ -248,7 +271,7 @@
 			m_settings.getDefaultFontSize(),
 			m_settings.getDefaultFontGlyphs());
 		FL_LOG(_log, "Initializing GUI manager");
-		m_guimanager->init(m_gui_graphics, m_settings.getScreenWidth(), m_settings.getScreenHeight());
+		m_guimanager->init(m_gui_graphics, m_renderbackend->getScreenWidth(), m_renderbackend->getScreenHeight());
 		FL_LOG(_log, "GUI manager initialized");
 		SDL_EnableUNICODE(1);
 
@@ -343,6 +366,21 @@
 	void Engine::finalizePumping() {
 		// nothing here at the moment..
 	}
+
+	void Engine::addChangeListener(IEngineChangeListener* listener) {
+		m_changelisteners.push_back(listener);
+	}
+
+	void Engine::removeChangeListener(IEngineChangeListener* listener) {
+		std::vector<IEngineChangeListener*>::iterator i = m_changelisteners.begin();
+		while (i != m_changelisteners.end()) {
+			if ((*i) == listener) {
+				m_changelisteners.erase(i);
+				return;
+			}
+			++i;
+		}
+	}
 }//FIFE
 
 /* vim: set noexpandtab: set shiftwidth=2: set tabstop=2: */
--- a/engine/core/controller/engine.h	Fri Oct 15 18:54:34 2010 +0000
+++ b/engine/core/controller/engine.h	Thu Oct 21 18:50:50 2010 +0000
@@ -63,6 +63,17 @@
 	class Cursor;
 	class SoundClipPool;
 	class RendererBase;
+	class Image;
+
+
+	class IEngineChangeListener {
+	public:
+		virtual ~IEngineChangeListener() {}
+
+		/** Screen mode has been changed
+		 */
+		virtual void onScreenModeChanged(const ScreenMode& newmode) = 0;
+	};
 
 	/** Engine acts as a controller to the whole system
 	 * Responsibilities of the engine are:
@@ -88,6 +99,16 @@
 		 */
 		const DeviceCaps& getDeviceCaps() const;
 
+		/** Changes the screen mode.
+		 * This should be called instead of the renderer's setScreenMode() function.
+		 * It takes care of any objects that need to be re-created after switching
+		 * screen modes.
+		 *
+		 * @param mode A valid ScreenMode retrieved from FIFE::DeviceCaps::getNearestScreenMode()
+		 * @return The new Screen Image
+		 */
+		Image* changeScreenMode(const ScreenMode& mode);
+
 		/** Initializes the engine
 		 */
 		void init();
@@ -163,6 +184,16 @@
 		 */
 		Cursor* getCursor() const { return m_cursor; }
 
+		/** Adds new change listener
+		* @param listener to add
+		*/
+		void addChangeListener(IEngineChangeListener* listener);
+
+		/** Removes associated change listener
+		* @param listener to remove
+		*/
+		void removeChangeListener(IEngineChangeListener* listener);
+
 	private:
 		void preInit();
 
@@ -189,6 +220,8 @@
 
 		std::vector<RendererBase*> m_renderers;
 
+		std::vector<IEngineChangeListener*> m_changelisteners;
+
 #ifdef USE_COCOA
 		objc_object *m_autoreleasePool;
 #endif
--- a/engine/core/controller/engine.i	Fri Oct 15 18:54:34 2010 +0000
+++ b/engine/core/controller/engine.i	Thu Oct 21 18:50:50 2010 +0000
@@ -41,6 +41,7 @@
 	class RendererBase;
 	class DeviceCaps;
 	class ScreenMode;
+	class Image;
 
 	class EngineSettings {
 	public:
@@ -85,6 +86,13 @@
 		EngineSettings();
 	};	
 	
+	%feature("director") IEngineChangeListener;
+	class IEngineChangeListener {
+	public:
+		virtual ~IEngineChangeListener() {}
+		virtual void onScreenModeChanged(const ScreenMode& newmode) = 0;
+	};
+
 	class Engine {
 	public:
 		Engine();
@@ -96,6 +104,8 @@
 		EngineSettings& getSettings();
 		const DeviceCaps& getDeviceCaps() const;
 		
+		Image* changeScreenMode(const ScreenMode& mode);
+		
 		void init();
 		void destroy();
 
@@ -112,5 +122,8 @@
 		GuiFont* getDefaultFont();
 		VFS* getVFS();
 		Cursor* getCursor();
+		
+		void addChangeListener(IEngineChangeListener* listener);
+		void removeChangeListener(IEngineChangeListener* listener);
 	};
 }
--- a/engine/core/gui/base/gui_font.cpp	Fri Oct 15 18:54:34 2010 +0000
+++ b/engine/core/gui/base/gui_font.cpp	Thu Oct 21 18:50:50 2010 +0000
@@ -38,15 +38,15 @@
 	GuiFont::GuiFont(AbstractFont* font): m_font(font) {
 		assert(font);
 	}
-	
+
 	GuiFont::~GuiFont() {
 		delete m_font;
 	}
-	
+
 	int GuiFont::getStringIndexAt(const std::string& text, int x) const {
 		return m_font->getStringIndexAt(text, x);
 	}
-	
+
 	void GuiFont::drawString(gcn::Graphics* graphics, const std::string& text, int x, int y) {
 		if (text == "") {
 			return;
@@ -90,35 +90,35 @@
 		}
 		image->render(rect);
 	}
-	
+
 	void GuiFont::setRowSpacing (int spacing) {
 		m_font->setRowSpacing(spacing);
 	}
-	
+
 	int GuiFont::getRowSpacing() const {
 		return m_font->getRowSpacing();
 	}
-	
+
 	void GuiFont::setGlyphSpacing(int spacing) {
 		m_font->setGlyphSpacing(spacing);
 	}
-	
+
 	int GuiFont::getGlyphSpacing() const {
 		return m_font->getGlyphSpacing();
 	}
-	
+
 	void GuiFont::setAntiAlias(bool antiAlias) {
 		m_font->setAntiAlias(antiAlias);
 	}
-	
+
 	bool GuiFont::isAntiAlias() {
 		return m_font->isAntiAlias();
 	}
-	
+
 	Image* GuiFont::getAsImage(const std::string& text) {
 		return m_font->getAsImage(text);
 	}
-	
+
 	Image* GuiFont::getAsImageMultiline(const std::string& text) {
 		return m_font->getAsImageMultiline(text);
 	}
@@ -130,16 +130,20 @@
 	void GuiFont::setColor(uint8_t r,uint8_t g,uint8_t b, uint8_t a) {
 		m_font->setColor(r, g, b, a);
 	}
-	
+
 	SDL_Color GuiFont::getColor() const {
 		return m_font->getColor();
 	}
-	
+
 	int GuiFont::getWidth(const std::string& text) const {
 		return m_font->getWidth(text);
 	}
-	
+
 	int GuiFont::getHeight() const {
 		return m_font->getHeight();
 	}
+
+	void GuiFont::invalidate() {
+		m_font->invalidate();
+	}
 }
--- a/engine/core/gui/base/gui_font.h	Fri Oct 15 18:54:34 2010 +0000
+++ b/engine/core/gui/base/gui_font.h	Thu Oct 21 18:50:50 2010 +0000
@@ -43,7 +43,7 @@
 		 */
 		GuiFont(AbstractFont* font);
 		virtual ~GuiFont();
-		
+
 		int getStringIndexAt(const std::string& text, int x) const;
 		void drawString(gcn::Graphics* graphics, const std::string& text, int x, int y);
 		void drawMultiLineString(gcn::Graphics* graphics, const std::string& text, int x, int y);
@@ -61,7 +61,8 @@
 		SDL_Color getColor() const;
 		int getWidth(const std::string& text) const;
 		int getHeight() const;
-		
+		void invalidate();
+
 	private:
 		AbstractFont* m_font;
 	};
--- a/engine/core/gui/guimanager.cpp	Fri Oct 15 18:54:34 2010 +0000
+++ b/engine/core/gui/guimanager.cpp	Thu Oct 21 18:50:50 2010 +0000
@@ -205,6 +205,14 @@
 		}
 	}
 
+	void GUIManager::invalidateFonts() {
+		std::vector<GuiFont*>::iterator it = m_fonts.begin();
+		while (it != m_fonts.end()) {
+			(*it)->invalidate();
+			++it;
+		}
+	}
+
 	GuiFont* GUIManager::setDefaultFont(const std::string& path, unsigned int size, const std::string& glyphs) {
 		m_fontpath = path;
 		m_fontsize = size;
--- a/engine/core/gui/guimanager.h	Fri Oct 15 18:54:34 2010 +0000
+++ b/engine/core/gui/guimanager.h	Thu Oct 21 18:50:50 2010 +0000
@@ -62,8 +62,8 @@
 	 *
 	 * This class controls the GUI system in FIFE.
 	 */
-	class GUIManager : 
-		public DynamicSingleton<GUIManager>, 
+	class GUIManager :
+		public DynamicSingleton<GUIManager>,
 		public ISdlEventListener
 		 {
 		public:
@@ -85,14 +85,14 @@
 			 * This will be called each frame.
 			 */
 			void turn();
-			
+
 			/** Inits the GUI Manager.
 			 * @param graphics backend specific grapchics object to use
 			 * @param screenWidth width for the gui top container
 			 * @param screenHeight height for the gui top container
 			 */
 			void init(gcn::Graphics* graphics, int screenWidth, int screenHeight);
-			
+
 			/** Resizes the top container.
 			 *
 			 * @param x The new starting X coordinate.
@@ -101,7 +101,7 @@
 			 * @param height The new height.
 			 */
 			void resizeTopContainer(unsigned int x, unsigned int y, unsigned int width, unsigned int height);
-			
+
 			/** Adds a new widget.
 			 *
 			 * @param A pointer to the widget to add.
@@ -117,7 +117,7 @@
 			 * @return The top container.
 			 */
 			gcn::Container* getTopContainer() const { return m_gcn_topcontainer; }
-			
+
 			/** Gets the console.
 			 *
 			 * @return The console.
@@ -127,7 +127,7 @@
 			/** Set the global font properties.
 			 */
 			GuiFont* setDefaultFont(const std::string& path, unsigned int size, const std::string& glyphs);
-			
+
 			/** Gets font with given properties. Note that font will be owned by guimanager
 			 */
 			GuiFont* createFont(const std::string& path = "", unsigned int size = 0, const std::string& glyphs = "");
@@ -136,6 +136,8 @@
 			 */
 			void releaseFont(GuiFont* font);
 
+			void invalidateFonts();
+
 			bool onSdlEvent(SDL_Event& evt);
 
 			KeyEvent translateKeyEvent(const gcn::KeyEvent& evt);
@@ -172,7 +174,7 @@
 			std::string m_fontpath;
 			std::string m_fontglyphs;
 			int m_fontsize;
-			
+
 			// true, if guichan logic has already been executed for this round
 			bool m_logic_executed;
 	};
--- a/engine/core/util/resource/pool.h	Fri Oct 15 18:54:34 2010 +0000
+++ b/engine/core/util/resource/pool.h	Thu Oct 21 18:50:50 2010 +0000
@@ -134,7 +134,7 @@
 		 */
 		virtual void reset();
 
-	private:
+	protected:
 		class PoolEntry {
 		public:
 			PoolEntry(): resource(0), location(0), loader(0) {}
--- a/engine/core/video/cursor.cpp	Fri Oct 15 18:54:34 2010 +0000
+++ b/engine/core/video/cursor.cpp	Thu Oct 21 18:50:50 2010 +0000
@@ -89,11 +89,12 @@
 		m_drag_offset_y(0),
 		m_mx(0),
 		m_my(0),
-		m_timemanager(TimeManager::instance()) {
+		m_timemanager(TimeManager::instance()),
+		m_invalidated(false) {
 		assert(m_timemanager);
 		set(m_cursor_type, m_cursor_id);
 	}
-	
+
 	void Cursor::set(MouseCursorType ctype, unsigned int cursor_id) {
 		m_cursor_id = cursor_id;
 		m_cursor_type = ctype;
@@ -115,8 +116,9 @@
 				m_animtime = m_timemanager->getTime();
 			}
 		}
+		m_invalidated = false;
 	}
-	
+
 	void Cursor::setDrag(MouseCursorType ctype, unsigned int drag_id, int drag_offset_x, int drag_offset_y) {
 		m_drag_type = ctype;
 		m_drag_id = drag_id;
@@ -128,13 +130,28 @@
 			}
 		}
 	}
-	
+
+	void Cursor::invalidate() {
+		if (m_native_cursor != NULL) {
+			SDL_free(m_native_cursor->wm_cursor);
+			m_native_cursor->wm_cursor = NULL;
+			SDL_FreeCursor(m_native_cursor);
+			m_native_cursor = NULL;
+
+			m_invalidated = true;
+		}
+	}
+
 	void Cursor::draw() {
+		if (m_invalidated) {
+			set(m_cursor_type, m_cursor_id);
+		}
+
 		SDL_GetMouseState(&m_mx, &m_my);
 		if ((m_cursor_type == CURSOR_NATIVE) && (m_drag_type == CURSOR_NONE)) {
 			return;
 		}
-		
+
 		// render possible drag image
 		Image* img = NULL;
 		if (m_drag_type == CURSOR_IMAGE) {
@@ -150,7 +167,7 @@
 			img->render(area);
 			m_renderbackend->popClipArea();
 		}
-		
+
 		// render possible cursor image
 		img = NULL;
 		if (m_cursor_type == CURSOR_IMAGE) {
@@ -324,7 +341,7 @@
 		cursor->x_cursor = xCursor;
 		XSync(dsp, false);
 #endif
-		
+
 		m_native_cursor = curs2;
 		SDL_SetCursor(curs2);
 
--- a/engine/core/video/cursor.h	Fri Oct 15 18:54:34 2010 +0000
+++ b/engine/core/video/cursor.h	Thu Oct 21 18:50:50 2010 +0000
@@ -39,7 +39,7 @@
 	class AnimationPool;
 	class RenderBackend;
 	class TimeManager;
-	
+
 	/** Defines the type of shown cursor
 	 * native -> default cursor
 	 * image -> cursor from image pool
@@ -65,13 +65,13 @@
 		NC_CROSS,			// Crosshair
 		NC_UPARROW,			// Vertical arrow
 		NC_RESIZENW,		// Cursor for resize in northwest corner
-		NC_RESIZESE,		// 
-		NC_RESIZESW,		// 
-		NC_RESIZENE,		// 
-		NC_RESIZEE,			// 
-		NC_RESIZEW,			// 
-		NC_RESIZEN,			// 
-		NC_RESIZES,			// 
+		NC_RESIZESE,		//
+		NC_RESIZESW,		//
+		NC_RESIZENE,		//
+		NC_RESIZEE,			//
+		NC_RESIZEW,			//
+		NC_RESIZEN,			//
+		NC_RESIZES,			//
 		NC_RESIZEALL,		// Four-pointed arrow pointing north, south, east, and west
 		NC_NO,				// Slashed circle
 		NC_HAND,			// Hand. Common for links, etc.
@@ -89,7 +89,9 @@
 
 		/** Destructor.
 		 */
-		virtual ~Cursor() {}
+		virtual ~Cursor() { invalidate(); }
+
+		void invalidate();
 
 		/** draws cursor on screen
 		 */
@@ -100,26 +102,26 @@
 		 * @param cursor_id Pool id to image or animation. For native cursors, this is the resource id to native cursor, or one of the values in NativeCursor
 		 */
 		void set(MouseCursorType ctype, unsigned int cursor_id=0);
-			
+
 		/** Sets the current drag cursor type and pool value
 		 * @param ctype drag cursor type
 		 * @param drag_id pool id for the drag cursor (either image or animation)
 		 * @param drag_offset offset of drag image shown with cursor
 		 */
 		void setDrag(MouseCursorType ctype, unsigned int drag_id=0, int drag_offset_x=0, int drag_offset_y=0);
-		
+
 		/** Gets the current mouse cursor type
 		 */
 		MouseCursorType getType() const { return m_cursor_type; }
-	
+
 		/** Gets the current mouse cursor pool id
 		 */
 		unsigned int getId() const { return m_cursor_id; }
-		
+
 		/** Gets the current mouse cursor type
 		 */
 		MouseCursorType getDragType() const { return m_drag_type; }
-		
+
 		/** Gets the current mouse cursor pool id
 		 */
 		unsigned int getDragId() const { return m_drag_id; }
@@ -146,7 +148,7 @@
 		  * @param One of the values in NativeCursor
 		  */
 		unsigned int getNativeId(unsigned int cursor_id);
-	
+
 	private:
 		unsigned int m_cursor_id;
 		unsigned int m_drag_id;
@@ -154,19 +156,21 @@
 		MouseCursorType m_drag_type;
 
 		SDL_Cursor* m_native_cursor;
-		
+
 		RenderBackend* m_renderbackend;
 		ImagePool* m_imgpool;
 		AnimationPool* m_animpool;
-		
+
 		unsigned int m_animtime;
 		unsigned int m_drag_animtime;
-		
+
 		int m_drag_offset_x;
 		int m_drag_offset_y;
 		int m_mx;
 		int m_my;
 		TimeManager* m_timemanager;
+
+		bool m_invalidated;
 	};
 
 } //FIFE
--- a/engine/core/video/devicecaps.cpp	Fri Oct 15 18:54:34 2010 +0000
+++ b/engine/core/video/devicecaps.cpp	Thu Oct 21 18:50:50 2010 +0000
@@ -53,24 +53,37 @@
 	}
 
 	bool ScreenMode::operator <(const ScreenMode& rhs) const {
-		if (m_bpp < rhs.getBPP() ) {
+
+		//sort by fullscreen first
+		if (!isFullScreen() && rhs.isFullScreen()){
+			return true;
+		}
+		else if (isFullScreen() && !rhs.isFullScreen()){
+			return false;
+		}
+
+		//next by bpp
+		if (m_bpp < rhs.getBPP()){
+			return true;
+		}
+		else if (m_bpp > rhs.getBPP()){
+			return false;
+		}
+
+		//then by screen dimentions
+		if (m_width == rhs.getWidth() && m_height == rhs.getHeight()){
+			if (!(m_SDLFlags & SDL_HWSURFACE) && (rhs.getSDLFlags() & SDL_HWSURFACE)) {
+				//I would like return true so that we prefer hardware surfaces but
+				//it really slows the engine down in fullscreen.  See the SDL FAQ for an
+				//explanation.
+				return false;
+			}
+		}
+
+		else if (m_width < rhs.getWidth() || m_height < rhs.getHeight()) {
 			return true;
 		}
 
-		else if (m_bpp == rhs.getBPP()) {
-			if (m_width == rhs.getWidth() && m_height == rhs.getHeight()){
-				if (!(m_SDLFlags & SDL_HWSURFACE) && (rhs.getSDLFlags() & SDL_HWSURFACE)) {
-					//I would like return true so that we prefer hardware surfaces but
-					//it really slows the engine down in fullscreen.  See the SDL FAQ for an
-					//explanation.
-					return false;
-				}
-			}
-
-			else if (m_width < rhs.getWidth() || m_height < rhs.getHeight()) {
-				return true;
-			}
-		}
 		return false;
 	}
 
--- a/engine/core/video/fonts/abstractfont.h	Fri Oct 15 18:54:34 2010 +0000
+++ b/engine/core/video/fonts/abstractfont.h	Thu Oct 21 18:50:50 2010 +0000
@@ -99,7 +99,7 @@
 		 *  The rsulting image is pooled, so it's not that time critical
 		 */
 		virtual Image* getAsImageMultiline(const std::string& text) = 0;
-		
+
 		virtual std::string splitTextToWidth (const std::string& text, int render_width) = 0;
 
 		/** Set the color the text should be rendered in
@@ -109,14 +109,16 @@
 		/** Get the color the text was rendered in
 		 */
 		virtual SDL_Color getColor() const = 0;
-		
+
 		/** gets width of given text
 		 */
 		virtual int getWidth(const std::string& text) const = 0;
-		
+
 		/** gets height of this font
 		 */
 		virtual int getHeight() const = 0;
+
+		virtual void invalidate() = 0;
 	};
 }
 
--- a/engine/core/video/fonts/fontbase.cpp	Fri Oct 15 18:54:34 2010 +0000
+++ b/engine/core/video/fonts/fontbase.cpp	Thu Oct 21 18:50:50 2010 +0000
@@ -50,6 +50,10 @@
 			m_antiAlias(true) {
 	}
 
+	void FontBase::invalidate() {
+		m_pool.invalidateCachedText();
+	}
+
 	void FontBase::setRowSpacing(int spacing) {
 		mRowSpacing = spacing;
 	}
@@ -143,7 +147,7 @@
 				}
 				lines.push_back(text_surface);
 			} while (it != text.end());
-			
+
 			render_height = (getRowSpacing() + getHeight()) * lines.size();
 			SDL_Surface* final_surface = SDL_CreateRGBSurface(SDL_SWSURFACE,
 				render_width,render_height,32,
@@ -173,7 +177,7 @@
 		const uint8_t newline_utf8 = '\n';
 		uint32_t newline;
 		utf8::utf8to32(&newline_utf8,&newline_utf8 + 1,&newline);
-		if (render_width <= 0 || text.empty()) { 
+		if (render_width <= 0 || text.empty()) {
 			return text;
 		}
 		std::string output;
@@ -190,7 +194,7 @@
 			} else {
 				firstLine = false;
 			}
-			
+
 			bool haveNewLine = false;
 			while( getWidth(line) < render_width && pos != text.end() )
 			{
@@ -223,7 +227,7 @@
 					output.append(line);
 					continue;
 				}
-				
+
 				if (line == "\n") {
 					++pos;
 				}
--- a/engine/core/video/fonts/fontbase.h	Fri Oct 15 18:54:34 2010 +0000
+++ b/engine/core/video/fonts/fontbase.h	Thu Oct 21 18:50:50 2010 +0000
@@ -48,7 +48,9 @@
 	class FontBase: public AbstractFont {
 	public:
 		FontBase();
-		virtual ~FontBase() {}
+		virtual ~FontBase() {};
+
+		void invalidate();
 		void setRowSpacing (int spacing);
 		int getRowSpacing() const;
 		void setGlyphSpacing(int spacing);
@@ -56,15 +58,15 @@
 		void setAntiAlias(bool antiAlias);
 		bool isAntiAlias();
 		virtual int getStringIndexAt(const std::string &text, int x) const;
-		
+
 		Image* getAsImage(const std::string& text);
 		Image* getAsImageMultiline(const std::string& text);
 		std::string splitTextToWidth (const std::string& text, int render_width);
 
 		SDL_Color getColor() const;
-		
-		virtual SDL_Surface* renderString(const std::string& text) = 0;		
-		
+
+		virtual SDL_Surface* renderString(const std::string& text) = 0;
+
 	protected:
 		TextRenderPool m_pool;
 
--- a/engine/core/video/fonts/textrenderpool.cpp	Fri Oct 15 18:54:34 2010 +0000
+++ b/engine/core/video/fonts/textrenderpool.cpp	Thu Oct 21 18:50:50 2010 +0000
@@ -130,4 +130,12 @@
 		if( m_poolSize == 0 )
 			m_collectTimer.stop();
 	}
+
+	void TextRenderPool::invalidateCachedText() {
+		type_pool::iterator it = m_pool.begin();
+		while (it != m_pool.end()) {
+			it->image->invalidate();
+			++it;
+		}
+	}
 }
--- a/engine/core/video/fonts/textrenderpool.h	Fri Oct 15 18:54:34 2010 +0000
+++ b/engine/core/video/fonts/textrenderpool.h	Thu Oct 21 18:50:50 2010 +0000
@@ -61,6 +61,10 @@
 			 */
 			~TextRenderPool();
 
+			/** Invalidates all cached text images
+			 */
+			void invalidateCachedText();
+
 			/** Get a string image
 			 */
 			Image* getRenderedText( FontBase* fontbase, const std::string& text);
--- a/engine/core/video/image.h	Fri Oct 15 18:54:34 2010 +0000
+++ b/engine/core/video/image.h	Thu Oct 21 18:50:50 2010 +0000
@@ -146,6 +146,10 @@
 		 */
 		Image(const uint8_t* data, unsigned int width, unsigned int height);
 
+		/** Invalidates the Image causing it to be reset or re-loaded
+		 */
+		virtual void invalidate() = 0;
+
 		/** Renders itself to the Destination surface at the rectangle rect.
 		 *
 		 * @param rect The position and clipping where to draw this image to.
--- a/engine/core/video/imagepool.h	Fri Oct 15 18:54:34 2010 +0000
+++ b/engine/core/video/imagepool.h	Thu Oct 21 18:50:50 2010 +0000
@@ -50,6 +50,16 @@
 		 */
 		virtual ~ImagePool() {}
 
+		void invalidateLoadedImages() {
+			std::vector<PoolEntry*>::iterator it;
+			for (it = m_entries.begin(); it != m_entries.end(); it++) {
+				PoolEntry* entry = *it;
+				if( entry->resource) {
+					static_cast<Image*>(entry->resource)->invalidate();
+				}
+			}
+		}
+
 		inline Image& getImage(unsigned int index)  {
 			return static_cast<Image&>(get(index));
 		}
--- a/engine/core/video/opengl/glimage.cpp	Fri Oct 15 18:54:34 2010 +0000
+++ b/engine/core/video/opengl/glimage.cpp	Thu Oct 21 18:50:50 2010 +0000
@@ -62,6 +62,10 @@
 		cleanup();
 	}
 
+	void GLImage::invalidate() {
+		resetGlimage();
+	}
+
 	void GLImage::resetGlimage() {
 		cleanup();
 
--- a/engine/core/video/opengl/glimage.h	Fri Oct 15 18:54:34 2010 +0000
+++ b/engine/core/video/opengl/glimage.h	Thu Oct 21 18:50:50 2010 +0000
@@ -60,6 +60,7 @@
 		GLImage(SDL_Surface* surface);
 		GLImage(const uint8_t* data, unsigned int width, unsigned int height);
 		virtual ~GLImage();
+		void invalidate();
 		void render(const Rect& rect, SDL_Surface* dst, unsigned char alpha = 255);
 		void saveImage(const std::string& filename);
  		bool putPixel(int x, int y, int r, int g, int b, int a = 255);
--- a/engine/core/video/opengl/renderbackendopengl.cpp	Fri Oct 15 18:54:34 2010 +0000
+++ b/engine/core/video/opengl/renderbackendopengl.cpp	Thu Oct 21 18:50:50 2010 +0000
@@ -76,16 +76,6 @@
 	}
 
 	Image* RenderBackendOpenGL::createMainScreen(const ScreenMode& mode, const std::string& title, const std::string& icon){
-		m_screenMode = mode;
-		unsigned int width = mode.getWidth();
-		unsigned int height = mode.getHeight();
-		unsigned char bitsPerPixel = mode.getBPP();
-		bool fs = mode.isFullScreen();
-		Uint32 flags = mode.getSDLFlags();
-
-		delete m_screen;
-		m_screen = 0;
-
 		if(icon != "") {
 			SDL_Surface *img = IMG_Load(icon.c_str());
 			if(img != NULL) {
@@ -93,31 +83,32 @@
 			}
 		}
 
+		Image *image = setScreenMode(mode);
+
+		SDL_WM_SetCaption(title.c_str(), 0);
+
+		return image;
+	}
+
+	Image* RenderBackendOpenGL::setScreenMode(const ScreenMode& mode) {
+		uint16_t width = mode.getWidth();
+		uint16_t height = mode.getHeight();
+		uint16_t bitsPerPixel = mode.getBPP();
+		bool fs = mode.isFullScreen();
+		uint32_t flags = mode.getSDLFlags();
+
 		SDL_Surface* screen = NULL;
 
-		if( 0 == bitsPerPixel ) {
-			/// autodetect best mode
-			unsigned char possibleBitsPerPixel[] = {32, 24, 16, 0};
-			int i = 0;
-			while( true ) {
-				bitsPerPixel = possibleBitsPerPixel[i];
-				if( !bitsPerPixel ) {
-					throw SDLException("Videomode not available");
-				}
+		if (bitsPerPixel != 0) {
+			uint16_t bpp = SDL_VideoModeOK(width, height, bitsPerPixel, flags);
+			if (!bpp){
+				throw SDLException("Selected video mode not supported!");
+			}
+		}
 
-				if ( SDL_VideoModeOK(width, height, bitsPerPixel, flags) ) {
-					screen = SDL_SetVideoMode(width, height, bitsPerPixel, flags);
-					if( screen ) {
-						break;
-					}
-				}
-				++i;
-			}
-		} else {
-			if ( !SDL_VideoModeOK(width, height, bitsPerPixel, flags) ) {
-				throw SDLException("Videomode not available");
-			}
-			screen = SDL_SetVideoMode(width, height, bitsPerPixel, flags);
+		screen = SDL_SetVideoMode(width, height, bitsPerPixel, flags);
+		if( !screen ) {
+			throw SDLException("Unable to set video mode selected!");
 		}
 
 		FL_LOG(_log, LMsg("RenderBackendOpenGL")
@@ -125,13 +116,11 @@
 			<< " at " << int(bitsPerPixel) << " bpp");
 
 		//update the screen mode with the actual flags used
-
-		m_screenMode = ScreenMode(m_screenMode.getWidth(),
-		                          m_screenMode.getHeight(),
-		                          m_screenMode.getBPP(),
+		m_screenMode = ScreenMode(width,
+		                          height,
+		                          bitsPerPixel,
 		                          screen->flags);
 
-		SDL_WM_SetCaption(title.c_str(), 0);
 
 		if (!screen) {
 			throw SDLException(SDL_GetError());
@@ -152,10 +141,12 @@
 		glPointSize(1.0);
 		glLineWidth(1.0);
 
+		delete m_screen;
 		m_screen = new GLImage(screen);
 		return m_screen;
 	}
 
+
 	void RenderBackendOpenGL::startFrame() {
 		if(m_clear) {
 			clearBackBuffer();
--- a/engine/core/video/opengl/renderbackendopengl.h	Fri Oct 15 18:54:34 2010 +0000
+++ b/engine/core/video/opengl/renderbackendopengl.h	Thu Oct 21 18:50:50 2010 +0000
@@ -50,6 +50,7 @@
 		void clearBackBuffer();
 
 		Image* createMainScreen(const ScreenMode& mode, const std::string& title, const std::string& icon);
+		Image*  setScreenMode(const ScreenMode& mode);
 		Image* createImage(const uint8_t* data, unsigned int width, unsigned int height);
 		Image* createImage(SDL_Surface* surface);
  		bool putPixel(int x, int y, int r, int g, int b, int a = 255);
--- a/engine/core/video/renderbackend.h	Fri Oct 15 18:54:34 2010 +0000
+++ b/engine/core/video/renderbackend.h	Thu Oct 21 18:50:50 2010 +0000
@@ -92,6 +92,12 @@
 		 */
 		virtual Image* createMainScreen(const ScreenMode& mode, const std::string& title, const std::string& icon) = 0;
 
+		/** Sets the mainscreen display mode.
+		 * @param mode The ScreenMode to change the display to.  @see FIFE::ScreenMode.
+		 * @return The new Screen Image
+		 */
+		virtual Image* setScreenMode(const ScreenMode& mode) = 0;
+
 		/** Creates an Image suitable for this renderbackend.
 		 * @param data Pointer to the imagedata (needs to be in RGBA, 8 bits per channel).
 		 * @param width Width of the image.
@@ -118,7 +124,8 @@
 
 		SDL_Surface* getSurface();
 
-		/** Get current video mode
+		/** Get current screen mode
+		 * @return The current screen mode
 		 */
 		const ScreenMode& getCurrentScreenMode() const;
 
--- a/engine/core/video/sdl/renderbackendsdl.cpp	Fri Oct 15 18:54:34 2010 +0000
+++ b/engine/core/video/sdl/renderbackendsdl.cpp	Thu Oct 21 18:50:50 2010 +0000
@@ -80,13 +80,6 @@
 	}
 
 	Image* RenderBackendSDL::createMainScreen(const ScreenMode& mode, const std::string& title, const std::string& icon){
-		m_screenMode = mode;
-		unsigned int width = mode.getWidth();
-		unsigned int height = mode.getHeight();
-		unsigned char bitsPerPixel = mode.getBPP();
-		bool fs = mode.isFullScreen();
-		Uint32 flags = mode.getSDLFlags();
-
 		if(icon != "") {
 			SDL_Surface *img = IMG_Load(icon.c_str());
 			if(img != NULL) {
@@ -94,55 +87,49 @@
 			}
 		}
 
+		Image *image = setScreenMode(mode);
+
+		SDL_WM_SetCaption(title.c_str(), 0);
+
+		return image;
+	}
+
+	Image* RenderBackendSDL::setScreenMode(const ScreenMode& mode) {
+		uint16_t width = mode.getWidth();
+		uint16_t height = mode.getHeight();
+		uint16_t bitsPerPixel = mode.getBPP();
+		bool fs = mode.isFullScreen();
+		uint32_t flags = mode.getSDLFlags();
+
 		SDL_Surface* screen = NULL;
 
-		if( 0 == bitsPerPixel ) {
-			/// autodetect best mode
-			unsigned char possibleBitsPerPixel[] = {16, 24, 32, 0};
-			int i = 0;
-			while( true ) {
-				bitsPerPixel = possibleBitsPerPixel[i];
-				if( !bitsPerPixel ) {
-					// Last try, sometimes VideoModeOK seems to lie.
-					// Try bpp=0
-					screen = SDL_SetVideoMode(width, height, bitsPerPixel, flags);
-					if( !screen ) {
-						throw SDLException("Videomode not available");
-					}
-					break;
-				}
-				bitsPerPixel = SDL_VideoModeOK(width, height, bitsPerPixel, flags);
-				if ( bitsPerPixel ) {
-					screen = SDL_SetVideoMode(width, height, bitsPerPixel, flags);
-					if( screen ) {
-						break;
-					}
-				}
-				++i;
+		if (bitsPerPixel != 0) {
+			uint16_t bpp = SDL_VideoModeOK(width, height, bitsPerPixel, flags);
+			if (!bpp){
+				throw SDLException("Selected video mode not supported!");
 			}
-		} else {
-			if ( !SDL_VideoModeOK(width, height, bitsPerPixel, flags) ) {
-				throw SDLException("Videomode not available");
-			}
-			screen = SDL_SetVideoMode(width, height, bitsPerPixel, flags);
 		}
+
+		screen = SDL_SetVideoMode(width, height, bitsPerPixel, flags);
+		if( !screen ) {
+			throw SDLException("Unable to set video mode selected!");
+		}
+
 		FL_LOG(_log, LMsg("RenderBackendSDL")
 			<< "Videomode " << width << "x" << height
 			<< " at " << int(screen->format->BitsPerPixel) << " bpp");
 
 		//update the screen mode with the actual flags used
-
-		m_screenMode = ScreenMode(m_screenMode.getWidth(),
-		                          m_screenMode.getHeight(),
-		                          m_screenMode.getBPP(),
+		m_screenMode = ScreenMode(width,
+		                          height,
+		                          bitsPerPixel,
 		                          screen->flags);
 
-		SDL_WM_SetCaption(title.c_str(), NULL);
-
 		if (!screen) {
 			throw SDLException(SDL_GetError());
 		}
 
+		delete m_screen;
 		m_screen = new SDLImage(screen);
 		return m_screen;
 	}
--- a/engine/core/video/sdl/renderbackendsdl.h	Fri Oct 15 18:54:34 2010 +0000
+++ b/engine/core/video/sdl/renderbackendsdl.h	Thu Oct 21 18:50:50 2010 +0000
@@ -52,6 +52,7 @@
 		void clearBackBuffer();
 
 		Image* createMainScreen(const ScreenMode& mode, const std::string& title, const std::string& icon);
+		Image* setScreenMode(const ScreenMode& mode);
 		Image* createImage(const uint8_t* data, unsigned int width, unsigned int height);
 		Image* createImage(SDL_Surface* surface);
  		bool putPixel(int x, int y, int r, int g, int b, int a = 255);
--- a/engine/core/video/sdl/sdlimage.h	Fri Oct 15 18:54:34 2010 +0000
+++ b/engine/core/video/sdl/sdlimage.h	Thu Oct 21 18:50:50 2010 +0000
@@ -42,6 +42,7 @@
 		SDLImage(SDL_Surface* surface);
 		SDLImage(const uint8_t* data, unsigned int width, unsigned int height);
 		virtual ~SDLImage();
+		void invalidate() {}; //do nothing for SDL images (for now)
 		void render(const Rect& rect, SDL_Surface* dst, unsigned char alpha = 255);
 		void saveImage(const std::string& filename);
  		bool putPixel(int x, int y, int r, int g, int b, int a = 255);
--- a/engine/core/video/video.i	Fri Oct 15 18:54:34 2010 +0000
+++ b/engine/core/video/video.i	Thu Oct 21 18:50:50 2010 +0000
@@ -155,6 +155,7 @@
 	public:
 		virtual ~RenderBackend();
 		virtual const std::string& getName() const = 0;
+		
 		Image* getScreenImage() const { return m_screen; };
 		void captureScreen(const std::string& filename);
 		SDL_Surface* getSurface();
@@ -258,6 +259,7 @@
 
 		void fillDeviceCaps();
 		std::vector<ScreenMode> getSupportedScreenModes() const;
+		ScreenMode getNearestScreenMode(uint16_t width, uint16_t height, uint16_t bpp, const std::string& renderer, bool fs) const;
 		std::string getDriverName() const;
 		std::vector<string> getAvailableDrivers() const;
 		bool isHwSurfaceAvail() const;