← Back to team overview

widelands-dev team mailing list archive

[Merge] lp:~nha/widelands/graphics-refactor into lp:widelands

 

Nicolai Hähnle has proposed merging lp:~nha/widelands/graphics-refactor into lp:widelands.

Requested reviews:
  Widelands Developers (widelands-dev)


This merge contains a pretty huge refactoring that attempts to clarify the meaning of surfaces vs. pictures, and enforce it via the C++ type system.

>From now on Pictures are things that can act as blit sources, while Surfaces are things that can act as blit destinations. In SDL mode, everything is both a Picture and a Surface; in OpenGL mode, this is not the case.

As a side-effect, this also fixes the scaling of menu backgrounds in OpenGL mode.

It's a pretty huge change, which is why I didn't want to commit it immediately. Some more testing is a good idea, and I didn't want to mess with people who are playing this weekend.
-- 
https://code.launchpad.net/~nha/widelands/graphics-refactor/+merge/42016
Your team Widelands Developers is requested to review the proposed merge of lp:~nha/widelands/graphics-refactor into lp:widelands.
=== modified file 'src/CMakeLists.txt'
--- src/CMakeLists.txt	2010-11-07 22:42:19 +0000
+++ src/CMakeLists.txt	2010-11-27 16:29:59 +0000
@@ -54,7 +54,7 @@
     add_executable (widelands ${GUI_TYPE} main.cc build_info.cc ${WIN32_ICON_O})
   else (DEFINED MINGW)
     add_executable (widelands ${GUI_TYPE} main.cc build_info.cc)
-  endif (DEFINED MINGW) 
+  endif (DEFINED MINGW)
 endif (DEFINED MSVC)
 
 add_library (widelands_all ${WL_SRCS_CC} ${WL_SRCS_H})
@@ -72,7 +72,7 @@
     if (WIN32)
       string(REGEX REPLACE "^.*:" "" sourcenoslash ${sourcenoslash})
     endif (WIN32)
-    get_filename_component(sourcename ${sourcefile} NAME) 
+    get_filename_component(sourcename ${sourcefile} NAME)
     set(stamp ${sourcename}_)
     add_custom_command(
       OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/codecheck_${sourcenoslash}"
@@ -151,7 +151,7 @@
 
   else (DEFINED MSVC)
     target_link_libraries(widelands wsock32)
-  endif (DEFINED MSVC) 
+  endif (DEFINED MSVC)
 endif (WIN32)
 
 install(TARGETS widelands DESTINATION ${WLBUILD_INSTALL_BINDIR} COMPONENT ExecutableFiles)

=== modified file 'src/editor/ui_menus/editor_tool_set_terrain_options_menu.cc'
--- src/editor/ui_menus/editor_tool_set_terrain_options_menu.cc	2010-11-01 22:30:23 +0000
+++ src/editor/ui_menus/editor_tool_set_terrain_options_menu.cc	2010-11-27 16:29:59 +0000
@@ -94,7 +94,7 @@
 				pos.y += TEXTURE_HEIGHT + vspacing();
 			}
 
-			PictureID surface;
+			PictureID picture;
 
 			// If offscreen rendering is not available only the terrain (and not
 			// the terrain type) is shown.
@@ -102,11 +102,11 @@
 			//       or implement offscreen rendering for opengl
 			if (g_gr->caps().offscreen_rendering)
 			{
-				//  create a surface for this
-				surface = g_gr->create_picture_surface(64, 64);
+				OffscreenSurfacePtr offscreen = g_gr->create_offscreen_surface(64, 64);
+				picture = g_gr->get_offscreen_picture(offscreen);
 
 				//  get the rendertarget for this
-				RenderTarget & target = *g_gr->get_surface_renderer(surface);
+				RenderTarget target(offscreen);
 
 				//  first, blit the terrain texture
 				target.blit
@@ -144,16 +144,16 @@
 						target.blit(pic, dry);
 				}
 			} else {
-				surface = g_gr->get_picture
+				picture = g_gr->get_picture
 					(PicMod_Game,
 					 g_gr->get_maptexture_data(world.terrain_descr(i).get_texture())
 					 ->get_texture_picture());
 			}
 
 			//  Save this surface, so we can free it later on.
-			m_surfaces.push_back(surface);
+			m_surfaces.push_back(picture);
 
-			UI::Checkbox & cb = *new UI::Checkbox(this, pos, surface);
+			UI::Checkbox & cb = *new UI::Checkbox(this, pos, picture);
 			cb.set_size(TEXTURE_WIDTH + 1, TEXTURE_HEIGHT + 1);
 			cb.set_id(i);
 			cb.set_state(m_tool.is_enabled(i));
@@ -185,9 +185,8 @@
 }
 
 
-Editor_Tool_Set_Terrain_Options_Menu::~Editor_Tool_Set_Terrain_Options_Menu() {
-	container_iterate_const(std::vector<PictureID>, m_surfaces, i)
-		g_gr->free_picture_surface(*i.current);
+Editor_Tool_Set_Terrain_Options_Menu::~Editor_Tool_Set_Terrain_Options_Menu()
+{
 }
 
 

=== modified file 'src/graphic/animation_gfx.h'
--- src/graphic/animation_gfx.h	2010-11-10 20:05:21 +0000
+++ src/graphic/animation_gfx.h	2010-11-27 16:29:59 +0000
@@ -22,23 +22,22 @@
 
 #include "animation.h"
 #include "logic/widelands.h"
+#include "picture_id.h"
 #include "rgbcolor.h"
 
-struct Surface;
-
 struct AnimationGfx { /// The graphics belonging to an animation.
 	AnimationGfx(AnimationData const * data);
 	~AnimationGfx();
 
 	const Point get_hotspot() const throw () {return m_hotspot;}
-	typedef std::vector<Surface *> Frames;
+	typedef std::vector<PictureID> Frames;
 	typedef Frames::size_type Index;
 	Index nr_frames() const
 	{
 		assert((*m_plrframes)[0]); return m_plrframes[0].size();
 	}
 
-	Surface * get_frame
+	const PictureID & get_frame
 		(Index                    const i,
 		 Widelands::Player_Number const player_number,
 		 RGBColor         const * const playercolor)
@@ -56,7 +55,7 @@
 		return m_plrframes[player_number][i];
 	}
 
-	Surface * get_frame(Index const i) const {
+	const PictureID & get_frame(Index const i) const {
 		assert(i < nr_frames());
 		return m_plrframes[0][i];
 	}

=== added file 'src/graphic/compositemode.h'
--- src/graphic/compositemode.h	1970-01-01 00:00:00 +0000
+++ src/graphic/compositemode.h	2010-11-27 16:29:59 +0000
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2010 by the Widelands Development Team
+ *
+ * This program 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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef COMPOSITEMODE_H
+#define COMPOSITEMODE_H
+
+/**
+ * Defines composition operations performed while blitting.
+ */
+enum Composite {
+	/**
+	 * Perform a normal blitting operation that respects the alpha
+	 * channel if present.
+	 */
+	CM_Normal = 0,
+
+	/**
+	 * Perform a solid blit that ignores the alpha channel information.
+	 */
+	CM_Solid,
+
+	/**
+	 * Copy all pixel information, including alpha channel information.
+	 */
+	CM_Copy
+};
+
+#endif // COMPOSITEMODE_H

=== modified file 'src/graphic/font_handler.cc'
--- src/graphic/font_handler.cc	2010-11-01 22:37:46 +0000
+++ src/graphic/font_handler.cc	2010-11-27 16:29:59 +0000
@@ -32,7 +32,6 @@
 #include "rendertarget.h"
 #include "surface.h"
 #include "graphic/render/surface_sdl.h"
-#include "graphic/render/surface_opengl.h"
 
 #include <SDL_image.h>
 #include <SDL_ttf.h>
@@ -96,7 +95,7 @@
 	 Align               const align,
 	 uint32_t            const wrap,
 	 Widget_Cache        const widget_cache,
-	 PictureID         &       widget_cache_id,
+	 PictureID         *       widget_cache_id,
 	 uint32_t            const caret,
 	 bool                const transparent)
 {
@@ -124,20 +123,17 @@
 				m_cache.erase (i);
 			}
 		} else {
-			//not cached, create a new surface
+			//not cached, create a new surface and cache it
 			ci.picture_id =
 				create_text_surface
 					(font, fg, bg, text, align, wrap, 0, caret, transparent);
-			// Now cache it
-			assert(ci.picture_id->surface);
 			g_gr->get_picture_size(ci.picture_id, ci.w, ci.h);
 			ci.f = &font;
 			m_cache.push_front (ci);
 
-			while (m_cache.size() > CACHE_ARRAY_SIZE) {
-				g_gr->free_picture_surface(m_cache.back().picture_id);
+			while (m_cache.size() > CACHE_ARRAY_SIZE)
 				m_cache.pop_back();
-			}
+
 			//Set for alignment and blitting
 			picid = ci.picture_id;
 			w = ci.w;
@@ -145,16 +141,16 @@
 		}
 	} else if (widget_cache == Widget_Cache_Use) {
 		//  Widget gave us an explicit picid.
-		g_gr->get_picture_size(widget_cache_id, w, h);
-		picid = widget_cache_id;
-	} else { // We need to (re)create the picid for the widget.
-		if (widget_cache == Widget_Cache_Update)
-			g_gr->free_picture_surface(widget_cache_id);
-		widget_cache_id =
+		g_gr->get_picture_size(*widget_cache_id, w, h);
+		picid = *widget_cache_id;
+	} else {
+		// We need to (re)create the picid for the widget.
+		// The old picture is freed automatically
+		*widget_cache_id =
 			create_text_surface
 				(font, fg, bg, text, align, wrap, 0, caret, transparent);
-		g_gr->get_picture_size(widget_cache_id, w, h);
-		picid = widget_cache_id;
+		g_gr->get_picture_size(*widget_cache_id, w, h);
+		picid = *widget_cache_id;
 	}
 	do_align(align, dstpoint.x, dstpoint.y, w, h);
 	dst.blit(dstpoint, picid);
@@ -347,14 +343,11 @@
 	TTF_SizeUTF8(&font, text_caret_pos.c_str(), &caret_x, &caret_y);
 	caret_x += LINE_MARGIN;
 
-	Surface * const caret_surf =
-		g_gr->get_picture_surface
-			(g_gr->get_picture(PicMod_Game, "pics/caret.png"));
-
 	//TODO: Implement caret rendering for opengl
 	if (!g_opengl)
 	{
-		upcast(SurfaceSDL, sdlsurf, caret_surf);
+		PictureID caret = g_gr->get_picture(PicMod_Game, "pics/caret.png");
+		upcast(SurfaceSDL, sdlsurf, caret.get());
 		assert(sdlsurf);
 		SDL_Surface * const caret_surf_sdl = sdlsurf->get_sdl_surface();
 
@@ -421,16 +414,13 @@
 	 std::string          text,
 	 int32_t              wrap,
 	 Widget_Cache         widget_cache,
-	 PictureID    &       widget_cache_id,
+	 PictureID    *       widget_cache_id,
 	 bool           const transparent)
 {
 	PictureID picid;
 	if (widget_cache == Widget_Cache_Use)
-		picid = widget_cache_id;
+		picid = *widget_cache_id;
 	else {
-		if (widget_cache == Widget_Cache_Update) {
-			g_gr->free_picture_surface(widget_cache_id);
-		}
 		std::vector<Richtext_Block> blocks;
 		Text_Parser p;
 		p.parse(text, blocks);
@@ -473,19 +463,18 @@
 				img_pos.x = img_surf_w;
 				img_pos.y = 0;
 				if
-					(Surface * const image =
-					 g_gr->get_picture_surface //  Not Font, but Game.
-					 	(g_gr->get_picture(PicMod_Game, img_it->c_str())))
+					(PictureID const image =
+					 	g_gr->get_picture(PicMod_Game, *img_it))
 				{
 					img_surf_h =
 						img_surf_h < static_cast<int32_t>(image->get_h()) ?
 						image->get_h() : img_surf_h;
 					img_surf_w = img_surf_w + image->get_w();
 
-					upcast(SurfaceSDL, sdlsurf, image);
+					upcast(SurfaceSDL, sdlsurf, image.get());
 					if (sdlsurf)
 						rend_cur_images.push_back(sdlsurf->get_sdl_surface());
-
+					// TODO fix this for OpenGL
 				}
 			}
 			SDL_Surface * const block_images =
@@ -701,7 +690,7 @@
 			convert_sdl_surface
 				(*join_sdl_surfaces(wrap, global_h, rend_blocks, bg),
 				 bg, transparent);
-		widget_cache_id = picid;
+		*widget_cache_id = picid;
 	}
 	dst.blit(dstpoint, picid);
 }
@@ -813,11 +802,7 @@
 			(&surface, SDL_SRCCOLORKEY,
 			 SDL_MapRGB(surface.format, bg.r(), bg.g(), bg.b()));
 
-	Surface & surf = g_gr->create_surface(surface, transparent);
-
-	PictureID picid = g_gr->get_picture(PicMod_Font, surf);
-
-	return picid;
+	return g_gr->convert_sdl_surface_to_picture(&surface, transparent);
 }
 
 //Sets dstx and dsty to values for a specified align
@@ -846,15 +831,9 @@
 /*
  * Flushes the cached picture ids
  */
-void Font_Handler::flush_cache() {
-	while (!m_cache.empty()) {
-		g_gr->free_picture_surface (m_cache.front().picture_id);
-		m_cache.pop_front();
-	}
-}
-//Deletes widget controlled surface
-void Font_Handler::delete_widget_cache(PictureID const widget_cache_id) {
-	g_gr->free_picture_surface(widget_cache_id);
+void Font_Handler::flush_cache()
+{
+	m_cache.clear();
 }
 
 //Inserts linebreaks into a text, so it doesn't get bigger than max_width

=== modified file 'src/graphic/font_handler.h'
--- src/graphic/font_handler.h	2010-11-05 19:36:57 +0000
+++ src/graphic/font_handler.h	2010-11-27 16:29:59 +0000
@@ -56,7 +56,7 @@
 		 Align               align           = Align_CenterLeft,
 		 uint32_t            wrap         = std::numeric_limits<uint32_t>::max(),
 		 Widget_Cache        widget_cache    = Widget_Cache_None,
-		 PictureID         & widget_cache_id = g_gr->get_no_picture(),
+		 PictureID         * widget_cache_id = 0,
 		 uint32_t            caret        = std::numeric_limits<uint32_t>::max(),
 		 bool                transparent     = true);
 	void get_size
@@ -79,7 +79,6 @@
 	// from the graphics code before the graphics are flushed,
 	// to make sure that everything is forgotten
 	void flush_cache();
-	void delete_widget_cache(PictureID widget_cache_id);
 	void draw_richtext
 		(RenderTarget &,
 		 RGBColor bg,
@@ -87,7 +86,7 @@
 		 std::string text,
 		 int32_t wrap,
 		 Widget_Cache widget_cache = Widget_Cache_None,
-		 PictureID & widget_cache_id = g_gr->get_no_picture(),
+		 PictureID * widget_cache_id = 0,
 		 bool transparent = true);
 	void get_size_from_cache
 		(PictureID widget_cache_id, uint32_t & w, uint32_t & h);

=== modified file 'src/graphic/graphic.cc'
--- src/graphic/graphic.cc	2010-11-01 23:13:48 +0000
+++ src/graphic/graphic.cc	2010-11-27 16:29:59 +0000
@@ -32,11 +32,13 @@
 #include "io/streamwrite.h"
 
 #include "font_handler.h"
+#include "picture.h"
 #include "rendertarget.h"
 #include "texture.h"
 
 #include "render/surface_sdl.h"
-#include "render/surface_opengl.h"
+#include "render/gl_picture_texture.h"
+#include "render/gl_surface_screen.h"
 
 #include "logic/roadtype.h"
 #include "logic/widelands_fileread.h"
@@ -50,6 +52,7 @@
 
 #include <cstring>
 #include <iostream>
+#include <boost/scoped_array.hpp>
 
 Graphic * g_gr;
 bool g_opengl;
@@ -74,8 +77,6 @@
 	m_update_fullscreen(false),
 	m_roadtextures     (0)
 {
-	m_picturemap.resize(MaxModule);
-
 	// Initialize the table used to create grayed pictures
 	for
 		(uint32_t i = 0, r = 0, g = 0, b = 0;
@@ -150,9 +151,7 @@
 		log("Graphics: FULLSCREEN ENABLED\n");
 
 	// Set rendering capabilities for sdl. They are overwritten if in opengl mode
-	m_caps.resize_surfaces = true;
 	m_caps.offscreen_rendering = true;
-	m_caps.blit_resized = false;
 
 #ifdef USE_OPENGL
 	if (0 != (sdlsurface->flags & SDL_OPENGL)) {
@@ -199,9 +198,7 @@
 			(m_caps.gl.tex_power_of_two?"must have a size power of two\n":
 			 "may have any size\n");
 
-		m_caps.resize_surfaces = false;
 		m_caps.offscreen_rendering = false;
-		m_caps.blit_resized = true;
 	}
 #endif
 
@@ -280,13 +277,16 @@
 	}
 
 	if (g_opengl)
-		m_screen = new SurfaceOpenGL(w, h);
+	{
+		m_screen.reset(new GLSurfaceScreen(w, h));
+	}
 	else
 #endif
 	{
-		m_screen = new SurfaceSDL(*sdlsurface);
+		boost::shared_ptr<SurfaceSDL> screen(new SurfaceSDL(*sdlsurface));
+		screen->set_isscreen(true);
+		m_screen = screen;
 	}
-	m_screen->set_type(SURFACE_SCREEN);
 
 	m_sdl_screen = sdlsurface;
 	m_rendertarget = new RenderTarget(m_screen);
@@ -297,12 +297,11 @@
 */
 Graphic::~Graphic()
 {
-	for (size_t i = 1; i < m_picturemap.size(); ++i)
-		flush(static_cast<PicMod>(i));
-
 	delete m_rendertarget;
-	delete m_screen;
 	delete m_roadtextures;
+
+	// Remove traces of cached pictures
+	UI::g_fh->flush_cache();
 }
 
 /**
@@ -401,33 +400,27 @@
 }
 
 /**
- * Remove all resources (currently pictures) from the given modules.
- * \note flush(0) does nothing <- obviously wrong it deletes a lot!
-*/
-void Graphic::flush(PicMod const module) {
-	// Flush pictures
-
-	//pmit b, e = m_picturemap.end();
-	for (size_t i = 0; i < m_picturemap.size(); ++i) {
-		if (static_cast<PicMod>(i) == module) {
-			m_picturemap[i].clear();
-		}
-	}
-
-	if (!module || module & PicMod_Game) {
-		container_iterate_const(std::vector<Texture *>, m_maptextures, i)
-			delete *i.current;
-		m_maptextures.clear();
-
-		container_iterate_const(std::vector<AnimationGfx *>, m_animations, i)
-			delete *i.current;
-		m_animations.clear();
-
-		delete m_roadtextures;
-		m_roadtextures = 0;
-	}
-
-	if (not module or module & PicMod_UI) // Flush the cached Fontdatas
+ * Clear all cached resources from the given module.
+ *
+ * \note This only removes the cache entries. If the corresonding resources
+ * are still in use somewhere, they will not be freed.
+ */
+void Graphic::flush(PicMod const module)
+{
+	std::vector<std::string> eraselist;
+
+	for (pmit it = m_picturemap.begin(); it != m_picturemap.end(); ++it) {
+		it->second.modules &= ~(1 << module);
+		if (!it->second.modules)
+			eraselist.push_back(it->first);
+	}
+
+	while (!eraselist.empty()) {
+		m_picturemap.erase(eraselist.back());
+		eraselist.pop_back();
+	}
+
+	if (module == PicMod_UI) // Flush the cached Fontdatas
 		UI::g_fh->flush_cache();
 }
 
@@ -440,7 +433,7 @@
 }
 
 
-Surface & Graphic::load_image(std::string const & fname, bool const alpha) {
+PictureID Graphic::load_image(std::string const & fname, bool const alpha) {
 	//log("Graphic::LoadImage(\"%s\")\n", fname.c_str());
 	FileRead fr;
 	SDL_Surface * sdlsurf;
@@ -453,9 +446,7 @@
 	if (!sdlsurf)
 		throw wexception("%s", IMG_GetError());
 
-	Surface & surf = create_surface(*sdlsurf, alpha);
-
-	return surf;
+	return convert_sdl_surface_to_picture(sdlsurf, alpha);
 }
 
 /**
@@ -465,171 +456,192 @@
  *
  * \return 0 (a null-picture) if the picture cannot be loaded.
 */
-PictureID & Graphic::get_picture
+const PictureID & Graphic::get_picture
 	(PicMod const module, const std::string & fname, bool alpha)
 {
 	//  Check if the picture is already loaded.
-	pmit it = m_picturemap[module].find(fname);
+	pmit it = m_picturemap.find(fname);
 
-	if (it != m_picturemap[module].end()) {
-		return it->second;
-	} else {
-		Surface * surf;
+	if (it == m_picturemap.end()) {
+		PictureRec rec;
 
 		try {
-			surf = &load_image(fname, alpha);
+			rec.picture = load_image(fname, alpha);
 			//log("Graphic::get_picture(): loading picture '%s'\n", fname.c_str());
 		} catch (std::exception const & e) {
 			log("WARNING: Could not open %s: %s\n", fname.c_str(), e.what());
 			return get_no_picture();
 		}
-		// Convert the surface accordingly
-
-		// Fill in a free slot in the pictures array
-		Picture & pic = * new Picture();
-		PictureID id = PictureID(&pic);
-		m_picturemap[module].insert(std::make_pair(fname, id));
-
-		assert(pic.fname == 0);
-		pic.fname = strdup(fname.c_str());
-
-		//  FIXME no proper check for NULL return value!
-		assert(pic.fname != 0);
-
-		pic.surface = surf;
-
-		it = m_picturemap[module].find(fname);
+
+		it = m_picturemap.insert(std::make_pair(fname, rec)).first;
 	}
 
-	it->second->module = module;
-
-	return it->second;
-}
-
-PictureID Graphic::get_picture
-	(PicMod const module, Surface & surf, std::string const & fname)
-{
-	Picture & pic = * new Picture();
-	PictureID id = PictureID(&pic);
-	m_picturemap[module].insert(std::make_pair(fname, id));
-
-	pic.module    = module;
-	pic.surface   = &surf;
-
-	if (fname.size() != 0) {
-		assert(pic.fname == 0);
-		pic.fname = strdup(fname.c_str());
-	} else
-		pic.fname = 0;
-
-	//return m_picturemap.find(fname);
-	return id;
-}
-
-PictureID & Graphic::get_no_picture() const {
-	static PictureID invalid = PictureID(new Picture());
-	return invalid;
+	it->second.modules |= 1 << module;
+	return it->second.picture;
+}
+
+/**
+ * Add the given picture to the cache under the given name.
+ *
+ * This overwrites pre-existing cache entries, if any.
+ */
+void Graphic::add_picture_to_cache(PicMod module, const std::string & name, PictureID pic)
+{
+	PictureRec rec;
+	rec.picture = pic;
+	rec.modules = 1 << module;
+	m_picturemap.insert(std::make_pair(name, rec));
+}
+
+/**
+ * \return an empty, invalid, null picture
+ */
+const PictureID & Graphic::get_no_picture() const
+{
+	return IPicture::null();
 }
 
 /**
  * Produces a resized version of the specified picture
  *
- * This might not work with the renderer. Check g_gr->caps().resize_surfaces
- * to be sure the resizing is possible.
  * Might return same id if dimensions are the same
  */
 PictureID Graphic::get_resized_picture
-	(PictureID index,
+	(PictureID src,
 	 uint32_t const w, uint32_t const h,
 	 ResizeMode const mode)
 {
-	// Resizing is not possible with opengl surfaces
-	if (g_opengl)
-		g_gr->get_no_picture();
-
-	Surface * const orig = index->surface;
-	if (orig->get_w() == w and orig->get_h() == h)
-		return index;
-
-	uint32_t width = w;
-	uint32_t height = h;
-
-	if (mode != ResizeMode_Loose) {
-		const double ratio_x = double(w) / orig->get_w();
-		const double ratio_y = double(h) / orig->get_h();
-
-		//  if proportions are to be kept, recalculate width and height
-		if ((ratio_x - ratio_y) > 0.00001) { //  if not equal
-			double ratio = 0;
-
-			if (ResizeMode_Clip == mode)
-				ratio = std::max (ratio_x, ratio_y);
-			else if (ResizeMode_LeaveBorder == mode)
-				ratio = std::max (ratio_x, ratio_y);
-			else // average
-				ratio = (ratio_x + ratio_y) / 2;
-
-			width = uint32_t(orig->get_w() * ratio);
-			height = uint32_t(orig->get_h() * ratio);
+	if (src->get_w() == w and src->get_h() == h)
+		return src;
+
+	// First step: compute scaling factors
+	Rect srcrect;
+	Rect destrect;
+
+	if (mode == ResizeMode_Loose) {
+		srcrect = Rect(Point(0, 0), src->get_w(), src->get_h());
+		destrect = Rect(Point(0, 0), w, h);
+	} else {
+		const double ratio_x = double(w) / src->get_w();
+		const double ratio_y = double(h) / src->get_h();
+		double ratio;
+
+		if (ResizeMode_Clip == mode)
+			ratio = std::max(ratio_x, ratio_y);
+		else if (ResizeMode_LeaveBorder == mode)
+			ratio = std::min(ratio_x, ratio_y);
+		else // average
+			ratio = (ratio_x + ratio_y) / 2;
+
+		uint32_t fullwidth(src->get_w() * ratio);
+		uint32_t fullheight(src->get_h() * ratio);
+
+		if (fullwidth <= w) {
+			srcrect.x = 0;
+			srcrect.w = src->get_w();
+			destrect.x = (w - fullwidth) / 2;
+			destrect.w = fullwidth;
+		} else {
+			srcrect.w = std::min(src->get_w(), uint32_t(w / ratio));
+			srcrect.x = (src->get_w() - srcrect.w) / 2;
+			destrect.x = 0;
+			destrect.w = w;
+		}
+
+		if (fullheight <= h) {
+			srcrect.y = 0;
+			srcrect.h = src->get_h();
+			destrect.y = (h - fullheight) / 2;
+			destrect.h = fullheight;
+		} else {
+			srcrect.h = std::min(src->get_h(), uint32_t(h / ratio));
+			srcrect.y = (src->get_h() - srcrect.h) / 2;
+			destrect.y = 0;
+			destrect.h = h;
 		}
 	}
 
-	PictureID pic = g_gr->create_picture_surface(w, h);
+	// Second step: get source material
+	SDL_Surface * srcsdl = 0;
+	bool free_source = true;
 
-	if (mode == ResizeMode_Loose || (width == w && height == h)) {
-		if (g_opengl)
+	if (upcast(SurfaceSDL, srcsurf, src.get())) {
+		if
+			(srcrect.x != 0 || srcrect.w != uint32_t(srcsurf->get_w()) ||
+			 srcrect.y != 0 || srcrect.h != uint32_t(srcsurf->get_h()))
 		{
+			const SDL_PixelFormat & fmt = *srcsurf->get_sdl_surface()->format;
+			srcsdl = SDL_CreateRGBSurface
+				(SDL_SWSURFACE, srcrect.w, srcrect.h,
+				 fmt.BitsPerPixel, fmt.Rmask, fmt.Gmask, fmt.Bmask, fmt.Amask);
+			SDL_Rect srcrc = {srcrect.x, srcrect.y, srcrect.w, srcrect.h};
+			SDL_Rect dstrc = {0, 0, 0, 0};
+			SDL_BlitSurface(srcsurf->get_sdl_surface(), &srcrc, srcsdl, &dstrc);
 		} else {
-			dynamic_cast<SurfaceSDL *>
-				(pic->surface)->set_sdl_surface(*resize(index, w, h));
+			srcsdl = srcsurf->get_sdl_surface();
+			free_source = false;
 		}
 	} else {
-		SurfaceSDL src(*resize(index, width, height));
-
-		// apply rectangle by adjusted size
-		Rect srcrc;
-		srcrc.w = std::min(w, width);
-		srcrc.h = std::min(h, height);
-		srcrc.x = (width - srcrc.w) / 2;
-		srcrc.y = (height - srcrc.h) / 2;
-
-
-		g_gr->get_surface_renderer(pic)->blitrect //  Get the rendertarget
-			(Point((w - srcrc.w) / 2, (h - srcrc.h) / 2),
-			 get_picture(index->module, src), srcrc);
-	}
-	return pic;
+		srcsdl = extract_sdl_surface(src->pixelaccess(), srcrect);
+	}
+
+	// Third step: perform the zoom and placement
+	SDL_Surface * zoomed = zoomSurface
+		(srcsdl, double(destrect.w) / srcsdl->w, double(destrect.h) / srcsdl->h, 1);
+	if (free_source)
+		SDL_FreeSurface(srcsdl);
+
+	if (uint32_t(zoomed->w) != w || uint32_t(zoomed->h) != h) {
+		const SDL_PixelFormat & fmt = *zoomed->format;
+		SDL_Surface * placed = SDL_CreateRGBSurface
+			(SDL_SWSURFACE, w, h,
+			 fmt.BitsPerPixel, fmt.Rmask, fmt.Gmask, fmt.Bmask, fmt.Amask);
+		SDL_Rect srcrc = {0, 0, zoomed->w, zoomed->h};
+		SDL_Rect dstrc = {destrect.x, destrect.y};
+		SDL_BlitSurface(zoomed, &srcrc, placed, &dstrc);
+		SDL_FreeSurface(zoomed);
+		zoomed = placed;
+	}
+
+	return convert_sdl_surface_to_picture(zoomed);
 }
 
 /**
- * Produces a resized version of the specified picture. This works only for
- * SDL rendering. Check g_gr->caps().resize_surfaces before calling this
- * function.
- *
- * \param index position of the source picture in the stack
- * \param w target width
- * \param h target height
- * \return resized version of picture
+ * Create and return an \ref SDL_Surface that contains the given sub-rectangle
+ * of the given pixel region.
  */
-SDL_Surface * Graphic::resize
-	(const PictureID index, uint32_t const w, uint32_t const h)
+SDL_Surface * Graphic::extract_sdl_surface(IPixelAccess & pix, Rect srcrect)
 {
-	Surface & orig = *g_gr->get_picture_surface(index);
-
-	if (g_opengl)
-		throw wexception("Graphic::resize() not yet implemented for opengl");
-	else
-	{
-		SurfaceSDL & origsdl = dynamic_cast<SurfaceSDL &>(orig);
-		return
-			zoomSurface
-				(origsdl.get_sdl_surface(),
-				 double(w) / orig.get_w(), double(h) / orig.get_h(),
-				 1);
+	assert(srcrect.x >= 0);
+	assert(srcrect.y >= 0);
+	assert(srcrect.x + srcrect.w <= pix.get_w());
+	assert(srcrect.y + srcrect.h <= pix.get_h());
+
+	const SDL_PixelFormat & fmt = pix.format();
+	SDL_Surface * dest = SDL_CreateRGBSurface
+		(SDL_SWSURFACE, srcrect.w, srcrect.h,
+		 fmt.BitsPerPixel, fmt.Rmask, fmt.Gmask, fmt.Bmask, fmt.Amask);
+
+	pix.lock(IPixelAccess::Lock_Normal);
+	SDL_LockSurface(dest);
+
+	uint32_t srcpitch = pix.get_pitch();
+	uint32_t rowsize = srcrect.w * fmt.BytesPerPixel;
+	uint8_t * srcpix = pix.get_pixels() + srcpitch * srcrect.y + fmt.BytesPerPixel * srcrect.x;
+	uint8_t * dstpix = static_cast<uint8_t *>(dest->pixels);
+
+	for (uint32_t y = 0; y < srcrect.h; ++y) {
+		memcpy(dstpix, srcpix, rowsize);
+		srcpix += srcpitch;
+		dstpix += dest->pitch;
 	}
+
+	SDL_UnlockSurface(dest);
+	pix.unlock(IPixelAccess::Unlock_NoChange);
+
+	return dest;
 }
 
-
 /**
  * Stores the picture size in pw and ph.
  * Throws an exception if the picture doesn't exist.
@@ -637,20 +649,27 @@
 void Graphic::get_picture_size
 	(const PictureID & pic, uint32_t & w, uint32_t & h) const
 {
-	assert (pic->surface);
-	Surface & bmp = *pic->surface;
-
-	w = bmp.get_w();
-	h = bmp.get_h();
-}
-
-/**
- * Saves a surface to a png. This can be a file or part of a stream.
+	w = pic->get_w();
+	h = pic->get_h();
+}
+
+/**
+ * This is purely a convenience function intended to allow casting
+ * pointers without including a whole bunch of headers.
+ */
+PictureID Graphic::get_offscreen_picture(OffscreenSurfacePtr surface) const
+{
+	return surface;
+}
+
+
+/**
+ * Saves a pixel region to a png. This can be a file or part of a stream.
  *
  * @param surf The Surface to save
  * @param sw a StreamWrite where the png is written to
  */
-void Graphic::save_png(Surface & surf, StreamWrite * sw) const
+void Graphic::save_png(IPixelAccess & pix, StreamWrite * sw) const
 {
 	// Save a png
 	png_structp png_ptr =
@@ -686,7 +705,7 @@
 
 	// Fill info struct
 	png_set_IHDR
-		(png_ptr, info_ptr, surf.get_w(), surf.get_h(),
+		(png_ptr, info_ptr, pix.get_w(), pix.get_h(),
 		 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
 		 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
 
@@ -701,64 +720,31 @@
 	png_set_packing(png_ptr);
 
 	{
-		uint32_t surf_w = surf.get_w();
-		uint32_t surf_h = surf.get_h();
+		uint32_t surf_w = pix.get_w();
+		uint32_t surf_h = pix.get_h();
 		uint32_t row_size = 4 * surf_w;
 
-		png_bytep rowb = 0;
-		png_bytep rowp = 0;
+		boost::scoped_array<png_byte> row(new png_byte[row_size]);
 
 		//Write each row
-		SDL_PixelFormat * fmt;
-		upcast(SurfaceSDL, sdlsurf, &surf);
-#ifdef USE_OPENGL
-		upcast(SurfaceOpenGL, oglsurf, &surf);
-#endif
-		if (sdlsurf)
-		{
-			fmt = const_cast<SDL_PixelFormat *>(&sdlsurf->format());
-			rowb = (new png_byte[row_size]);
-			if (!rowb)
-				throw wexception("Out of memory.");
-		}
-#ifdef USE_OPENGL
-		else if (oglsurf) {
-			oglsurf->lock();
-			fmt = 0;
-		}
-#endif
-		else
-			return;
-
+		const SDL_PixelFormat & fmt = pix.format();
+		pix.lock(IPixelAccess::Lock_Normal);
 
 		// Write each row
 		for (uint32_t y = 0; y < surf_h; ++y) {
-			rowp = rowb;
-			if (sdlsurf)
-				for (uint32_t x = 0; x < surf_w; rowp += 4, ++x)
-					SDL_GetRGBA
-						(sdlsurf->get_pixel(x, y),
-						 fmt,
-						 rowp + 0, rowp + 1, rowp + 2, rowp + 3);
-#ifdef USE_OPENGL
-			else if (oglsurf) {
-				rowb = static_cast<png_bytep>
-					(oglsurf->get_pixels() +
-					 oglsurf->get_pitch() * (surf_h - y - 1));
+			for (uint32_t x = 0; x < surf_w; ++x) {
+				RGBAColor color;
+				color.set(fmt, pix.get_pixel(x, y));
+				row[4 * x] = color.r;
+				row[4 * x + 1] = color.g;
+				row[4 * x + 2] = color.b;
+				row[4 * x + 3] = color.a;
 			}
-#endif
-			else
-				throw wexception("Try to save save_png with unknown surface\n");
 
-			png_write_row(png_ptr, rowb);
+			png_write_row(png_ptr, row.get());
 		}
-#ifdef USE_OPENGL
-		if (oglsurf)
-			oglsurf->unlock();
-		else
-#endif
-			if (sdlsurf)
-				delete rowb;
+
+		pix.unlock(IPixelAccess::Unlock_NoChange);
 	}
 
 	// End write
@@ -767,267 +753,175 @@
 }
 
 /**
-* Saves a PictureID to a png. This can be a file or part of a stream. This
-* function retrieves the Surface for the PictureID and calls
-* save_png(Surface, StreamWrite)
-*
-* @param surf The Surface to save
-* @param sw a StreamWrite where the png is written to
-*/
+ * Saves a surface to a png. This can be a file or part of a stream.
+ *
+ * @param surf The Surface to save
+ * @param sw a StreamWrite where the png is written to
+ */
+void Graphic::save_png(SurfacePtr surf, StreamWrite * sw) const
+{
+	save_png(surf->pixelaccess(), sw);
+}
+
+/**
+ * Saves a PictureID to a png. This can be a file or part of a stream. This
+ * function retrieves the Surface for the PictureID and calls
+ * save_png(Surface, StreamWrite)
+ *
+ * @param surf The Surface to save
+ * @param sw a StreamWrite where the png is written to
+ */
 void Graphic::save_png(const PictureID & pic_index, StreamWrite * sw) const
 {
-	Surface & surf = const_cast<Surface &>(*get_picture_surface(pic_index));
-	save_png(surf, sw);
-}
-
-/**
- * Create a offscreen surface of specified size and return as PictureID.
- * The surface is put into a normal slot in the picture array so the surface
- * can be used in normal blit() operations. A RenderTarget for the surface can
- * be obtained using get_surface_renderer().
- * \note Surfaces do not belong to a module and must be freed explicitly.
- *
- * @param w width of the new surface
- * @param h height of the new surface
- * @param alpha if true the surface is created with alpha channel
- * @return PictureID of the new created offscreen surface
-*/
-PictureID Graphic::create_picture_surface(int32_t w, int32_t h, bool alpha)
-{
-	//log(" Graphic::create_picture_surface(%d, %d)\n", w, h);
-	Surface & surf = create_surface(w, h, alpha);
-
-	Picture & pic = *new Picture();
-	PictureID id = PictureID(&pic);
-	m_picturemap[PicSurface].insert(std::make_pair("", id));
-
-	pic.module    = PicSurface; // mark as surface
-	pic.surface   = &surf;
-	assert(pic.rendertarget == 0);
-	pic.rendertarget = new RenderTarget(pic.surface);
-
-	return id;
-}
-
-/**
- * Create a Surface from a SDL_Surface. This creates a Surface for OpenGL or
- * Software rendering depending on the actual setting. The SDL_Surface must
- * not be used after calling this. Surface takes care of the SDL_Surface.
- *
- * @param surf a SDL_Surface from which the Surface will be created
+	save_png(pic_index->pixelaccess(), sw);
+}
+
+/**
+ * Create a Picture from an SDL_Surface.
+ *
+ * @param surf a SDL_Surface from which the Surface will be created; this function
+ * takes ownership of surf
  * @param alpha if true the surface is created with alpha channel
  * @return the new Surface created from the SDL_Surface
  */
-Surface & Graphic::create_surface(SDL_Surface & surf, bool alpha)
+PictureID Graphic::convert_sdl_surface_to_picture(SDL_Surface * surf, bool alpha)
 {
 	if (g_opengl)
 	{
 #ifdef USE_OPENGL
-		return *new SurfaceOpenGL(surf);
+		return PictureID(new GLPictureTexture(surf));
 #endif
 	} else {
 		SDL_Surface * surface;
 		if (alpha)
-			surface = SDL_DisplayFormatAlpha(&surf);
-		else
-			surface = SDL_DisplayFormat(&surf);
-		SDL_FreeSurface(&surf);
-		return *new SurfaceSDL(*surface);
-	}
-}
-
-/**
-* Create a Surface from an other Surface. This makes a copy of a Surface.
-*
-* @param surf the surface which will be copied to the new surface
-* @param alpha if true the surface is created with alpha channel
-* @return the new Surface
-*/
-Surface & Graphic::create_surface(Surface & surf, bool alpha)
-{
-	upcast(SurfaceSDL, sdlsurf, &surf);
-	if (sdlsurf)
-	{
-		if (alpha)
-			return
-				*new SurfaceSDL
-					(*SDL_DisplayFormatAlpha(sdlsurf->get_sdl_surface()));
-		else
-			return
-				*new SurfaceSDL
-					(*SDL_DisplayFormat(sdlsurf->get_sdl_surface()));
-	}
-	else
-	{
-		Surface & tsurf = create_surface(surf.get_w(), surf.get_h());
-
-		surf.lock();
-		tsurf.lock();
-		for (unsigned int x = 0; x < surf.get_w(); x++)
-			for (unsigned int y = 0; y < surf.get_h(); y++)
-			{
-				tsurf.set_pixel(x, y, surf.get_pixel(x, y));
-			}
-		surf.unlock();
-		tsurf.unlock();
-
-		return tsurf;
-	}
-}
-
-/**
-* Create a empty offscreen surface of specified size.
-*
-* @param w width of the new surface
-* @param h height of the new surface
-* @param alpha if true the surface is created with alpha channel
-* @return the new created surface
-*/
-Surface & Graphic::create_surface(int32_t w, int32_t h, bool alpha)
-{
-	if (g_opengl)
-	{
-#ifdef USE_OPENGL
-		return *new SurfaceOpenGL(w, h);
-#endif
-	} else {
-		const SDL_PixelFormat & format = m_screen->format();
-		SDL_Surface & tsurf = *SDL_CreateRGBSurface
-			(SDL_SWSURFACE,
-			 w, h,
-			 format.BitsPerPixel,
-			 format.Rmask, format.Gmask, format.Bmask, format.Amask);
-		if (alpha) {
-			SDL_Surface & surf = *SDL_DisplayFormatAlpha(&tsurf);
-			SDL_FreeSurface(&tsurf);
-			return *new SurfaceSDL(surf);
-		}
-		return *new SurfaceSDL(tsurf);
-	}
-}
-
-/**
- * Free the given surface.
- * Unlike normal pictures, surfaces are not freed by flush().
- *
- * @param picid the PictureID ot to be freed
-*/
-void Graphic::free_picture_surface(const PictureID & picid) {
-	if
-		(picid->module != PicMod_Font &&
-		 picid->module != PicSurface)
-	{
-		log
-			("Graphic::free_surface ignoring free of %u %s\n",
-			 picid->module, picid->fname);
-		return;
-	}
-	assert(picid->module == PicMod_Font || picid->module == PicSurface);
-
-	delete picid->surface;
-	picid->surface = 0;
-	delete picid->rendertarget;
-	picid->rendertarget = 0;
-	delete picid->fname;
-	picid->fname = 0;
-
-	container_iterate(Picturemap, m_picturemap[picid->module], it)
-		if (it.current->second == picid) {
-			m_picturemap[picid->module].erase(it.current);
-			break;
-		}
-}
-
-/**
-* create a grayed version.
-*
-* @param picid the PictureID ot to grayed out
-* @return the gray version of the picture
-*/
-PictureID Graphic::create_grayed_out_pic(const PictureID & picid) {
-	if (picid != get_no_picture()) {
-		Surface & s = create_surface(*get_picture_surface(picid), true);
-#ifdef USE_OPENGL
-		upcast(SurfaceOpenGL, gl_dest, &s);
-		upcast(SurfaceOpenGL, gl_src, get_picture_surface(picid));
-#endif
-		upcast(SurfaceSDL, sdl_s, &s);
-		SDL_PixelFormat const * format = 0;
-		if (sdl_s)
-			format = &(sdl_s->format());
-		uint32_t const w = s.get_w(), h = s.get_h();
-#ifdef USE_OPENGL
-		if (gl_src)
-			gl_src->lock();
-#endif
-		s.lock();
-		for (uint32_t y = 0; y < h; ++y)
-			for (uint32_t x = 0; x < w; ++x) {
-				uint8_t r, g, b, a;
-#ifdef USE_OPENGL
-				if (gl_src)
-				{
-					uint32_t pixel = gl_src->get_pixel(x, y);
-					r = pixel & 0xFF;
-					g = (pixel & 0xFF00) >> 8;
-					b = (pixel & 0xFF0000) >> 16;
-					a = (pixel & 0xFF000000) >> 24;
-				} else
-#endif
-				//  FIXME need for const_cast is SDL bug #421
-					SDL_GetRGBA
-						(sdl_s->get_pixel(x, y),
-						 const_cast<SDL_PixelFormat *>(format), &r, &g, &b, &a);
-
-				//  Halve the opacity to give some difference for pictures that are
-				//  grayscale to begin with.
-				a >>= 1;
-
-				uint8_t const gray =
-					(luminance_table_r[r] +
-					 luminance_table_g[g] +
-					 luminance_table_b[b] +
-					 8388608U) //  compensate for truncation:  .5 * 2^24
-					>> 24;
-
-				// NOTE const_cast is needed for SDL-1.2 older than revision 3008
-#ifdef USE_OPENGL
-				if (gl_dest)
-				{
-					gl_dest->set_pixel(x, y, g + (g << 8) + (g << 16) + (a << 24));
-				} else
-#endif
-					sdl_s->set_pixel
-						(x, y,
-						 SDL_MapRGBA
-						 	(const_cast<SDL_PixelFormat *>(format),
-						 	 gray, gray, gray, a));
-
-			}
-		s.unlock();
-#ifdef USE_OPENGL
-		if (gl_src)
-			gl_src->unlock();
-#endif
-		return get_picture(PicSurface, s);
-	} else
+			surface = SDL_DisplayFormatAlpha(surf);
+		else
+			surface = SDL_DisplayFormat(surf);
+		SDL_FreeSurface(surf);
+		return PictureID(new SurfaceSDL(*surface));
+	}
+}
+
+/**
+ * Create a empty offscreen surface of specified size.
+ *
+ * @param w width of the new surface
+ * @param h height of the new surface
+ * @param alpha if true the surface is created with alpha channel
+ * @return the new created surface
+ */
+OffscreenSurfacePtr Graphic::create_offscreen_surface(int32_t w, int32_t h, bool alpha)
+{
+#ifdef USE_OPENGL
+	if (g_opengl)
+	{
+
+		throw wexception("OpenGL mode does not support offscreen surfaces");
+	}
+	else
+#endif
+	{
+		const SDL_PixelFormat & format = *m_sdl_screen->format;
+		SDL_Surface & tsurf = *SDL_CreateRGBSurface
+			(SDL_SWSURFACE,
+			 w, h,
+			 format.BitsPerPixel,
+			 format.Rmask, format.Gmask, format.Bmask, format.Amask);
+		if (alpha) {
+			SDL_Surface & surf = *SDL_DisplayFormatAlpha(&tsurf);
+			SDL_FreeSurface(&tsurf);
+			return OffscreenSurfacePtr(new SurfaceSDL(surf));
+		}
+		return OffscreenSurfacePtr(new SurfaceSDL(tsurf));
+	}
+}
+
+/**
+ * Create a picture with initially undefined contents.
+ *
+ * Use \ref IPicture::pixelaccess to upload image data afterwards.
+ *
+ * @param w width of the new surface
+ * @param h height of the new surface
+ * @param alpha if true the surface is created with alpha channel
+ * @return the new created surface
+ */
+PictureID Graphic::create_picture(int32_t w, int32_t h, bool alpha)
+{
+#ifdef USE_OPENGL
+	if (g_opengl)
+	{
+		return PictureID(new GLPictureTexture(w, h));
+	}
+	else
+#endif
+	{
+		const SDL_PixelFormat & format = *m_sdl_screen->format;
+		SDL_Surface & tsurf = *SDL_CreateRGBSurface
+			(SDL_SWSURFACE,
+			 w, h,
+			 format.BitsPerPixel,
+			 format.Rmask, format.Gmask, format.Bmask, format.Amask);
+		if (alpha) {
+			SDL_Surface & surf = *SDL_DisplayFormatAlpha(&tsurf);
+			SDL_FreeSurface(&tsurf);
+			return OffscreenSurfacePtr(new SurfaceSDL(surf));
+		}
+		return PictureID(new SurfaceSDL(tsurf));
+	}
+}
+
+
+/**
+ * Create a grayed version of the given picture.
+ *
+ * @param picid the PictureID ot to grayed out
+ * @return the gray version of the picture
+ */
+PictureID Graphic::create_grayed_out_pic(const PictureID & picid)
+{
+	if (!picid || !picid->valid())
 		return get_no_picture();
-}
-
-
-/**
- * Returns the RenderTarget for the given surface
-*/
-RenderTarget * Graphic::get_surface_renderer(const PictureID & pic) {
-	//assert(pic < m_pictures.size());
-	//  assert(m_pictures[pic].module == 0xff); fails showing terrains in editor
-
-	RenderTarget & rt = *pic->rendertarget;
-
-	rt.reset();
-
-	return &rt;
-}
+
+	IPixelAccess & origpix = picid->pixelaccess();
+	uint32_t w = picid->get_w();
+	uint32_t h = picid->get_h();
+	const SDL_PixelFormat & origfmt = origpix.format();
+
+	PictureID destpicture = create_picture(w, h, origfmt.Amask);
+	IPixelAccess & destpix = destpicture->pixelaccess();
+	const SDL_PixelFormat & destfmt = destpix.format();
+
+	origpix.lock(IPixelAccess::Lock_Normal);
+	destpix.lock(IPixelAccess::Lock_Discard);
+	for (uint32_t y = 0; y < h; ++y) {
+		for (uint32_t x = 0; x < w; ++x) {
+			RGBAColor color;
+
+			color.set(origfmt, origpix.get_pixel(x, y));
+
+			//  Halve the opacity to give some difference for pictures that are
+			//  grayscale to begin with.
+			color.a >>= 1;
+
+			uint8_t const gray =
+				(luminance_table_r[color.r] +
+				 luminance_table_g[color.g] +
+				 luminance_table_b[color.b] +
+				 8388608U) //  compensate for truncation:  .5 * 2^24
+				>> 24;
+
+			color.r = color.g = color.b = gray;
+
+			destpix.set_pixel(x, y, color.map(destfmt));
+		}
+	}
+	origpix.unlock(IPixelAccess::Unlock_NoChange);
+	destpix.unlock(IPixelAccess::Unlock_Update);
+
+	return destpicture;
+}
+
 
 /**
  * Creates a terrain texture.
@@ -1046,7 +940,7 @@
 {
 	try {
 		m_maptextures.push_back
-			(new Texture(fnametempl, frametime, m_screen->format()));
+			(new Texture(fnametempl, frametime, *m_sdl_screen->format));
 	} catch (std::exception const & e) {
 		log("Failed to load maptexture %s: %s\n", &fnametempl, e.what());
 		return 0;
@@ -1123,10 +1017,10 @@
 		w = h = 0;
 	} else {
 		// Get the frame and its data. Ignore playerclrs.
-		Surface const & frame =
-			*gfx->get_frame((time / data->frametime) % gfx->nr_frames());
-		w = frame.get_w();
-		h = frame.get_h();
+		const PictureID & frame =
+			gfx->get_frame((time / data->frametime) % gfx->nr_frames());
+		w = frame->get_w();
+		h = frame->get_h();
 	}
 }
 
@@ -1137,7 +1031,7 @@
 {
 	log("Save screenshot to %s\n", &fname);
 	StreamWrite * sw = g_fs->OpenStreamWrite(std::string(&fname));
-	save_png(*m_screen, sw);
+	save_png(m_screen, sw);
 	delete sw;
 }
 
@@ -1163,21 +1057,6 @@
 	static_cast<StreamWrite *>(png_get_io_ptr(png_ptr))->Flush();
 }
 
-
-/**
-* Returns the bitmap that belongs to the given picture ID.
-* May return 0 if the given picture does not exist.
-*/
-Surface * Graphic::get_picture_surface(const PictureID & id)
-{
-	return id->surface;
-}
-
-const Surface * Graphic::get_picture_surface(const PictureID & id) const
-{
-	return id->surface;
-}
-
 /**
  * Retrieve the animation with the given number.
  *
@@ -1210,7 +1089,7 @@
  * if not done yet.
  * \return The road texture
 */
-Surface * Graphic::get_road_texture(int32_t const roadtex)
+PictureID Graphic::get_road_texture(int32_t const roadtex)
 {
 	if (not m_roadtextures) {
 		// Load the road textures
@@ -1223,7 +1102,6 @@
 	}
 
 	return
-		get_picture_surface
-			(roadtex == Widelands::Road_Normal ?
-			 m_roadtextures->pic_road_normal : m_roadtextures->pic_road_busy);
+		(roadtex == Widelands::Road_Normal ?
+		 m_roadtextures->pic_road_normal : m_roadtextures->pic_road_busy);
 }

=== modified file 'src/graphic/graphic.h'
--- src/graphic/graphic.h	2010-11-15 18:25:31 +0000
+++ src/graphic/graphic.h	2010-11-27 16:29:59 +0000
@@ -21,8 +21,8 @@
 #define GRAPHIC_H
 
 #include "animation_gfx.h"
-#include "picture.h"
 #include "picture_id.h"
+#include "surfaceptr.h"
 #include "rect.h"
 
 #include <png.h>
@@ -41,8 +41,7 @@
 
 namespace UI {struct ProgressWindow;}
 
-struct Surface;
-class Texture;
+struct IPixelAccess;
 struct RenderTarget;
 struct Graphic;
 struct Road_Textures;
@@ -84,15 +83,29 @@
 {
 	/// The renderer allows rendering (blit, draw_line) to offscreen surfaces
 	bool offscreen_rendering;
-	/// It is possible to resize surfaces with get_resized_picture()
-	bool resize_surfaces;
-	/// It is possible to resize surfaces while bliting
-	bool blit_resized;
 	/// The capabilities of the opengl hardware and drive
 	GLCaps gl;
 };
 
 /**
+ * Picture caches (modules).
+ *
+ * \ref Graphic maintains a cache of \ref PictureID s to avoid continuous re-loading of
+ * pictures that may not be referenced all the time (e.g. UI elements).
+ *
+ * This cache is separated into different modules, and can be flushed per-module.
+ */
+enum PicMod {
+	PicMod_UI = 0,
+	PicMod_Menu,
+	PicMod_Game,
+
+	// Must be last
+	PicMod_Last
+};
+
+
+/**
  * A renderer to get pixels to a 16bit framebuffer.
  *
  * Picture IDs can be allocated using \ref get_picture() and used in
@@ -102,8 +115,7 @@
  * graphics system is unloaded, or when \ref flush() is called with the
  * appropriate module flag; the user can request to flush one single picture
  * alone, but this is only used (and useful) in the editor.
-*/
-
+ */
 struct Graphic {
 	Graphic
 		(int32_t w, int32_t h, int32_t bpp,
@@ -124,31 +136,26 @@
 
 	void flush(PicMod module);
 	void flush_animations();
-	Surface & load_image(std::string const &, bool alpha = false);
-	PictureID & get_picture(PicMod, std::string const &, bool alpha = true)
+	PictureID load_image(std::string const &, bool alpha = false);
+	const PictureID & get_picture(PicMod, std::string const &, bool alpha = true)
 		__attribute__ ((pure));
-	PictureID get_picture
-		(PicMod module, Surface &, const std::string & name = "");
-	//__attribute__ ((pure));
-	PictureID & get_no_picture() const;
-
-	Surface * get_picture_surface(const PictureID & id);
-	const Surface * get_picture_surface(const PictureID & id) const;
+	void add_picture_to_cache(PicMod, const std::string &, PictureID);
+	const PictureID & get_no_picture() const;
 
 	void get_picture_size
 		(const PictureID & pic, uint32_t & w, uint32_t & h) const;
+	PictureID get_offscreen_picture(OffscreenSurfacePtr surface) const;
 
 	void save_png(const PictureID &, StreamWrite *) const;
-	void save_png(Surface & surf, StreamWrite *) const;
-
-	PictureID create_picture_surface(int32_t w, int32_t h, bool alpha = false);
-	Surface & create_surface(SDL_Surface &, bool alpha = false);
-	Surface & create_surface(Surface &, bool alpha = false);
-	Surface & create_surface(int32_t w, int32_t h, bool alpha = false);
-	void free_picture_surface(const PictureID & pic);
+	void save_png(SurfacePtr surf, StreamWrite *) const;
+	void save_png(IPixelAccess & pix, StreamWrite *) const;
+
+	PictureID convert_sdl_surface_to_picture(SDL_Surface *, bool alpha = false);
+
+	OffscreenSurfacePtr create_offscreen_surface(int32_t w, int32_t h, bool alpha = false);
+	PictureID create_picture(int32_t w, int32_t h, bool alpha = false);
 
 	PictureID create_grayed_out_pic(const PictureID & picid);
-	RenderTarget * get_surface_renderer(const PictureID & pic);
 
 	enum  ResizeMode {
 		// do not worry about proportions, just sketch to requested size
@@ -163,7 +170,6 @@
 
 	PictureID get_resized_picture
 		(PictureID, uint32_t w, uint32_t h, ResizeMode);
-	SDL_Surface * resize(const PictureID index, uint32_t w, uint32_t h);
 
 	uint32_t get_maptexture(char const & fnametempl, uint32_t frametime);
 	void animate_maptextures(uint32_t time);
@@ -183,10 +189,13 @@
 	Texture * get_maptexture_data(uint32_t id);
 	AnimationGfx * get_animation(uint32_t) const;
 
-	Surface * get_road_texture(int32_t roadtex);
+	PictureID get_road_texture(int32_t roadtex);
 
 	GraphicCaps const & caps() const throw () {return m_caps;}
 
+private:
+	SDL_Surface * extract_sdl_surface(IPixelAccess & pix, Rect srcrect);
+
 protected:
 	// Static helper function for png writing
 	static void m_png_write_function
@@ -197,7 +206,7 @@
 
 	/// This is the main screen Surface.
 	/// A RenderTarget for this can be retrieved with get_render_target()
-	Surface * m_screen;
+	SurfacePtr m_screen;
 	/// This saves a copy of the screen SDL_Surface. This is needed for
 	/// opengl rendering as the SurfaceOpenGL does not use it. It allows
 	/// manipulation the screen context.
@@ -214,12 +223,19 @@
 	/// stores which features the current renderer has
 	GraphicCaps m_caps;
 
-	/// hash of filename/picture ID pairs
-	std::vector
-		<std::map<std::string, boost::shared_ptr<Picture> > > m_picturemap;
-	typedef std::map<std::string, boost::shared_ptr<Picture> > Picturemap;
+	struct PictureRec {
+		PictureID picture;
+
+		/// bit-mask of modules that this picture exists in
+		uint32_t modules;
+	};
+
+	typedef std::map<std::string, PictureRec> Picturemap;
 	typedef Picturemap::iterator pmit;
 
+	/// hash of cached filename/picture pairs
+	Picturemap m_picturemap;
+
 	Road_Textures * m_roadtextures;
 	std::vector<Texture *> m_maptextures;
 	std::vector<AnimationGfx *> m_animations;
@@ -229,4 +245,3 @@
 extern bool g_opengl;
 
 #endif
-

=== added file 'src/graphic/offscreensurface.h'
--- src/graphic/offscreensurface.h	1970-01-01 00:00:00 +0000
+++ src/graphic/offscreensurface.h	2010-11-27 16:29:59 +0000
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2010 by the Widelands Development Team
+ *
+ * This program 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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef OFFSCREENSURFACE_H
+#define OFFSCREENSURFACE_H
+
+#include "picture.h"
+#include "pixelaccess.h"
+#include "surface.h"
+
+/**
+ * Interface to surfaces that can act conveniently both as
+ * source and as destination for rendering.
+ */
+struct IOffscreenSurface : Surface, IPicture, IPixelAccess {
+};
+
+#endif // OFFSCREENSURFACE_H

=== modified file 'src/graphic/picture.cc'
--- src/graphic/picture.cc	2009-07-17 18:12:17 +0000
+++ src/graphic/picture.cc	2010-11-27 16:29:59 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 by the Widelands Development Team
+ * Copyright (C) 2009-2010 by the Widelands Development Team
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -19,12 +19,25 @@
 
 #include "picture.h"
 
-#include "surface.h"
-#include "rendertarget.h"
-
-Picture::~Picture() {
-	delete surface;
-	free(fname);
-	delete rendertarget;
+#include "wexception.h"
+
+struct NullPicture : IPicture {
+	virtual bool valid() {return false;}
+
+	virtual uint32_t get_w() {return 0;}
+	virtual uint32_t get_h() {return 0;}
+
+	virtual IPixelAccess & pixelaccess() {throw wexception("pixelaccess() attempted on null picture");}
+	virtual Surface & surface() {throw wexception("surface() attempted on null picture");}
+};
+
+/**
+ * \return an invalid, null picture
+ *
+ * \see Graphic::get_no_picture
+ */
+const PictureID & IPicture::null()
+{
+	static PictureID thenull(new NullPicture);
+	return thenull;
 }
-

=== modified file 'src/graphic/picture.h'
--- src/graphic/picture.h	2010-11-10 20:05:21 +0000
+++ src/graphic/picture.h	2010-11-27 16:29:59 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2002-2004, 2006-2009 by the Widelands Development Team
+ * Copyright (C) 2002-2004, 2006-2010 by the Widelands Development Team
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -20,43 +20,36 @@
 #ifndef PICTURE_H
 #define PICTURE_H
 
-/***
- * Picture/PictureID
- *
- * PictureID is a reference to a picture
- * picmod is used to specify which buffer picture is loaded in.
- * warning: a picture can be loaded multiple times in multiple buffers
- * when buffer is flushed pictures will hang around till the last reference
- * is gone too
- ***/
-
-
-struct RenderTarget;
+#include <stdint.h>
+#include <string>
+
+#include "picture_id.h"
+
+struct IPixelAccess;
 struct Surface;
 
-/// picture module flags
-enum PicMod {
-	INVALID     = 0,
-	PicMod_UI   = 1,
-	PicMod_Menu = 2,
-	PicMod_Game = 3,
-	PicMod_Font = 4,
-	PicSurface  = 5,
-	MaxModule   = 6 //MaxModule ALWAYS has to be the 'size' of picmod
-};
-
-struct Picture {
-	Picture() : module(INVALID), surface(0), fname(0), rendertarget(0) {}
-	~Picture();
-	//void operator delete(void * p);
-
-	//PicMod lists which 'buffer' to load the images in.
-	// INVALID if unused, MaxModule not a legal module
-	PicMod    module;
-	Surface * surface;
-
-	char         * fname; //  module & (PicMod_UI|PicMod_Menu|PicMod_Game)
-	RenderTarget * rendertarget; //  module & (PicMod_Font | PicSurface)
+/**
+ * Interface to a bitmap that can act as the source of a rendering
+ * operation.
+ */
+struct IPicture {
+	IPicture() {}
+	virtual ~IPicture() {}
+
+	virtual bool valid() = 0;
+
+	virtual uint32_t get_w() = 0;
+	virtual uint32_t get_h() = 0;
+
+	virtual IPixelAccess & pixelaccess() = 0;
+
+private:
+	// forbid copying
+	IPicture(const IPicture &);
+	IPicture & operator= (const IPicture &);
+
+public:
+	static const PictureID & null();
 };
 
 #endif

=== modified file 'src/graphic/picture_id.h'
--- src/graphic/picture_id.h	2009-11-22 14:46:22 +0000
+++ src/graphic/picture_id.h	2010-11-27 16:29:59 +0000
@@ -21,8 +21,8 @@
 
 #include <boost/shared_ptr.hpp>
 
-struct Picture;
+struct IPicture;
 
-typedef boost::shared_ptr<Picture> PictureID;
+typedef boost::shared_ptr<IPicture> PictureID;
 
 #endif

=== added file 'src/graphic/pixelaccess.h'
--- src/graphic/pixelaccess.h	1970-01-01 00:00:00 +0000
+++ src/graphic/pixelaccess.h	2010-11-27 16:29:59 +0000
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2010 by the Widelands Development Team
+ *
+ * This program 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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef PIXELACCESS_H
+#define PIXELACCESS_H
+
+#include <stdint.h>
+
+struct SDL_PixelFormat;
+
+/**
+ * Interface that provides direct pixel access to a picture or surface.
+ *
+ * \note Direct pixel access should be used only carefully, since it can be
+ * extremely slow.
+ */
+struct IPixelAccess {
+	enum LockMode {
+		/**
+		 * Normal mode preserves pre-existing pixel data so that it can
+		 * be read or modified.
+		 */
+		Lock_Normal = 0,
+
+		/**
+		 * Discard mode discards pre-existing pixel data. All pixels
+		 * will be undefined unless they are re-written.
+		 */
+		Lock_Discard
+	};
+
+	enum UnlockMode {
+		/**
+		 * Update mode will ensure that any changes in the pixel data
+		 * will appear in subsequent operations.
+		 */
+		Unlock_Update = 0,
+
+		/**
+		 * NoChange mode indicates that the caller changed no pixel data.
+		 *
+		 * \note If the caller did change pixel data but specifies NoChange
+		 * mode, the results are undefined.
+		 */
+		Unlock_NoChange
+	};
+
+	IPixelAccess() {}
+	virtual ~IPixelAccess() {}
+
+	/// Get width and height
+	//@{
+	virtual uint32_t get_w() = 0;
+	virtual uint32_t get_h() = 0;
+	//@}
+
+	/// This returns the pixel format for direct pixel access.
+	virtual SDL_PixelFormat const & format() const = 0;
+
+	/**
+	 * Lock/Unlock pairs must guard any of the direct pixel access using the
+	 * functions below.
+	 *
+	 * \note Lock/Unlock pairs cannot be nested.
+	 */
+	//@{
+	virtual void lock(LockMode) = 0;
+	virtual void unlock(UnlockMode) = 0;
+	//@}
+
+	//@{
+	virtual uint32_t get_pixel(uint32_t x, uint32_t y) = 0;
+	virtual void set_pixel(uint32_t x, uint32_t y, uint32_t clr) = 0;
+	//@}
+
+	/**
+	 * \return Pitch of the raw pixel data, i.e. the number of bytes
+	 * contained in each image row. This can be strictly larger than
+	 * bytes per pixel times the width.
+	 */
+	virtual uint16_t get_pitch() const = 0;
+
+	/**
+	 * \return Pointer to the raw pixel data.
+	 *
+	 * \warning May only be called inside lock/unlock pairs.
+	 */
+	virtual uint8_t * get_pixels() const = 0;
+
+private:
+	IPixelAccess & operator= (const IPixelAccess &);
+};
+
+#endif // PIXELSURFACE_H

=== modified file 'src/graphic/render/animationgfx.cc'
--- src/graphic/render/animationgfx.cc	2010-05-18 19:34:36 +0000
+++ src/graphic/render/animationgfx.cc	2010-11-27 16:29:59 +0000
@@ -22,8 +22,8 @@
 #include "io/streamwrite.h"
 
 #include "surface_sdl.h"
-#include "surface_opengl.h"
 #include "graphic/graphic.h"
+#include "graphic/picture.h"
 
 #include "log.h"
 #include "upcast.h"
@@ -99,17 +99,17 @@
 			strcpy(after_basename, extensions[extnr]);
 			if (g_fs->FileExists(filename)) { //  Is the frame actually there?
 				try {
-					Surface & surface = g_gr->load_image(filename, true);
+					PictureID pic = g_gr->load_image(filename, true);
 					if (width == 0) { //  This is the first frame.
-						width  = surface.get_w();
-						height = surface.get_h();
-					} else if (width != surface.get_w() or height != surface.get_h())
+						width  = pic->get_w();
+						height = pic->get_h();
+					} else if (width != pic->get_w() or height != pic->get_h())
 						throw wexception
 							("wrong size: (%u, %u), should be (%u, %u) like the "
 							 "first frame",
-							 surface.get_w(), surface.get_h(), width, height);
+							 pic->get_w(), pic->get_h(), width, height);
 					//  Get a new AnimFrame.
-					m_plrframes[0].push_back(&surface);
+					m_plrframes[0].push_back(pic);
 #ifdef VALIDATE_ANIMATION_CROPPING
 					if (not data_in_x_min)
 						for (int y = 0; y < height; ++y) {
@@ -179,13 +179,13 @@
 				strcpy(after_basename + 3, extensions[extnr]);
 				if (g_fs->FileExists(filename)) {
 					try {
-						Surface & surface = g_gr->load_image(filename, true);
-						if (width != surface.get_w() or height != surface.get_h())
+						PictureID picture = g_gr->load_image(filename, true);
+						if (width != picture->get_w() or height != picture->get_h())
 							throw wexception
 								("playercolor mask has wrong size: (%u, %u), should "
 								 "be (%u, %u) like the animation frame",
-								 surface.get_w(), surface.get_h(), width, height);
-						m_pcmasks.push_back(&surface);
+								 picture->get_w(), picture->get_h(), width, height);
+						m_pcmasks.push_back(picture);
 						break;
 					} catch (std::exception const & e) {
 						throw wexception
@@ -243,14 +243,6 @@
 
 AnimationGfx::~AnimationGfx()
 {
-	for (Widelands::Player_Number i = 0; i <= MAX_PLAYERS; ++i) {
-		std::vector<Surface *> & frames = m_plrframes[i];
-		for (uint32_t j = 0; j < frames.size(); ++j)
-			delete frames[j];
-	}
-
-	for (uint32_t j = 0; j < m_pcmasks.size(); ++j)
-		delete m_pcmasks[j];
 }
 
 
@@ -262,47 +254,36 @@
 void AnimationGfx::encode(uint8_t const plr, RGBColor const * const plrclrs)
 {
 	assert(m_plrframes[0].size() == m_pcmasks.size());
-	std::vector<Surface *> & frames = m_plrframes[plr];
+	std::vector<PictureID> & frames = m_plrframes[plr];
 
 	for (uint32_t i = 0; i < m_plrframes[0].size(); ++i) {
 		//  Copy the old surface.
-		Surface & origsurface = *m_plrframes[0][i];
-		Surface & newsurface = g_gr->create_surface(origsurface, true);
-
-		Surface & pcmask = *m_pcmasks[i];
-		SDL_PixelFormat * fmt, * fmt_pc;
-
-#ifdef USE_OPENGL
-		upcast(SurfaceOpenGL, oglsurf, &origsurface);
-
-		if (oglsurf)
-		{
-			fmt_pc = fmt = new SDL_PixelFormat;
-			memset(fmt, 0, sizeof(SDL_PixelFormat));
-			fmt->BitsPerPixel = 32; fmt->BytesPerPixel = 4;
-			fmt->Amask = 0xFF000000; fmt->Ashift = 24;
-			fmt->Bmask = 0x00FF0000; fmt->Bshift = 16;
-			fmt->Gmask = 0x0000FF00; fmt->Gshift = 8;
-			fmt->Rmask = 0x000000FF; fmt->Rshift = 0;
-		} else
-#endif
-		{
-			fmt = const_cast<SDL_PixelFormat *>(&newsurface.format());
-			fmt_pc = const_cast<SDL_PixelFormat *>(&pcmask.format());
-		}
-
-		origsurface.lock();
-		pcmask.lock();
-		newsurface.lock();
+		PictureID origpic = m_plrframes[0][i];
+		uint32_t w = origpic->get_w();
+		uint32_t h = origpic->get_h();
+		IPixelAccess & origpix = m_plrframes[0][i]->pixelaccess();
+		IPixelAccess & pcmask = m_pcmasks[i]->pixelaccess();
+
+		PictureID newpicture = g_gr->create_picture(w, h, true);
+		IPixelAccess & newpix = newpicture->pixelaccess();
+
+		const SDL_PixelFormat & fmt = origpix.format();
+		const SDL_PixelFormat & fmt_pc = pcmask.format();
+		const SDL_PixelFormat & destfmt = newpix.format();
+
+		origpix.lock(IPixelAccess::Lock_Normal);
+		pcmask.lock(IPixelAccess::Lock_Normal);
+		newpix.lock(IPixelAccess::Lock_Discard);
 		// This could be done significantly faster, but since we
 		// cache the result, let's keep it simple for now.
-		for (uint32_t y = 0; y < newsurface.get_h(); ++y) {
-			for (uint32_t x = 0; x < newsurface.get_w(); ++x) {
+		for (uint32_t y = 0; y < h; ++y) {
+			for (uint32_t x = 0; x < w; ++x) {
 				RGBAColor source;
 				RGBAColor mask;
+				RGBAColor product;
 
-				source.set(*fmt, newsurface.get_pixel(x, y));
-				mask.set(*fmt_pc, pcmask.get_pixel(x, y));
+				source.set(fmt, origpix.get_pixel(x, y));
+				mask.set(fmt_pc, pcmask.get_pixel(x, y));
 
 				if
 					(uint32_t const influence =
@@ -320,23 +301,25 @@
 					plrclr.g = (plrclrs[3].g() * intensity) >> 8;
 					plrclr.b = (plrclrs[3].b() * intensity) >> 8;
 
-					RGBAColor dest(source);
-					dest.r =
-						(plrclr.r * influence + dest.r * (65536 - influence)) >> 16;
-					dest.g =
-						(plrclr.g * influence + dest.g * (65536 - influence)) >> 16;
-					dest.b =
-						(plrclr.b * influence + dest.b * (65536 - influence)) >> 16;
-
-					newsurface.set_pixel(x, y, dest.map(*fmt));
+					product.r =
+						(plrclr.r * influence + source.r * (65536 - influence)) >> 16;
+					product.g =
+						(plrclr.g * influence + source.g * (65536 - influence)) >> 16;
+					product.b =
+						(plrclr.b * influence + source.b * (65536 - influence)) >> 16;
+					product.a = source.a;
+				} else {
+					product = source;
 				}
+
+				newpix.set_pixel(x, y, product.map(destfmt));
 			}
 		}
-		origsurface.unlock();
-		pcmask.unlock();
-		newsurface.unlock();
+		origpix.unlock(IPixelAccess::Unlock_NoChange);
+		pcmask.unlock(IPixelAccess::Unlock_NoChange);
+		newpix.unlock(IPixelAccess::Unlock_Update);
 
-		frames.push_back(&newsurface);
+		frames.push_back(newpicture);
 	}
 }
 

=== modified file 'src/graphic/render/gameview.cc'
--- src/graphic/render/gameview.cc	2010-11-02 00:07:12 +0000
+++ src/graphic/render/gameview.cc	2010-11-27 16:29:59 +0000
@@ -33,7 +33,6 @@
 #include "graphic/graphic.h"
 #include "graphic/rendertarget.h"
 #include "graphic/surface.h"
-#include "surface_opengl.h"
 #include "surface_sdl.h"
 #include "graphic/texture.h"
 
@@ -973,13 +972,10 @@
 	 Texture const &  f_d_texture,
 	 Texture const &  f_r_texture)
 {
-	upcast(SurfaceSDL, sdlsurf, m_surface);
-#ifdef USE_OPENGL
-	upcast(SurfaceOpenGL, oglsurf, m_surface);
-#endif
+	upcast(SurfaceSDL, sdlsurf, m_surface.get());
 	if (sdlsurf)
 	{
-		dynamic_cast<SurfaceSDL *>(m_surface)->set_subwin(subwin);
+		sdlsurf->set_subwin(subwin);
 		switch (sdlsurf->format().BytesPerPixel) {
 		case 2:
 			draw_field_int<Uint16>
@@ -998,16 +994,17 @@
 		default:
 			assert(false);
 		}
-		dynamic_cast<SurfaceSDL *>(m_surface)->unset_subwin();
+		sdlsurf->unset_subwin();
 	}
 #ifdef USE_OPENGL
-	else if (oglsurf) {
+	else
+	{
 		// Draw triangle right (bottom) of the field
 		draw_field_opengl
-			(*oglsurf, subwin, f_vert, br_vert, r_vert, f_r_texture);
+			(subwin, f_vert, br_vert, r_vert, f_r_texture);
 		// Draw triangle bottom of the field
 		draw_field_opengl
-			(*oglsurf, subwin, f_vert, bl_vert, br_vert, f_d_texture);
+			(subwin, f_vert, bl_vert, br_vert, f_d_texture);
 		// Draw the roads
 		draw_roads_opengl(subwin, roads, f_vert, r_vert, bl_vert, br_vert);
 	}
@@ -1273,7 +1270,7 @@
 	//       necesary. The created surface could be cached and only redrawn two
 	//       or three times per second
 	const SDL_PixelFormat & fmt =
-		g_gr->get_render_target()->get_surface().format();
+		g_gr->get_render_target()->get_surface()->pixelaccess().format();
 	SDL_Surface * surface =
 		SDL_CreateRGBSurface
 			(SDL_SWSURFACE,
@@ -1312,11 +1309,9 @@
 
 	SDL_UnlockSurface(surface);
 
-	Surface & surf = g_gr->create_surface(*surface);
-
-	m_surface->blit(Point(rc.x, rc.y), &surf, rc2, false);
-
-	delete &surf;
+	PictureID picture = g_gr->convert_sdl_surface_to_picture(surface);
+
+	m_surface->blit(Point(rc.x, rc.y), picture, rc2);
 }
 
 void GameView::rendermap_init()

=== added file 'src/graphic/render/gl_picture_texture.cc'
--- src/graphic/render/gl_picture_texture.cc	1970-01-01 00:00:00 +0000
+++ src/graphic/render/gl_picture_texture.cc	2010-11-27 16:29:59 +0000
@@ -0,0 +1,235 @@
+/*
+ * Copyright 2010 by the Widelands Development Team
+ *
+ * This program 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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "gl_picture_texture.h"
+
+#include <SDL_video.h>
+
+#include "gl_utils.h"
+#include "graphic/graphic.h"
+#include "wexception.h"
+
+
+/**
+ * Initialize an OpenGL texture of the given dimensions.
+ *
+ * The initial data of the texture is undefined.
+ */
+GLPictureTexture::GLPictureTexture(int w, int h)
+{
+	init(w, h);
+}
+
+/**
+ * Initialize an OpenGL texture with the contents of the given surface.
+ *
+ * \note Takes ownership of the given surface.
+ */
+GLPictureTexture::GLPictureTexture(SDL_Surface * surface)
+{
+	init(surface->w, surface->h);
+
+	// Convert image data
+	uint8_t bpp = surface->format->BytesPerPixel;
+
+	if
+		(surface->format->palette or (surface->format->colorkey > 0) or
+		 m_tex_w != static_cast<uint32_t>(surface->w) or
+		 m_tex_h != static_cast<uint32_t>(surface->h) or
+		 (bpp != 3 && bpp != 4))
+	{
+		SDL_Surface * converted = SDL_CreateRGBSurface
+			(SDL_SWSURFACE, m_tex_w, m_tex_h,
+			 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
+		assert(converted);
+		SDL_SetAlpha(converted, 0, 0);
+		SDL_SetAlpha(surface, 0, 0);
+		SDL_BlitSurface(surface, 0, converted, 0);
+		SDL_FreeSurface(surface);
+		surface = converted;
+		bpp = surface->format->BytesPerPixel;
+	}
+
+	SDL_PixelFormat const & fmt = *surface->format;
+	GLenum pixels_format;
+
+	glPushAttrib(GL_PIXEL_MODE_BIT);
+
+	if (bpp == 4) {
+		if
+			(fmt.Rmask == 0x000000ff and fmt.Gmask == 0x0000ff00 and
+			 fmt.Bmask == 0x00ff0000)
+		{
+			if (fmt.Amask == 0xff000000) {
+				pixels_format = GL_RGBA;
+			} else {
+				pixels_format = GL_RGBA;
+				// Read four bytes per pixel but ignore the alpha value
+				glPixelTransferi(GL_ALPHA_SCALE, 0.0f);
+				glPixelTransferi(GL_ALPHA_BIAS, 1.0f);
+			}
+		} else if
+			(fmt.Bmask == 0x000000ff and fmt.Gmask == 0x0000ff00 and
+			 fmt.Rmask == 0x00ff0000)
+		{
+			if (fmt.Amask == 0xff000000) {
+				pixels_format = GL_BGRA;
+			} else {
+				pixels_format = GL_BGRA;
+				// Read four bytes per pixel but ignore the alpha value
+				glPixelTransferi(GL_ALPHA_SCALE, 0.0f);
+				glPixelTransferi(GL_ALPHA_BIAS, 1.0f);
+			}
+		} else
+			throw wexception("OpenGL: Unknown pixel format");
+	} else  if (bpp == 3) {
+		if
+			(fmt.Rmask == 0x000000ff and fmt.Gmask == 0x0000ff00 and
+			 fmt.Bmask == 0x00ff0000)
+		{
+			pixels_format = GL_RGB;
+		} else if
+			(fmt.Bmask == 0x000000ff and fmt.Gmask == 0x0000ff00 and
+			 fmt.Rmask == 0x00ff0000)
+		{
+			pixels_format = GL_BGR;
+		} else
+			throw wexception("OpenGL: Unknown pixel format");
+	} else
+		throw wexception("OpenGL: Unknown pixel format");
+
+	SDL_LockSurface(surface);
+
+	glTexImage2D
+		(GL_TEXTURE_2D, 0, GL_RGBA, m_tex_w, m_tex_h, 0,
+		 pixels_format, GL_UNSIGNED_BYTE, surface->pixels);
+
+	SDL_UnlockSurface(surface);
+	SDL_FreeSurface(surface);
+
+	glPopAttrib();
+	handle_glerror();
+}
+
+GLPictureTexture::~GLPictureTexture()
+{
+	glDeleteTextures(1, &m_texture);
+}
+
+void GLPictureTexture::init(uint32_t w, uint32_t h)
+{
+	handle_glerror();
+
+	m_w = w;
+	m_h = h;
+
+	if (g_gr->caps().gl.tex_power_of_two) {
+		m_tex_w = next_power_of_two(w);
+		m_tex_h = next_power_of_two(h);
+	} else {
+		m_tex_w = w;
+		m_tex_h = h;
+	}
+
+	glGenTextures(1, &m_texture);
+	glBindTexture(GL_TEXTURE_2D, m_texture);
+
+	// set texture filter to use linear filtering. This looks nicer for resized
+	// texture. Most textures and images are not resized so the filtering
+	// makes no difference
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+	handle_glerror();
+}
+
+bool GLPictureTexture::valid()
+{
+	return true;
+}
+
+uint32_t GLPictureTexture::get_w()
+{
+	return m_w;
+}
+
+uint32_t GLPictureTexture::get_h()
+{
+	return m_h;
+}
+
+const SDL_PixelFormat & GLPictureTexture::format() const
+{
+	return gl_rgba_format();
+}
+
+void GLPictureTexture::lock(LockMode mode)
+{
+	assert(!m_pixels);
+
+	m_pixels.reset(new uint8_t[m_tex_w * m_tex_h * 4]);
+
+	if (mode == Lock_Normal) {
+		glBindTexture(GL_TEXTURE_2D, m_texture);
+		glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_pixels.get());
+	}
+}
+
+void GLPictureTexture::unlock(UnlockMode mode)
+{
+	assert(m_pixels);
+
+	if (mode == Unlock_Update) {
+		glBindTexture(GL_TEXTURE_2D, m_texture);
+		glTexImage2D
+			(GL_TEXTURE_2D, 0, GL_RGBA, m_tex_w, m_tex_h, 0, GL_RGBA,
+			 GL_UNSIGNED_BYTE,  m_pixels.get());
+	}
+
+	m_pixels.reset(0);
+}
+
+uint16_t GLPictureTexture::get_pitch() const
+{
+	return 4 * m_tex_w;
+}
+
+uint8_t * GLPictureTexture::get_pixels() const
+{
+	return m_pixels.get();
+}
+
+uint32_t GLPictureTexture::get_pixel(uint32_t x, uint32_t y)
+{
+	assert(m_pixels);
+	assert(x < m_w);
+	assert(y < m_h);
+
+	uint8_t * data = &m_pixels[(y * m_tex_w + x) * 4];
+	return *(reinterpret_cast<uint32_t *>(data));
+}
+
+void GLPictureTexture::set_pixel(uint32_t x, uint32_t y, uint32_t clr)
+{
+	assert(m_pixels);
+	assert(x < m_w);
+	assert(y < m_h);
+
+	uint8_t * data = &m_pixels[(y * m_tex_w + x) * 4];
+	*(reinterpret_cast<uint32_t *>(data)) = clr;
+}

=== added file 'src/graphic/render/gl_picture_texture.h'
--- src/graphic/render/gl_picture_texture.h	1970-01-01 00:00:00 +0000
+++ src/graphic/render/gl_picture_texture.h	2010-11-27 16:29:59 +0000
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2010 by the Widelands Development Team
+ *
+ * This program 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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef GL_PICTURE_TEXTURE_H
+#define GL_PICTURE_TEXTURE_H
+
+#include <boost/scoped_array.hpp>
+
+#include <SDL_opengl.h>
+
+#include "graphic/picture.h"
+#include "graphic/pixelaccess.h"
+
+struct SDL_Surface;
+
+struct GLPictureTexture : IPicture, IPixelAccess {
+	GLPictureTexture(SDL_Surface * surface);
+	GLPictureTexture(int w, int h);
+	~GLPictureTexture();
+
+	/// Interface implementation
+	//@{
+	virtual bool valid();
+
+	virtual uint32_t get_w();
+	virtual uint32_t get_h();
+
+	virtual const SDL_PixelFormat & format() const;
+	virtual void lock(LockMode);
+	virtual void unlock(UnlockMode);
+	virtual uint16_t get_pitch() const;
+	virtual uint8_t * get_pixels() const;
+	virtual void set_pixel(uint32_t x, uint32_t y, uint32_t clr);
+	virtual uint32_t get_pixel(uint32_t x, uint32_t y);
+
+	virtual IPixelAccess & pixelaccess() {return *this;}
+	//@}
+
+	GLuint get_gl_texture() const {return m_texture;}
+	uint32_t get_tex_w() const {return m_tex_w;}
+	uint32_t get_tex_h() const {return m_tex_h;}
+
+private:
+	void init(uint32_t w, uint32_t h);
+
+private:
+	GLuint m_texture;
+
+	/// Logical width and height of the surface
+	uint32_t m_w, m_h;
+
+	/// Keep the size of the opengl texture. This is necessary because some
+	/// systems support only a power of two for texture sizes.
+	uint32_t m_tex_w, m_tex_h;
+
+	/// Pixel data, while the texture is locked
+	boost::scoped_array<uint8_t> m_pixels;
+};
+
+#endif //GL_PICTURE_TEXTURE_H

=== added file 'src/graphic/render/gl_surface_screen.cc'
--- src/graphic/render/gl_surface_screen.cc	1970-01-01 00:00:00 +0000
+++ src/graphic/render/gl_surface_screen.cc	2010-11-27 16:29:59 +0000
@@ -0,0 +1,286 @@
+/*
+ * Copyright 2010 by the Widelands Development Team
+ *
+ * This program 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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "gl_surface_screen.h"
+
+#include "gl_picture_texture.h"
+#include "gl_utils.h"
+#include "graphic/graphic.h"
+#include "upcast.h"
+
+GLSurfaceScreen::GLSurfaceScreen(uint32_t w, uint32_t h)
+{
+	m_w = w;
+	m_h = h;
+}
+
+bool GLSurfaceScreen::valid()
+{
+	return true;
+}
+
+uint32_t GLSurfaceScreen::get_w()
+{
+	return m_w;
+}
+
+uint32_t GLSurfaceScreen::get_h()
+{
+	return m_h;
+}
+
+void GLSurfaceScreen::update()
+{
+	assert(g_opengl);
+	SDL_GL_SwapBuffers();
+}
+
+const SDL_PixelFormat & GLSurfaceScreen::format() const
+{
+	return gl_rgba_format();
+}
+
+void GLSurfaceScreen::lock(IPixelAccess::LockMode mode)
+{
+	assert(!m_pixels);
+
+	m_pixels.reset(new uint8_t[m_w * m_h * 4]);
+
+	if (mode == Lock_Normal)
+		glReadPixels(0, 0, m_w, m_h, GL_RGBA, GL_UNSIGNED_BYTE, m_pixels.get());
+}
+
+void GLSurfaceScreen::unlock(IPixelAccess::UnlockMode mode)
+{
+	assert(m_pixels);
+
+	if (mode == Unlock_Update)
+		glDrawPixels(m_w, m_h, GL_RGBA, GL_UNSIGNED_BYTE, m_pixels.get());
+
+	m_pixels.reset(0);
+}
+
+uint16_t GLSurfaceScreen::get_pitch() const
+{
+	return 4 * m_w;
+}
+
+uint8_t * GLSurfaceScreen::get_pixels() const
+{
+	return m_pixels.get();
+}
+
+uint32_t GLSurfaceScreen::get_pixel(uint32_t x, uint32_t y)
+{
+	assert(m_pixels);
+	assert(x < m_w);
+	assert(y < m_h);
+
+	uint8_t * data = &m_pixels[4 * (y * m_w + x)];
+	return *(reinterpret_cast<uint32_t *>(data));
+}
+
+void GLSurfaceScreen::set_pixel(uint32_t x, uint32_t y, Uint32 clr)
+{
+	assert(m_pixels);
+	assert(x < m_w);
+	assert(y < m_h);
+
+	uint8_t * data = &m_pixels[4 * (y * m_w + x)];
+	*(reinterpret_cast<uint32_t *>(data)) = clr;
+}
+
+/**
+ * Draws the outline of a rectangle
+ */
+void GLSurfaceScreen::draw_rect(const Rect rc, const RGBColor clr)
+{
+	assert(g_opengl);
+	glDisable(GL_BLEND);
+	glDisable(GL_TEXTURE_2D);
+
+	glBegin(GL_LINE_LOOP); {
+		glColor3ub(clr.r(), clr.g(), clr.b());
+		glVertex2f(rc.x + 0.5f,        rc.y + 0.5f);
+		glVertex2f(rc.x + rc.w - 0.5f, rc.y + 0.5f);
+		glVertex2f(rc.x + rc.w - 0.5f, rc.y + rc.h - 0.5f);
+		glVertex2f(rc.x + 0.5f,        rc.y + rc.h - 0.5f);
+	} glEnd();
+	glEnable(GL_TEXTURE_2D);
+}
+
+
+/**
+ * Draws a filled rectangle
+ */
+void GLSurfaceScreen::fill_rect(const Rect rc, const RGBAColor clr) {
+	assert(rc.x >= 0);
+	assert(rc.y >= 0);
+	assert(rc.w >= 0);
+	assert(rc.h >= 0);
+	assert(g_opengl);
+
+	glDisable(GL_TEXTURE_2D);
+	glDisable(GL_BLEND);
+
+	glBegin(GL_QUADS); {
+		glColor4ub(clr.r, clr.g, clr.b, clr.a);
+		glVertex2f(rc.x,        rc.y);
+		glVertex2f(rc.x + rc.w, rc.y);
+		glVertex2f(rc.x + rc.w, rc.y + rc.h);
+		glVertex2f(rc.x,        rc.y + rc.h);
+	} glEnd();
+	glEnable(GL_TEXTURE_2D);
+}
+
+/**
+ * Change the brightness of the given rectangle
+ */
+void GLSurfaceScreen::brighten_rect(const Rect rc, const int32_t factor)
+{
+	if (!factor)
+		return;
+
+	assert(rc.x >= 0);
+	assert(rc.y >= 0);
+	assert(rc.w >= 1);
+	assert(rc.h >= 1);
+	assert(g_opengl);
+
+	/* glBlendFunc is a very nice feature of opengl. You can specify how the
+	* color is calculated.
+	*
+	* glBlendFunc(GL_ONE, GL_ONE) means the following:
+	* Rnew = Rdest + Rsrc
+	* Gnew = Gdest + Gsrc
+	* Bnew = Bdest + Bsrc
+	* Anew = Adest + Asrc
+	* where Xnew is the new calculated color for destination, Xdest is the old
+	* color of the destination and Xsrc is the color of the source.
+	*/
+	glEnable(GL_BLEND);
+	glDisable(GL_TEXTURE_2D);
+	glBlendFunc(GL_ONE, GL_ONE);
+
+	// And now simply draw a rect with facor as the color
+	// (this is the source color) over the region
+	glBegin(GL_QUADS); {
+		glColor3f
+			((static_cast<GLfloat>(factor) / 256.0f),
+			 (static_cast<GLfloat>(factor) / 256.0f),
+			 (static_cast<GLfloat>(factor) / 256.0f));
+		glVertex2f(rc.x,        rc.y);
+		glVertex2f(rc.x + rc.w, rc.y);
+		glVertex2f(rc.x + rc.w, rc.y + rc.h);
+		glVertex2f(rc.x,        rc.y + rc.h);
+	} glEnd();
+}
+
+void GLSurfaceScreen::draw_line
+		(int32_t x1,
+		 int32_t y1,
+		 int32_t x2,
+		 int32_t y2,
+		 RGBColor color,
+		 const Rect * clip)
+{
+	if (clip) {
+		glPushAttrib(GL_ENABLE_BIT | GL_SCISSOR_BIT);
+		glScissor
+			(clip->x, g_gr->get_yres() - clip->y - clip->h, clip->w, clip->h);
+		glEnable(GL_SCISSOR_TEST);
+	}
+	glDisable(GL_BLEND);
+	glDisable(GL_TEXTURE_2D);
+	glBegin(GL_LINES); {
+		glColor3ub(color.r(), color.g(), color.b());
+		glVertex2f(x1 + 0.5f, y1 + 0.5f);
+		glVertex2f(x2 + 0.5f, y2 + 0.5f);
+	} glEnd();
+	if (clip) {
+		glPopAttrib();
+	}
+}
+
+/**
+ * Clear the entire screen to black
+ */
+void GLSurfaceScreen::clear()
+{
+	assert(g_opengl);
+	glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+	glClear(GL_COLOR_BUFFER_BIT);
+}
+
+
+void GLSurfaceScreen::blit
+	(Point const dst, PictureID const src, Rect const srcrc, Composite cm)
+{
+	upcast(GLPictureTexture, oglsrc, src.get());
+	assert(oglsrc);
+	assert(g_opengl);
+
+	/* Set a texture scaling factor. Normaly texture coordiantes
+	* (see glBegin()...glEnd() Block below) are given in the range 0-1
+	* to avoid the calculation (and let opengl do it) the texture
+	* space is modified. glMatrixMode select which matrix to manipulate
+	* (the texture transformation matrix in this case). glLoadIdentity()
+	* resets the (selected) matrix to the identity matrix. And finally
+	* glScalef() calculates the texture matrix.
+	*/
+	glMatrixMode(GL_TEXTURE);
+	glLoadIdentity();
+	glScalef
+		(1.0f / static_cast<GLfloat>(oglsrc->get_tex_w()),
+		 1.0f / static_cast<GLfloat>(oglsrc->get_tex_h()), 1);
+
+	// Enable Alpha blending
+	if (cm == CM_Normal) {
+		glEnable(GL_BLEND);
+		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+	} else {
+		glDisable(GL_BLEND);
+	}
+
+	glEnable(GL_TEXTURE_2D);
+	glBindTexture(GL_TEXTURE_2D, oglsrc->get_gl_texture());
+
+	glBegin(GL_QUADS); {
+		//  set color white, otherwise textures get mixed with color
+		glColor3f(1.0, 1.0, 1.0);
+		//  top-left
+		glTexCoord2i(srcrc.x,           srcrc.y);
+		glVertex2i  (dst.x,             dst.y);
+		//  top-right
+		glTexCoord2i(srcrc.x + srcrc.w, srcrc.y);
+		glVertex2f  (dst.x + srcrc.w,   dst.y);
+		//  bottom-right
+		glTexCoord2i(srcrc.x + srcrc.w, srcrc.y + srcrc.h);
+		glVertex2f  (dst.x + srcrc.w,   dst.y + srcrc.h);
+		//  bottom-left
+		glTexCoord2i(srcrc.x,           srcrc.y + srcrc.h);
+		glVertex2f  (dst.x,             dst.y + srcrc.h);
+	} glEnd();
+
+	glLoadIdentity();
+}
+
+void GLSurfaceScreen::fast_blit(PictureID src)
+{
+	blit(Point(0, 0), src, Rect(Point(0, 0), src->get_w(), src->get_h()), CM_Normal);
+}

=== added file 'src/graphic/render/gl_surface_screen.h'
--- src/graphic/render/gl_surface_screen.h	1970-01-01 00:00:00 +0000
+++ src/graphic/render/gl_surface_screen.h	2010-11-27 16:29:59 +0000
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2010 by the Widelands Development Team
+ *
+ * This program 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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef GL_SURFACE_SCREEN_H
+#define GL_SURFACE_SCREEN_H
+
+#include <boost/scoped_array.hpp>
+
+#include "graphic/picture_id.h"
+#include "graphic/pixelaccess.h"
+#include "graphic/surface.h"
+
+/**
+ * This surface represents the screen in OpenGL mode.
+ */
+struct GLSurfaceScreen : Surface, IPixelAccess {
+	GLSurfaceScreen(uint32_t w, uint32_t h);
+
+	/// Interface implementations
+	//@{
+	virtual bool valid();
+
+	virtual uint32_t get_w();
+	virtual uint32_t get_h();
+
+	virtual void update();
+
+	virtual const SDL_PixelFormat & format() const;
+	virtual void lock(LockMode);
+	virtual void unlock(UnlockMode);
+	virtual uint16_t get_pitch() const;
+	virtual uint8_t * get_pixels() const;
+	virtual void set_pixel(uint32_t x, uint32_t y, Uint32 clr);
+	virtual uint32_t get_pixel(uint32_t x, uint32_t y);
+	virtual IPixelAccess & pixelaccess() {return *this;}
+
+	virtual void clear();
+	virtual void draw_rect(Rect, RGBColor);
+	virtual void fill_rect(Rect, RGBAColor);
+	virtual void brighten_rect(Rect, int32_t factor);
+
+	virtual void draw_line
+		(int32_t x1, int32_t y1,
+		 int32_t x2, int32_t y2,
+		 RGBColor, Rect const * clip = 0);
+
+	virtual void blit(Point, PictureID, Rect srcrc, Composite cm);
+	virtual void fast_blit(PictureID);
+	//@}
+
+private:
+	/// Size of the screen
+	uint32_t m_w, m_h;
+
+	/// Pixel data while locked
+	boost::scoped_array<uint8_t> m_pixels;
+};
+
+#endif // GL_SURFACE_SCREEN_H

=== added file 'src/graphic/render/gl_utils.cc'
--- src/graphic/render/gl_utils.cc	1970-01-01 00:00:00 +0000
+++ src/graphic/render/gl_utils.cc	2010-11-27 16:29:59 +0000
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2010 by the Widelands Development Team
+ *
+ * This program 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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "gl_utils.h"
+
+#include <SDL_video.h>
+
+#include "log.h"
+
+/**
+ * Return the smallest power of two greater than or equal to \p x.
+ */
+uint32_t next_power_of_two(uint32_t x)
+{
+	uint32_t pot = 1;
+
+	while (pot < x)
+		pot *= 2;
+
+	return pot;
+}
+
+/**
+ * \return the standard 32-bit RGBA format that we use in OpenGL
+ */
+const SDL_PixelFormat & gl_rgba_format()
+{
+	static SDL_PixelFormat format;
+	static bool init = false;
+	if (init)
+		return format;
+
+	init = true;
+	memset(&format, 0, sizeof(format));
+	format.BitsPerPixel = 32;
+	format.BytesPerPixel = 4;
+	format.Rmask = 0x000000ff;
+	format.Gmask = 0x0000ff00;
+	format.Bmask = 0x00ff0000;
+	format.Amask = 0xff000000;
+	format.Rshift = 0;
+	format.Gshift = 8;
+	format.Bshift = 16;
+	format.Ashift = 24;
+	return format;
+}
+
+GLenum _handle_glerror(const char * file, unsigned int line)
+{
+	GLenum err = glGetError();
+#ifdef DEBUG
+	if (err == GL_NO_ERROR)
+		return err;
+
+	log("%s:%d: OpenGL ERROR: ", file, line);
+
+	switch (err)
+	{
+	case GL_INVALID_VALUE:
+		log("invalid value\n");
+		break;
+	case GL_INVALID_ENUM:
+		log("invalid enum\n");
+		break;
+	case GL_INVALID_OPERATION:
+		log("invalid operation\n");
+		break;
+	case GL_STACK_OVERFLOW:
+		log("stack overflow\n");
+		break;
+	case GL_STACK_UNDERFLOW:
+		log("stack undeflow\n");
+		break;
+	case GL_OUT_OF_MEMORY:
+		log("out of memory\n");
+		break;
+	case GL_TABLE_TOO_LARGE:
+		log("table too large\n");
+		break;
+	default:
+		log("unknown\n");
+	}
+#endif
+	return err;
+}

=== added file 'src/graphic/render/gl_utils.h'
--- src/graphic/render/gl_utils.h	1970-01-01 00:00:00 +0000
+++ src/graphic/render/gl_utils.h	2010-11-27 16:29:59 +0000
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2010 by the Widelands Development Team
+ *
+ * This program 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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef GL_UTILS_H
+#define GL_UTILS_H
+
+#include <stdint.h>
+#include <SDL_opengl.h>
+
+struct SDL_PixelFormat;
+
+uint32_t next_power_of_two(uint32_t x);
+const SDL_PixelFormat & gl_rgba_format();
+GLenum _handle_glerror(const char * file, unsigned int line);
+
+/**
+ * handle_glerror() is intended to make debugging of oengl easier. It logs the
+ * error code returned by glGetError and returns the error code.
+ */
+#define handle_glerror() _handle_glerror(__FILE__, __LINE__)
+
+#endif // GL_UTILS_H

=== removed file 'src/graphic/render/render_opengl.cc'
--- src/graphic/render/render_opengl.cc	2010-11-01 22:37:46 +0000
+++ src/graphic/render/render_opengl.cc	1970-01-01 00:00:00 +0000
@@ -1,269 +0,0 @@
-/*
- * Copyright 2010 by the Widelands Development Team
- *
- * This program 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; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program 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 this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "graphic/graphic.h"
-#include "surface_opengl.h"
-
-#include "log.h"
-#include "upcast.h"
-#include "wexception.h"
-
-#include <SDL.h>
-
-
-#ifdef USE_OPENGL
-
-/*
- * Updating the whole Surface
- */
-void SurfaceOpenGL::update() {
-	assert(g_opengl);
-	SDL_GL_SwapBuffers();
-}
-
-/*
-===============
-Draws the outline of a rectangle
-===============
-*/
-void SurfaceOpenGL::draw_rect(const Rect rc, const RGBColor clr) {
-	assert(g_opengl);
-	//log("SurfaceOpenGL::draw_rect() for opengl is experimental\n");
-	glDisable(GL_BLEND);
-	glDisable(GL_TEXTURE_2D);
-
-	glBegin(GL_LINE_LOOP); {
-		glColor3ub(clr.r(), clr.g(), clr.b());
-		glVertex2f(m_offsx + rc.x + 0.5f,        m_offsy + rc.y + 0.5f);
-		glVertex2f(m_offsx + rc.x + rc.w - 0.5f, m_offsy + rc.y + 0.5f);
-		glVertex2f(m_offsx + rc.x + rc.w - 0.5f, m_offsy + rc.y + rc.h - 0.5f);
-		glVertex2f(m_offsx + rc.x + 0.5f,        m_offsy + rc.y + rc.h - 0.5f);
-	} glEnd();
-	glEnable(GL_TEXTURE_2D);
-}
-
-
-/*
-===============
-Draws a filled rectangle
-===============
-*/
-void SurfaceOpenGL::fill_rect(const Rect rc, const RGBAColor clr) {
-	assert(rc.x >= 0);
-	assert(rc.y >= 0);
-	assert(rc.w >= 0);
-	assert(rc.h >= 0);
-	assert(g_opengl);
-
-	glDisable(GL_TEXTURE_2D);
-	glDisable(GL_BLEND);
-
-	glBegin(GL_QUADS); {
-		glColor4ub(clr.r, clr.g, clr.b, clr.a);
-		glVertex2f(m_offsx + rc.x,        m_offsy + rc.y);
-		glVertex2f(m_offsx + rc.x + rc.w, m_offsy + rc.y);
-		glVertex2f(m_offsx + rc.x + rc.w, m_offsy + rc.y + rc.h);
-		glVertex2f(m_offsx + rc.x,        m_offsy + rc.y + rc.h);
-	} glEnd();
-	glEnable(GL_TEXTURE_2D);
-}
-
-/*
-===============
-Change the brightness of the given rectangle
-This function is slow as hell.
-
-* This function is a possible point to optimize on
-  slow system. It takes a lot of cpu time atm and is
-  not needed. It is used by the ui_basic stuff to
-  highlight things.
-===============
-*/
-void SurfaceOpenGL::brighten_rect(const Rect rc, const int32_t factor) {
-	if (!factor)
-		return;
-
-	assert(rc.x >= 0);
-	assert(rc.y >= 0);
-	assert(rc.w >= 1);
-	assert(rc.h >= 1);
-	assert(g_opengl);
-
-	/* glBlendFunc is a very nice feature of opengl. You can specify how the
-	* color is calculated.
-	*
-	* glBlendFunc(GL_ONE, GL_ONE) means the following:
-	* Rnew = Rdest + Rsrc
-	* Gnew = Gdest + Gsrc
-	* Bnew = Bdest + Bsrc
-	* Anew = Adest + Asrc
-	* where Xnew is the new calculated color for destination, Xdest is the old
-	* color of the destination and Xsrc is the color of the source.
-	*/
-	glEnable(GL_BLEND);
-	glDisable(GL_TEXTURE_2D);
-	glBlendFunc(GL_ONE, GL_ONE);
-
-	// And now simply draw a rect with facor as the color
-	// (this is the source color) over the region
-	glBegin(GL_QUADS); {
-		glColor3f
-			((static_cast<GLfloat>(factor) / 256.0f),
-			 (static_cast<GLfloat>(factor) / 256.0f),
-			 (static_cast<GLfloat>(factor) / 256.0f));
-		glVertex2f(m_offsx + rc.x,        m_offsy + rc.y);
-		glVertex2f(m_offsx + rc.x + rc.w, m_offsy + rc.y);
-		glVertex2f(m_offsx + rc.x + rc.w, m_offsy + rc.y + rc.h);
-		glVertex2f(m_offsx + rc.x,        m_offsy + rc.y + rc.h);
-	} glEnd();
-}
-
-void SurfaceOpenGL::draw_line
-		(int32_t x1,
-		 int32_t y1,
-		 int32_t x2,
-		 int32_t y2,
-		 RGBColor color,
-		 const Rect * clip)
-{
-	if (clip) {
-		glPushAttrib(GL_ENABLE_BIT | GL_SCISSOR_BIT);
-		glScissor
-			(clip->x, g_gr->get_yres() - clip->y - clip->h, clip->w, clip->h);
-		glEnable(GL_SCISSOR_TEST);
-	}
-	glDisable(GL_BLEND);
-	glDisable(GL_TEXTURE_2D);
-	glBegin(GL_LINES); {
-		glColor3ub(color.r(), color.g(), color.b());
-		glVertex2f(x1 + m_offsx + 0.5f, y1 + m_offsy + 0.5f);
-		glVertex2f(x2 + m_offsx + 0.5f, y2 + m_offsy + 0.5f);
-	} glEnd();
-	if (clip) {
-		glPopAttrib();
-	}
-}
-
-/*
-===============
-Clear the entire bitmap to black
-===============
-*/
-void SurfaceOpenGL::clear()
-{
-	assert(g_opengl);
-	glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
-	glClear(GL_COLOR_BUFFER_BIT);
-	return;
-}
-
-
-void SurfaceOpenGL::blit
-	(Point const dst, Surface * const src, Rect const srcrc, bool enable_alpha)
-{
-	blit(Rect(dst, srcrc.w, srcrc.h), src, srcrc, enable_alpha);
-}
-
-
-void SurfaceOpenGL::blit
-	(Rect dst, Surface * src, Rect srcrc, bool enable_alpha)
-{
-	upcast(SurfaceOpenGL, oglsrc, src);
-
-	assert(g_opengl);
-#ifdef DEBUG
-	if (m_surf_type != SURFACE_SCREEN)
-	{
-		throw wexception
-			("Surface not the screen: Offscreen rendering not possible");
-		return;
-	}
-
-	if (not oglsrc)
-	{
-		throw wexception("Invalid surface: Not a opengl surface");
-	}
-#endif
-	GLuint tex;
-
-	try {
-		tex = oglsrc->get_texture();
-	} catch (...) {
-		throw wexception
-			("SurfaceOpenGL::blit(): Source surface has no texture\n");
-		return;
-	}
-
-	/* Set a texture scaling factor. Normaly texture coordiantes
-	* (see glBegin()...glEnd() Block below) are given in the range 0-1
-	* to avoid the calculation (and let opengl do it) the texture
-	* space is modified. glMatrixMode select which matrix to manipulate
-	* (the texture transformation matrix in this case). glLoadIdentity()
-	* resets the (selected) matrix to the identity matrix. And finally
-	* glScalef() calculates the texture matrix.
-	*/
-	glMatrixMode(GL_TEXTURE);
-	glLoadIdentity();
-	glScalef
-		(1.0f / static_cast<GLfloat>(oglsrc->get_tex_w()),
-		 1.0f / static_cast<GLfloat>(oglsrc->get_tex_h()), 1);
-
-	// Enable Alpha blending
-	if (enable_alpha) {
-		glEnable(GL_BLEND);
-		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-	} else
-		glDisable(GL_BLEND);
-
-	/* select the texture to paint on the screen
-	* openGL does not know anything about SDL_Surfaces
-	* opengl uses textures to handle images
-	* getTexture() returns the texture id of the Surface. It creates
-	* the texture from the SDL_Surface if it doesn't exist
-	*/
-	glEnable(GL_TEXTURE_2D);
-	glBindTexture(GL_TEXTURE_2D, tex);
-
-	/* This block between blBegin() and glEnd() does the blit.
-	* It draws a textured rectangle. glTexCoord2i() set the Texture
-	* Texture cooardinates. This is the source rectangle.
-	* glVertex2f() sets the screen coordiantes which belong to the
-	* previous texture coordinate. This is the destination rectangle
-	*/
-
-	glBegin(GL_QUADS); {
-		//  set color white, otherwise textures get mixed with color
-		glColor3f(1.0, 1.0, 1.0);
-		//  top-left
-		glTexCoord2i(srcrc.x,           srcrc.y);
-		glVertex2i  (m_offsx + dst.x,   m_offsy + dst.y);
-		//  top-right
-		glTexCoord2i(srcrc.x + srcrc.w, srcrc.y);
-		glVertex2f  (m_offsx + dst.x + dst.w,  m_offsy + dst.y);
-		//  bottom-right
-		glTexCoord2i(srcrc.x + srcrc.w, srcrc.y + srcrc.h);
-		glVertex2f  (m_offsx + dst.x + dst.w,  m_offsy + dst.y + dst.h);
-		//  bottom-left
-		glTexCoord2i(srcrc.x,           srcrc.y + srcrc.h);
-		glVertex2f  (m_offsx + dst.x,   m_offsy + dst.y + dst.h);
-	} glEnd();
-
-	glLoadIdentity();
-}
-
-#endif //USE_OPENGL

=== modified file 'src/graphic/render/render_sdl.cc'
--- src/graphic/render/render_sdl.cc	2010-11-01 22:37:46 +0000
+++ src/graphic/render/render_sdl.cc	2010-11-27 16:29:59 +0000
@@ -49,7 +49,7 @@
  * Updating the whole Surface
  */
 void SurfaceSDL::update() {
-	if (m_surf_type == SURFACE_SCREEN) {
+	if (m_isscreen) {
 		//flip defaults to SDL_UpdateRect(m_surface, 0, 0, 0, 0);
 		SDL_Flip(m_surface);
 		//log("SurfaceSDL::update(): update complete screen\n");
@@ -128,7 +128,7 @@
 
 	const Point bl = rc.bottom_left();
 
-	lock();
+	lock(IPixelAccess::Lock_Normal);
 
 	if (m_surface->format->BytesPerPixel == 4)
 	{
@@ -183,7 +183,7 @@
 				SDL_MapRGB(m_surface->format, r, g, b);
 		}
 	}
-	unlock();
+	unlock(IPixelAccess::Unlock_Update);
 }
 
 #define draw_pixel(p, r, clr)                                                 \
@@ -257,24 +257,35 @@
 
 
 void SurfaceSDL::blit
-	(Point const dst, Surface * const src, Rect const srcrc, bool enable_alpha)
+	(Point const dst, PictureID src, Rect const srcrc, Composite cm)
 {
-	assert(src);
+	upcast(SurfaceSDL, sdlsurf, src.get());
+	assert(sdlsurf);
 	assert(this);
 	SDL_Rect srcrect = {srcrc.x, srcrc.y, srcrc.w, srcrc.h};
 	SDL_Rect dstrect = {dst.x, dst.y, 0, 0};
 
-	SDL_BlitSurface
-		(dynamic_cast<SurfaceSDL *>(src)->get_sdl_surface(),
-		 &srcrect, m_surface, &dstrect);
+	bool alpha;
+	uint8_t alphaval;
+	if (cm == CM_Solid || cm == CM_Copy) {
+		alpha = sdlsurf->get_sdl_surface()->flags & SDL_SRCALPHA;
+		alphaval = sdlsurf->get_sdl_surface()->format->alpha;
+		SDL_SetAlpha(sdlsurf->get_sdl_surface(), 0, 0);
+	}
+
+	SDL_BlitSurface(sdlsurf->get_sdl_surface(), &srcrect, m_surface, &dstrect);
+
+	if (cm == CM_Solid || cm == CM_Copy) {
+		SDL_SetAlpha(sdlsurf->get_sdl_surface(), alpha?SDL_SRCALPHA:0, alphaval);
+	}
 }
 
 
 /*
  * Fast blit, simply copy the source to the destination
  */
-void SurfaceSDL::fast_blit(Surface * const src) {
+void SurfaceSDL::fast_blit(PictureID const src) {
 	SDL_BlitSurface
-		(dynamic_cast<SurfaceSDL *>(src)->get_sdl_surface(),
+		(dynamic_cast<SurfaceSDL *>(src.get())->get_sdl_surface(),
 		 0, m_surface, 0);
 }

=== removed file 'src/graphic/render/surface_opengl.cc'
--- src/graphic/render/surface_opengl.cc	2010-11-01 22:37:46 +0000
+++ src/graphic/render/surface_opengl.cc	1970-01-01 00:00:00 +0000
@@ -1,381 +0,0 @@
-/*
- * Copyright 2010 by the Widelands Development Team
- *
- * This program 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; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program 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 this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "surface_opengl.h"
-#include "log.h"
-#include "graphic/graphic.h"
-
-#include <cassert>
-#include <cmath>
-
-#ifdef USE_OPENGL
-
-long unsigned int pix_used = 0;
-long unsigned int pix_aloc = 0;
-long unsigned int num_tex = 0;
-
-#define handle_glerror() _handle_glerror(__FILE__, __LINE__)
-
-SDL_PixelFormat * rgbafmt = 0;
-
-/* handle_glerror() is intended to make debugging of oengl easier. It logs the
- * error code returned by glGetError and returns the error code.
- */
-GLenum _handle_glerror(const char * file, unsigned int line)
-{
-	GLenum err = glGetError();
-#ifdef DEBUG
-	if (err == GL_NO_ERROR)
-		return err;
-
-	log("%s:%d: OpenGL ERROR: ", file, line);
-
-	switch (err)
-	{
-	case GL_INVALID_VALUE:
-		log("invalid value\n");
-		break;
-	case GL_INVALID_ENUM:
-		log("invalid enum\n");
-		break;
-	case GL_INVALID_OPERATION:
-		log("invalid operation\n");
-		break;
-	case GL_STACK_OVERFLOW:
-		log("stack overflow\n");
-		break;
-	case GL_STACK_UNDERFLOW:
-		log("stack undeflow\n");
-		break;
-	case GL_OUT_OF_MEMORY:
-		log("out of memory\n");
-		break;
-	case GL_TABLE_TOO_LARGE:
-		log("table too large\n");
-		break;
-	default:
-		log("unknown\n");
-	}
-#endif
-	return err;
-}
-
-SurfaceOpenGL::SurfaceOpenGL(SDL_Surface & par_surface):
-	Surface(par_surface.w, par_surface.h, SURFACE_SOURCE),
-	m_glTexUpdate(false),
-	m_pixels     (0),
-	m_locked(false)
-{
-	GLuint texture;
-	SDL_Surface * surface;
-	GLenum pixels_format, pixels_type;
-	GLint  Bpp;
-
-	handle_glerror();
-
-	surface = &par_surface;
-
-	if (g_gr->caps().gl.tex_power_of_two)
-	{
-		int wexp = log(static_cast<float>(surface->w)) / log(2.0f);
-		int hexp = log(static_cast<float>(surface->h)) / log(2.0f);
-		if (pow(2.0f, wexp) < surface->w)
-			wexp++;
-		if (pow(2.0f, hexp) < surface->h)
-			hexp++;
-
-		m_tex_w = pow(2.0f, wexp);
-		m_tex_h = pow(2.0f, hexp);
-	} else {
-		m_tex_w = surface->w;
-		m_tex_h = surface->h;
-	}
-
-	if
-		(surface->format->palette or (surface->format->colorkey > 0) or
-		 m_tex_w != static_cast<uint32_t>(surface->w) or
-		 m_tex_h != static_cast<uint32_t>(surface->h))
-	{
-		//log("SurfaceOpenGL: convert surface for opengl\n");
-		surface = SDL_CreateRGBSurface
-			(SDL_SWSURFACE, m_tex_w, m_tex_h,
-			 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
-		assert(surface);
-		//SDL_DisplayFormatAlpha(&par_surface);
-		SDL_SetAlpha(surface, 0, 0);
-		SDL_SetAlpha(&par_surface, 0, 0);
-		SDL_BlitSurface(&par_surface, 0, surface, 0);
-		SDL_FreeSurface(&par_surface);
-	}
-
-	SDL_PixelFormat const & fmt = *surface->format;
-	Bpp = fmt.BytesPerPixel;
-
-	/* log
-		("SurfaceOpenGL::SurfaceOpenGL(SDL_Surface) Size: (%d, %d) %db(%dB) ",
-		 m_tex_w, m_tex_h,
-		 fmt.BitsPerPixel, Bpp);
-	log("R:%X, G:%X, B:%X, A:%X", fmt.Rmask, fmt.Gmask, fmt.Bmask, fmt.Amask); */
-
-	glPushAttrib(GL_PIXEL_MODE_BIT);
-	bool pushed = not (handle_glerror() == GL_STACK_OVERFLOW);
-
-	if (Bpp == 4)
-	{
-		if
-			(fmt.Rmask == 0x000000ff and fmt.Gmask == 0x0000ff00 and
-			 fmt.Bmask == 0x00ff0000)
-		{
-			if (fmt.Amask == 0xff000000)
-			{
-				pixels_format = GL_RGBA; //log(" RGBA 8888 ");
-			} else {
-				pixels_format = GL_RGBA; //log(" RGB 8880 ");
-				// Read four bytes per pixel but ignore the alpha value
-				glPixelTransferi(GL_ALPHA_SCALE, 0.0f);
-				glPixelTransferi(GL_ALPHA_BIAS, 1.0f);
-			}
-		} else if
-			(fmt.Bmask == 0x000000ff and fmt.Gmask == 0x0000ff00 and
-			 fmt.Rmask == 0x00ff0000)
-		{
-			if (fmt.Amask == 0xff000000)
-			{
-				pixels_format = GL_BGRA; //log(" BGRA 8888 ");
-			} else {
-				pixels_format = GL_BGRA; //log(" BGR 8880 ");
-				// Read four bytes per pixel but ignore the alpha value
-				glPixelTransferi(GL_ALPHA_SCALE, 0.0f);
-				glPixelTransferi(GL_ALPHA_BIAS, 1.0f);
-			}
-		} else
-			throw wexception("OpenGL: Unknown pixel format");
-		pixels_type = GL_UNSIGNED_BYTE;
-	} else if (Bpp == 3)
-	{
-		if
-			(fmt.Rmask == 0x000000ff and fmt.Gmask == 0x0000ff00 and
-			 fmt.Bmask == 0x00ff0000)
-		{
-			pixels_format = GL_RGB; //log(" RGB 888 ");
-		} else if
-			(fmt.Bmask == 0x000000ff and fmt.Gmask == 0x0000ff00 and
-			 fmt.Rmask == 0x00ff0000)
-		{
-			pixels_format = GL_BGR; //log(" BGR 888 ");
-		} else
-			throw wexception("OpenGL: Unknown pixel format");
-		pixels_type = GL_UNSIGNED_BYTE;
-	} else if (Bpp == 2)
-	{
-		if (fmt.Rmask == 0xF800 and fmt.Gmask == 0x7E0 and fmt.Bmask == 0x1F)
-		{
-			pixels_format = GL_RGB; //log(" RGB 565");
-		} else if
-			(fmt.Bmask == 0xF800 and fmt.Gmask == 0x7E0 and fmt.Rmask == 0x1F)
-		{
-			pixels_format = GL_BGR; //log(" BGR 565");
-		} else
-			assert(false);
-		pixels_type = GL_UNSIGNED_SHORT_5_6_5;
-	} else
-		throw wexception("OpenGL: Unknown pixel format");
-	//log("\n");
-
-	// Let OpenGL create a texture object
-	glGenTextures(1, &texture);
-	handle_glerror();
-
-	// select the texture object
-	glBindTexture(GL_TEXTURE_2D, texture);
-	handle_glerror();
-
-	// set texture filter to use linear filtering. This looks nicer for resized
-	// texture. Most textures and images are not resized so the filtering
-	// makes no difference
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-	handle_glerror();
-
-	SDL_LockSurface(surface);
-
-	// glTexImage2D creates the texture of size (m_tex_w x m_tex_h) and copies
-	// the pixels for surface->pixels to it.
-	// The third parameter (internal format) specifies how opengl should store
-	//   the pixels. This has nothing to do with the read pixels
-	// 7th and 8th parameter (format and type) specify the format of the read
-	//   pixels (9th parameter)
-	glTexImage2D
-		(GL_TEXTURE_2D, 0, WL_GLINTERNALFORMAT, m_tex_w, m_tex_h, 0,
-		 pixels_format, pixels_type, surface->pixels);
-	handle_glerror();
-
-	if (pushed)
-		glPopAttrib();
-
-	SDL_UnlockSurface(surface);
-	SDL_FreeSurface(surface);
-
-	pix_used += m_w * m_h;
-	pix_aloc += m_tex_w * m_tex_h;
-	num_tex++;
-	/*
-	log
-		("texture stats: num: %lu, used: %lu (%luM), "
-		 "alocated: %lu (%luM) ++\n",
-		 num_tex, pix_used * 4, pix_used * 4 / (1024 * 1024),
-		 pix_aloc * 4, pix_aloc * 4/ (1024 * 1024));
-	*/
-	assert(glIsTexture(texture));
-
-	m_texture = new oglTexture(texture);
-	m_glTexUpdate = false;
-}
-
-
-SurfaceOpenGL::~SurfaceOpenGL() {
-	if (m_texture) {
-		pix_used -= m_w * m_h;
-		pix_aloc -= m_tex_w * m_tex_h;
-		num_tex--;
-		delete m_texture;
-	}
-	/* log
-		("~SurfaceOpenGL(): texture stats: num: %lu, "
-		 "used: %lu (%luM), alocated: %lu (%luM) --\n",
-		 num_tex, pix_used * 4, pix_used * 4 / (1024 * 1024),
-		 pix_aloc * 4, pix_aloc * 4/ (1024 * 1024)); */
-
-	delete[] m_pixels;
-}
-
-
-SurfaceOpenGL::SurfaceOpenGL(int const w, int const h):
-	Surface(w, h, SURFACE_SOURCE),
-	m_texture(0),
-	m_glTexUpdate(false),
-	m_pixels     (0),
-	m_locked(false)
-{
-	if (g_gr and g_gr->caps().gl.tex_power_of_two) {
-		//  Some old graphics cards support only opengl textures which have a
-		//  size of 2^n. To get it working on these cards we take the next equal
-		//  or greater power of two. This is a waste of graphics memory and
-		//  causes some problem with borders of textures and repeated textures
-		//  but at least it works.
-		int wexp = log(static_cast<float>(w)) / log(2.0f);
-		int hexp = log(static_cast<float>(h)) / log(2.0f);
-		if (pow(2.0f, wexp) < w)
-			wexp++;
-		if (pow(2.0f, hexp) < h)
-			hexp++;
-
-		m_tex_w = pow(2.0f, wexp);
-		m_tex_h = pow(2.0f, hexp);
-	} else {
-		m_tex_w = w;
-		m_tex_h = h;
-	}
-}
-
-/* This returns a SDL_Pixel format for the returned pixels. lock() copies the
- * pixels always as 32Bit RGBA. So we create and return a RGBA SDL_PixelFormat
- */
-const SDL_PixelFormat * SurfaceOpenGL::get_format() const
-{
-	if (rgbafmt)
-		return rgbafmt;
-	rgbafmt = new SDL_PixelFormat;
-	rgbafmt->BitsPerPixel = 32;
-	rgbafmt->BytesPerPixel = 4;
-	rgbafmt->Rmask = 0x000000ff; rgbafmt->Gmask = 0x0000ff00;
-	rgbafmt->Bmask = 0x00ff0000; rgbafmt->Amask = 0xff000000;
-	rgbafmt->Ashift = 24; rgbafmt->Bshift = 16; rgbafmt->Gshift = 8;
-	rgbafmt->Rshift = 0; rgbafmt->palette = 0;
-	return rgbafmt;
-}
-
-/* lock the surface for pixel access. This allocates memory and copies the
- * pixles from opengl texture to it. This copies the whole texture even if
- * only one pixel is read. So use this as rare as possible.
- */
-void SurfaceOpenGL::lock() {
-	if (m_locked)
-		return;
-	try {
-		if (m_surf_type == SURFACE_SCREEN)
-			m_pixels = new uint8_t[m_w * m_h * 4];
-		else
-			m_pixels = new uint8_t[m_tex_w * m_tex_h * 4];
-	} catch (std::bad_alloc) {
-		return;
-	}
-	if (m_surf_type == SURFACE_SCREEN)
-		glReadPixels
-			(0, 0, m_w, m_h, GL_RGBA, GL_UNSIGNED_BYTE, m_pixels);
-	else if (m_texture) {
-		assert(glIsTexture(m_texture->id()));
-		glBindTexture(GL_TEXTURE_2D, m_texture->id());
-		glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_pixels);
-		m_glTexUpdate = false;
-	} else
-		m_glTexUpdate = true;
-	//log("locked opengl surface(%d, %d)\n", m_tex_w, m_tex_h);
-	m_locked = true;
-}
-
-/* Unlock the surface after pixel access. This loads the pixels to the texture
- * if pixels were changed and free the alocated memory.
- */
-void SurfaceOpenGL::unlock() {
-	if (not m_locked)
-		return;
-	assert(m_pixels);
-
-	if (m_glTexUpdate) {
-		assert(m_surf_type != SURFACE_SCREEN);
-		if (!m_texture)
-		{
-			GLuint texture;
-			glGenTextures(1, &texture);
-
-			// selcet the texture object
-			glBindTexture(GL_TEXTURE_2D, texture);
-
-			// set texture filter to siply take the nearest pixel.
-			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-
-			pix_used += m_w * m_h;
-			pix_aloc += m_tex_w * m_tex_h;
-			num_tex++;
-
-			m_texture = new oglTexture(texture);
-		}
-		glBindTexture(GL_TEXTURE_2D, m_texture->id());;
-		glTexImage2D
-			(GL_TEXTURE_2D, 0, WL_GLINTERNALFORMAT, m_tex_w, m_tex_h, 0, GL_RGBA,
-			 GL_UNSIGNED_BYTE,  m_pixels);
-	}
-
-	delete [] m_pixels;
-	m_pixels = 0;
-	m_locked = false;
-}
-
-#endif //USE_OPENGL

=== removed file 'src/graphic/render/surface_opengl.h'
--- src/graphic/render/surface_opengl.h	2010-11-01 22:37:46 +0000
+++ src/graphic/render/surface_opengl.h	1970-01-01 00:00:00 +0000
@@ -1,170 +0,0 @@
-/*
- * Copyright 2010 by the Widelands Development Team
- *
- * This program 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; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program 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 this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#if !defined(SURFACE_OPENGL_H) and defined(USE_OPENGL)
-#define SURFACE_OPENGL_H
-
-#include "rgbcolor.h"
-#include "rect.h"
-#include "graphic/surface.h"
-
-#include <SDL_opengl.h>
-
-#include <cassert>
-
-#define WL_GLINTERNALFORMAT GL_RGBA
-
-namespace Widelands {
-struct Editor_Game_Base;
-struct Field;
-struct Player;
-}
-
-namespace UI {
-struct Font_Handler;
-}
-
-struct Vertex;
-
-/**
- * This implements OpenGL rendering. Do not use this class directly. The right
- * way is to use the base class Surface wherever possible. Everything which
- * needs to know about the underlying renderer should go to the graphics
- * subdirectory.
- * Surfaces are created through Graphic::create_surface() functions.
-*/
-class SurfaceOpenGL : public Surface {
-public:
-	/**
-	 * Manages a single OpenGL texture. This makes sure the texture is
-	 * freed when the object is destroyed.
-	*/
-	struct oglTexture {
-		oglTexture() {}
-		oglTexture(GLuint id): m_textureID(id) {}
-		~oglTexture() {glDeleteTextures(1, &m_textureID);}
-		GLuint id() const {return m_textureID;}
-	private:
-		GLuint m_textureID;
-	};
-
-	SurfaceOpenGL(SDL_Surface & surface);
-	explicit SurfaceOpenGL(int w = 0, int h = 0);
-	~SurfaceOpenGL();
-
-	//@{
-	/// Get width and height
-	uint32_t get_w() const {return m_w;}
-	uint32_t get_h() const {return m_h;}
-	uint32_t get_tex_w() const {return m_tex_w;}
-	uint32_t get_tex_h() const {return m_tex_h;}
-	//@}
-
-	void update();
-
-	GLuint get_texture() const
-	{
-#if defined(DEBUG)
-		if (m_surf_type != SURFACE_SOURCE)
-			throw wexception
-				("Try to get opengl texture id but not a source surface");
-		if (not m_texture)
-			throw wexception("no texture");
-#endif
-		return m_texture->id();
-	}
-
-	const SDL_PixelFormat * get_format() const;
-	SDL_PixelFormat const & format() const {return *get_format();}
-
-	/// Directly access the pixels. This is only valid if the surface is locked
-	inline uint16_t get_pitch() const {return m_tex_w * 4;}
-	uint8_t * get_pixels() const
-	{
-		assert(m_locked);
-		assert(m_pixels);
-		return m_pixels;
-	}
-
-	/// Lock: The Surface need to be locked before get or set pixel
-	void lock();
-	void unlock();
-
-	/// For the slowest: Indirect pixel access
-	inline uint32_t get_pixel(uint32_t x, uint32_t y) {
-		x += m_offsx;
-		y += m_offsy;
-
-		assert(x < get_w());
-		assert(y < get_h());
-		assert(m_locked);
-
-		return *reinterpret_cast<uint32_t *>(m_pixels + y * get_pitch() + x * 4);
-	}
-	inline void set_pixel(uint32_t x, uint32_t y, Uint32 clr) {
-		x += m_offsx;
-		y += m_offsy;
-
-		assert(x < get_w());
-		assert(y < get_h());
-		assert(m_locked);
-		m_glTexUpdate = true;
-
-		*reinterpret_cast<uint32_t *>(m_pixels + y * get_pitch() + x * 4) = clr;
-	}
-
-	void clear();
-	void draw_rect(Rect, RGBColor);
-	void fill_rect(Rect, RGBAColor);
-	void brighten_rect(Rect, int32_t factor);
-
-	void draw_line
-		(int32_t x1, int32_t y1,
-		 int32_t x2, int32_t y2,
-		 RGBColor, Rect const * clip = 0);
-
-	void blit(Point, Surface *, Rect srcrc, bool enable_alpha = true);
-	void blit(Rect dst, Surface *, Rect srcrc, bool enable_alpha = true);
-	//void fast_blit(Surface *);
-
-	oglTexture & getTexture() {return *m_texture;}
-
-private:
-	SurfaceOpenGL & operator= (SurfaceOpenGL const &);
-	explicit SurfaceOpenGL    (SurfaceOpenGL const &);
-
-	/// stores the opengl texture id and frees if destroyed
-	oglTexture * m_texture;
-	/// Indicates that the texture needs to be updated after pixel access
-	bool m_glTexUpdate;
-
-	//@{
-	/// set/unset a clipping rectangle
-	void set_subwin(Rect r);
-	void unset_subwin();
-	//@}
-
-	uint8_t * m_pixels;
-	bool m_locked;
-
-	/// Keep the size of the opengl texture. This is necessary because some
-	/// systems support only a power of two for texture sizes.
-	uint32_t m_tex_w, m_tex_h;
-};
-
-#endif

=== modified file 'src/graphic/render/surface_sdl.cc'
--- src/graphic/render/surface_sdl.cc	2010-05-18 13:21:05 +0000
+++ src/graphic/render/surface_sdl.cc	2010-11-27 16:29:59 +0000
@@ -25,7 +25,7 @@
 
 SurfaceSDL::~SurfaceSDL() {
 	//log("SurfaceSDL::~SurfaceSDL()\n");
-	if (m_surface and m_surf_type != SURFACE_SCREEN)
+	if (m_surface and !m_isscreen)
 		SDL_FreeSurface(m_surface);
 }
 
@@ -58,12 +58,12 @@
 		m_offsx * m_surface->format->BytesPerPixel;
 }
 
-void SurfaceSDL::lock() {
+void SurfaceSDL::lock(LockMode) {
 	if (SDL_MUSTLOCK(m_surface))
 		SDL_LockSurface(m_surface);
 }
 
-void SurfaceSDL::unlock() {
+void SurfaceSDL::unlock(UnlockMode) {
 	if (SDL_MUSTLOCK(m_surface))
 		SDL_UnlockSurface(m_surface);
 }
@@ -147,3 +147,8 @@
 	m_w = m_surface->w;
 	m_h = m_surface->h;
 }
+
+void SurfaceSDL::set_isscreen(bool screen)
+{
+	m_isscreen = screen;
+}

=== modified file 'src/graphic/render/surface_sdl.h'
--- src/graphic/render/surface_sdl.h	2010-11-01 22:37:46 +0000
+++ src/graphic/render/surface_sdl.h	2010-11-27 16:29:59 +0000
@@ -23,7 +23,7 @@
 #include "rgbcolor.h"
 #include "rect.h"
 
-#include "graphic/surface.h"
+#include "graphic/offscreensurface.h"
 
 /**
 * This implements SDL rendering. Do not use this class directly. The right
@@ -32,17 +32,24 @@
 * subdirectory.
 * Surfaces are created through Graphic::create_surface() functions.
 */
-struct SurfaceSDL : public Surface {
+struct SurfaceSDL : IOffscreenSurface {
 	SurfaceSDL(SDL_Surface & surface) :
-		Surface(surface.w, surface.h, SURFACE_OFFSCREEN),
-		m_surface(&surface)
+		m_surface(&surface),
+		m_offsx(0), m_offsy(0),
+		m_w(surface.w), m_h(surface.h),
+		m_isscreen(false)
 	{}
 	SurfaceSDL():
-		Surface(),
-		m_surface(0)
+		m_surface(0),
+		m_offsx(0), m_offsy(0),
+		m_w(0), m_h(0),
+		m_isscreen(false)
 	{}
 	~SurfaceSDL();
 
+	virtual uint32_t get_w() {return m_w;}
+	virtual uint32_t get_h() {return m_h;}
+
 	/// Set surface, only call once
 	void set_sdl_surface(SDL_Surface & surface);
 	SDL_Surface * get_sdl_surface() {return m_surface;}
@@ -53,21 +60,13 @@
 	/// Save a bitmap of this to a file
 	void save_bmp(const char & fname) const;
 
-/*
-	// For the bravest: Direct Pixel access. Use carefully
-	/// Needed if you want to blit directly to the screen by memcpy
-	void force_disable_alpha();
-	const SDL_PixelFormat * get_format() const;
-	uint16_t get_pitch() const {return m_surface->pitch;}
-*/
-
 	SDL_PixelFormat const & format() const;
 	uint8_t * get_pixels() const;
 	uint16_t get_pitch() const {return m_surface->pitch;}
 
 	/// Lock
-	void lock();
-	void unlock();
+	void lock(LockMode);
+	void unlock(UnlockMode);
 
 	/// For the slowest: Indirect pixel access
 	uint32_t get_pixel(uint32_t x, uint32_t y);
@@ -83,17 +82,27 @@
 		 int32_t x2, int32_t y2,
 		 RGBColor, Rect const * clip = 0);
 
-	void blit(Point, Surface *, Rect srcrc, bool enable_alpha = true);
-	void fast_blit(Surface *);
+	void blit(Point, PictureID, Rect srcrc, Composite cm);
+	void fast_blit(PictureID);
 
 	void set_subwin(Rect r);
 	void unset_subwin();
 
+	void set_isscreen(bool screen);
+
+	bool valid() {return m_surface;}
+
+	virtual IPixelAccess & pixelaccess() {return *this;}
+
 private:
 	SurfaceSDL & operator= (SurfaceSDL const &);
 	explicit SurfaceSDL    (SurfaceSDL const &);
 
 	SDL_Surface * m_surface;
+	int32_t m_offsx;
+	int32_t m_offsy;
+	uint32_t m_w, m_h;
+	bool m_isscreen;
 };
 
 #endif

=== modified file 'src/graphic/render/terrain_opengl.h'
--- src/graphic/render/terrain_opengl.h	2010-11-05 19:36:57 +0000
+++ src/graphic/render/terrain_opengl.h	2010-11-27 16:29:59 +0000
@@ -19,13 +19,12 @@
 
 #ifdef USE_OPENGL
 
-#include "surface_opengl.h"
+#include "gl_picture_texture.h"
 #include "vertex.h"
 
 
 void draw_field_opengl
-	(Surface & surf,
-	 Rect const & subwin,
+	(Rect const & subwin,
 	 Vertex const & p1,
 	 Vertex const & p2,
 	 Vertex const & p3,
@@ -122,11 +121,11 @@
 	uint8_t road;
 
 	GLuint rt_normal =
-		dynamic_cast<SurfaceOpenGL const &>
-		(*g_gr->get_road_texture(Widelands::Road_Normal)).get_texture();
+		dynamic_cast<GLPictureTexture const &>
+		(*g_gr->get_road_texture(Widelands::Road_Normal)).get_gl_texture();
 	GLuint rt_busy   =
-		dynamic_cast<SurfaceOpenGL const &>
-		(*g_gr->get_road_texture(Widelands::Road_Busy)).get_texture();
+		dynamic_cast<GLPictureTexture const &>
+		(*g_gr->get_road_texture(Widelands::Road_Busy)).get_gl_texture();
 
 	glDisable(GL_BLEND);
 	glColor4f(1.0f, 1.0f, 1.0f, 0.6f);

=== modified file 'src/graphic/render/terrain_sdl.h'
--- src/graphic/render/terrain_sdl.h	2010-11-05 19:36:57 +0000
+++ src/graphic/render/terrain_sdl.h	2010-11-27 16:29:59 +0000
@@ -23,6 +23,7 @@
 #include "constants.h"
 #include "log.h"
 #include "random.h"
+#include "upcast.h"
 #include "vertex.h"
 
 #include "wui/mapviewpixelconstants.h"
@@ -532,7 +533,7 @@
 }
 
 template<typename T> static void render_road_horiz
-	(SurfaceSDL & dst, Point const start, Point const end, Surface const & src)
+	(SurfaceSDL & dst, Point const start, Point const end, SurfaceSDL const & src)
 {
 	int32_t const dstw = dst.get_w();
 	int32_t const dsth = dst.get_h();
@@ -559,7 +560,7 @@
 }
 
 template<typename T> static void render_road_vert
-	(SurfaceSDL & dst, Point const start, Point const end, Surface const & src)
+	(SurfaceSDL & dst, Point const start, Point const end, SurfaceSDL const & src)
 {
 	int32_t const dstw = dst.get_w();
 	int32_t const dsth = dst.get_h();
@@ -597,10 +598,10 @@
 	 Texture const &  f_d_texture,
 	 Texture const &  f_r_texture)
 {
-	Surface const & rt_normal = *g_gr->get_road_texture(Widelands::Road_Normal);
-	Surface const & rt_busy   = *g_gr->get_road_texture(Widelands::Road_Busy);
+	upcast(SurfaceSDL, rt_normal, g_gr->get_road_texture(Widelands::Road_Normal).get());
+	upcast(SurfaceSDL, rt_busy, g_gr->get_road_texture(Widelands::Road_Busy).get());
 
-	dst.lock();
+	dst.lock(IPixelAccess::Lock_Normal);
 
 	render_triangle<T> (dst, f_vert, br_vert, r_vert, f_r_texture);
 	render_triangle<T> (dst, f_vert, bl_vert, br_vert, f_d_texture);
@@ -613,10 +614,10 @@
 		if (road) {
 			switch (road) {
 			case Widelands::Road_Normal:
-				render_road_horiz<T> (dst, f_vert, r_vert, rt_normal);
+				render_road_horiz<T> (dst, f_vert, r_vert, *rt_normal);
 				break;
 			case Widelands::Road_Busy:
-				render_road_horiz<T> (dst, f_vert, r_vert, rt_busy);
+				render_road_horiz<T> (dst, f_vert, r_vert, *rt_busy);
 				break;
 			default:
 				assert(false);
@@ -631,10 +632,10 @@
 		if (road) {
 			switch (road) {
 			case Widelands::Road_Normal:
-				render_road_vert<T> (dst, f_vert, br_vert, rt_normal);
+				render_road_vert<T> (dst, f_vert, br_vert, *rt_normal);
 				break;
 			case Widelands::Road_Busy:
-				render_road_vert<T> (dst, f_vert, br_vert, rt_busy);
+				render_road_vert<T> (dst, f_vert, br_vert, *rt_busy);
 				break;
 			default:
 				assert(false);
@@ -649,10 +650,10 @@
 		if (road) {
 			switch (road) {
 			case Widelands::Road_Normal:
-				render_road_vert<T> (dst, f_vert, bl_vert, rt_normal);
+				render_road_vert<T> (dst, f_vert, bl_vert, *rt_normal);
 				break;
 			case Widelands::Road_Busy:
-				render_road_vert<T> (dst, f_vert, bl_vert, rt_busy);
+				render_road_vert<T> (dst, f_vert, bl_vert, *rt_busy);
 				break;
 			default:
 				assert(false);
@@ -662,7 +663,7 @@
 		}
 	}
 
-	dst.unlock();
+	dst.unlock(IPixelAccess::Unlock_Update);
 
 	// FIXME: similar textures may not need dithering
 }

=== modified file 'src/graphic/rendertarget.cc'
--- src/graphic/rendertarget.cc	2010-06-14 19:31:37 +0000
+++ src/graphic/rendertarget.cc	2010-11-27 16:29:59 +0000
@@ -27,9 +27,7 @@
 #include "logic/tribe.h"
 #include "vertex.h"
 
-#include "surface.h"
-#include "graphic/render/surface_opengl.h"
-#include "graphic/render/surface_sdl.h"
+#include "offscreensurface.h"
 
 #include "log.h"
 #include "upcast.h"
@@ -43,16 +41,23 @@
 using Widelands::TCoords;
 
 /**
- * Build a render target for the given bitmap.
- * \note The bitmap will not be owned by the renderer, i.e. it won't be
- * deleted by the destructor.
+ * Build a render target for the given surface.
  */
-RenderTarget::RenderTarget(Surface * const bmp)
+RenderTarget::RenderTarget(SurfacePtr bmp)
 {
 	m_surface = bmp;
 	reset();
 }
 
+/**
+ * Build a render target for the given surface.
+ */
+RenderTarget::RenderTarget(OffscreenSurfacePtr surf)
+{
+	m_surface = surf;
+	reset();
+}
+
 
 /**
  * Sets an arbitrary drawing window.
@@ -178,108 +183,33 @@
 }
 
 /**
- * Blits a Surface on the screen or (if possible) on another Surface
- * Check g_gr->caps().offscreen_rendering to see if it is possible to blit
- * to a non screen surface.
- *
- * This blit function copies the pixels to the destination surface.
- * I the source surface contains a alpha channel this is used during
- * the blit.
- */
-void RenderTarget::blit(const Point dst, const PictureID picture)
-{
-	if (Surface * const src = g_gr->get_picture_surface(picture))
-		doblit
-			(Rect(dst, 0, 0),
-			 src, Rect(Point(0, 0), src->get_w(), src->get_h()));
-}
-
-/**
- * Blits a Surface on the screen or (if possible) on another Surface
- * Check g_gr->caps().offscreen_rendering to see if it is possible to blit
- * to a non screen surface.
- *
- * This blit function copies the pixels to the destination surface.
- * I the source surface contains a alpha channel this is used during
- * the blit.
- */
-void RenderTarget::blit(const Rect dst, const PictureID picture)
-{
-	if (Surface * const src = g_gr->get_picture_surface(picture))
-		doblit(dst, src, Rect(Point(0, 0), src->get_w(), src->get_h()));
-}
-
-/**
- * Blits a Surface on the screen or (if possible) on another Surface
- * Check g_gr->caps().offscreen_rendering to see if it is possible to blit
- * to a non screen surface.
- *
- * This blit function copies the pixels values without alpha channel to the
- * destination surface.
- */
-void RenderTarget::blit_solid(const Point dst, const PictureID picture)
-{
-	Surface * const src = g_gr->get_picture_surface(picture);
-	if (not src)
-		return;
-
-	upcast(SurfaceSDL, sdlsurf, src);
-	upcast(SurfaceOpenGL, oglsurf, src);
-
-	if (sdlsurf) {
-		bool alpha;
-		uint8_t alphaval;
-		alpha = sdlsurf->get_sdl_surface()->flags & SDL_SRCALPHA;
-		alphaval = sdlsurf->get_sdl_surface()->format->alpha;
-		SDL_SetAlpha(sdlsurf->get_sdl_surface(), 0, 0);
-		doblit
-			(Rect(dst, 0, 0),
-			 src, Rect(Point(0, 0), src->get_w(), src->get_h()), false);
-		SDL_SetAlpha(sdlsurf->get_sdl_surface(), alpha?SDL_SRCALPHA:0, alphaval);
-	} else if (oglsurf) {
-		doblit
-			(Rect(dst, 0, 0),
-			 src, Rect(Point(0, 0), src->get_w(), src->get_h()), false);
-	}
-}
-
-/**
- * Blits a Surface on the screen or (if possible) on another Surface
- * Check g_gr->caps().offscreen_rendering to see if it is possible to blit
- * to a non screen surface.
- *
- * This blit function copies the pixels (including alpha channel)
- * to the destination surface.
- * The destination pixels will be exactly like the source pixels.
- */
-void RenderTarget::blit_copy(Point dst, PictureID picture)
-{
-	Surface * const src = g_gr->get_picture_surface(picture);
-	upcast(SurfaceSDL, sdlsurf, src);
-	bool alpha;
-	uint8_t alphaval;
-	if (sdlsurf) {
-		alpha = sdlsurf->get_sdl_surface()->flags & SDL_SRCALPHA;
-		alphaval = sdlsurf->get_sdl_surface()->format->alpha;
-		SDL_SetAlpha(sdlsurf->get_sdl_surface(), 0, 0);
-	}
-	if (src)
-		doblit
-			(Rect(dst, 0, 0),
-			 src, Rect(Point(0, 0), src->get_w(), src->get_h()), false);
-	if (sdlsurf) {
-		SDL_SetAlpha(sdlsurf->get_sdl_surface(), alpha?SDL_SRCALPHA:0, alphaval);
-	}
-}
-
+ * Blits a Picture on the screen or (if possible) on another Surface
+ * Check g_gr->caps().offscreen_rendering to see if it is possible to blit
+ * to a non screen surface.
+ *
+ * This blit function copies the pixels to the destination surface.
+ * I the source surface contains a alpha channel this is used during
+ * the blit.
+ */
+void RenderTarget::blit(const Point dst, const PictureID picture, Composite cm)
+{
+	if (picture->valid())
+		doblit
+			(Rect(dst, 0, 0),
+			 picture, Rect(Point(0, 0), picture->get_w(), picture->get_h()), cm);
+}
+
+/**
+ * Like \ref blit, but use only a sub-rectangle of the source picture.
+ */
 void RenderTarget::blitrect
-	(Point const dst, PictureID const picture, Rect const srcrc)
+	(Point const dst, PictureID const picture, Rect const srcrc, Composite cm)
 {
 	assert(0 <= srcrc.x);
 	assert(0 <= srcrc.y);
 
-	if (Surface * const src = g_gr->get_picture_surface(picture))
-		doblit(Rect(dst, 0, 0), src, srcrc);
+	if (picture->valid())
+		doblit(Rect(dst, 0, 0), picture, srcrc, cm);
 }
 
 /**
@@ -288,24 +218,25 @@
  * The pixel from ofs inside picture is placed at the top-left corner of
  * the filled rectangle.
  */
-void RenderTarget::tile(Rect r, PictureID const picture, Point ofs)
+void RenderTarget::tile(Rect r, PictureID const picture, Point ofs, Composite cm)
 {
-	Surface * const src = g_gr->get_picture_surface(picture);
-
-	if (!src)
+	if (!picture->valid())
 		return;
 
+	int32_t srcw = picture->get_w();
+	int32_t srch = picture->get_h();
+
 	if (clip(r)) {
 		// Make sure the offset is within bounds
-		ofs.x = ofs.x % src->get_w();
+		ofs.x = ofs.x % srcw;
 
 		if (ofs.x < 0)
-			ofs.x += src->get_w();
+			ofs.x += srcw;
 
-		ofs.y = ofs.y % src->get_h();
+		ofs.y = ofs.y % srch;
 
 		if (ofs.y < 0)
-			ofs.y += src->get_h();
+			ofs.y += srch;
 
 		// Blit the picture into the rectangle
 		uint32_t ty = 0;
@@ -316,19 +247,19 @@
 			Rect srcrc;
 
 			srcrc.y = ofs.y;
-			srcrc.h = src->get_h() - ofs.y;
+			srcrc.h = srch - ofs.y;
 
 			if (ty + srcrc.h > r.h)
 				srcrc.h = r.h - ty;
 
 			while (tx < r.w) {
 				srcrc.x = tofsx;
-				srcrc.w = src->get_w() - tofsx;
+				srcrc.w = srcw - tofsx;
 
 				if (tx + srcrc.w > r.w)
 					srcrc.w = r.w - tx;
 
-				m_surface->blit(r + Point(tx, ty), src, srcrc);
+				m_surface->blit(r + Point(tx, ty), picture, srcrc, cm);
 
 				tx += srcrc.w;
 
@@ -372,7 +303,7 @@
 
 	// Get the frame and its data
 	uint32_t const framenumber = time / data->frametime % gfx->nr_frames();
-	Surface * const frame =
+	const PictureID & frame =
 		player ?
 		gfx->get_frame
 			(framenumber, player->player_number(), player->get_playercolor())
@@ -411,7 +342,7 @@
 
 	// Get the frame and its data
 	uint32_t const framenumber = time / data->frametime % gfx->nr_frames();
-	Surface * const frame =
+	const PictureID & frame =
 		player ?
 		gfx->get_frame
 			(framenumber, player->player_number(), player->get_playercolor())
@@ -486,14 +417,13 @@
  * Clip against window and source bitmap, then call the Bitmap blit routine.
  */
 void RenderTarget::doblit
-	(Rect dst, Surface * const src, Rect srcrc, bool enable_alpha)
+	(Point dst, PictureID src, Rect srcrc, Composite cm)
 {
 	assert(0 <= srcrc.x);
 	assert(0 <= srcrc.y);
 	dst += m_offset;
 
 	// Clipping
-
 	if (dst.x < 0) {
 		if (srcrc.w <= static_cast<uint32_t>(-dst.x))
 			return;
@@ -527,10 +457,5 @@
 
 	dst += m_rect;
 
-	// Draw it
-	upcast(SurfaceOpenGL, oglsurf, m_surface);
-	if (oglsurf and dst.w and dst.h)
-		oglsurf->blit(dst, src, srcrc, enable_alpha);
-	else
-		m_surface->blit(Point(dst.x, dst.y), src, srcrc, enable_alpha);
+	m_surface->blit(dst, src, srcrc, cm);
 }

=== modified file 'src/graphic/rendertarget.h'
--- src/graphic/rendertarget.h	2010-11-10 20:05:21 +0000
+++ src/graphic/rendertarget.h	2010-11-27 16:29:59 +0000
@@ -20,7 +20,9 @@
 #ifndef RENDERTARGET_H
 #define RENDERTARGET_H
 
+#include "compositemode.h"
 #include "picture_id.h"
+#include "surfaceptr.h"
 #include "rect.h"
 #include "rgbcolor.h"
 
@@ -29,7 +31,6 @@
 namespace Widelands {
 struct Player;
 };
-struct Surface;
 
 /**
  * This abstract class represents anything that can be rendered to.
@@ -47,7 +48,8 @@
  * false and doesn't change the window state at all.
 */
 struct RenderTarget {
-	RenderTarget(Surface *);
+	RenderTarget(SurfacePtr);
+	RenderTarget(OffscreenSurfacePtr);
 	RenderTarget(RenderTarget & rt):
 		m_surface(rt.m_surface),
 		m_rect(rt.m_rect),
@@ -70,12 +72,9 @@
 	void brighten_rect(Rect, int32_t factor);
 	void clear();
 
-	void blit(Point dst, PictureID picture);
-	void blit(Rect dst, PictureID picture);
-	void blit_solid(Point dst, PictureID picture);
-	void blit_copy(Point dst, PictureID picture);
-	void blitrect(Point dst, PictureID picture, Rect src);
-	void tile(Rect, PictureID picture, Point ofs);
+	void blit(Point dst, PictureID picture, Composite cm = CM_Normal);
+	void blitrect(Point dst, PictureID picture, Rect src, Composite cm = CM_Normal);
+	void tile(Rect, PictureID picture, Point ofs, Composite cm = CM_Normal);
 
 	void drawanim
 		(Point                     dst,
@@ -92,15 +91,15 @@
 
 	void reset();
 
-	Surface & get_surface() {return *m_surface;}
+	SurfacePtr get_surface() {return m_surface;}
 
 protected:
 	bool clip(Rect & r) const throw ();
 
-	void doblit(Rect dst, Surface * src, Rect srcrc, bool enable_alpha = true);
+	void doblit(Point dst, PictureID src, Rect srcrc, Composite cm = CM_Normal);
 
 	///The target surface
-	Surface * m_surface;
+	SurfacePtr m_surface;
 	///The current clip rectangle
 	Rect m_rect;
 	///Drawing offset

=== modified file 'src/graphic/surface.h'
--- src/graphic/surface.h	2010-11-01 22:37:46 +0000
+++ src/graphic/surface.h	2010-11-27 16:29:59 +0000
@@ -20,80 +20,28 @@
 #ifndef SURFACE_H
 #define SURFACE_H
 
+#include "compositemode.h"
 #include "rgbcolor.h"
 #include "rect.h"
+#include "surfaceptr.h"
 #include "wexception.h"
 
 /**
- * The type of a surface. This make it possible to check a bit before drawing.
+ * Interface to a basic surfaces that can be used as destination for drawing.
  */
-enum SurfaceType {
-	SURFACE_INVALID,
-	SURFACE_SOURCE,       ///< This sourface is used as source only
-	SURFACE_OFFSCREEN,    ///< Use surface as source and destinantion
-	SURFACE_SCREEN        ///< This draws to screen directly
-};
-
-/// A virtual base for rendering. Objects of Surface are used as Source or
-/// destination for drawing. Surfaces are created with the
-/// Graphic::create_surface() functions.
 struct Surface {
+	Surface() {}
 	virtual ~Surface() {}
 
 	//@{
 	/// Get width and height
-	virtual uint32_t get_w() const {return m_w;}
-	virtual uint32_t get_h() const {return m_h;}
+	virtual uint32_t get_w() = 0;
+	virtual uint32_t get_h() = 0;
 	//@}
 
 	/// Update the screen. This is only useful for the screen surface.
 	virtual void update() = 0;
 
-	//@{
-	/// For the slowest: Indirect pixel access.
-	/// A safe function to get and set single pixels. lock() must be called
-	/// before pixel access can be used. get_pixel() and set_pixel() are easier
-	/// and safer to use but also much slower than direct pixel access.
-	virtual uint32_t get_pixel(uint32_t x, uint32_t y) {
-		//  FIXME make abstract or move body out of declaration
-		throw wexception("get_pixel() not implemented");
-	}
-	virtual void set_pixel(uint32_t x, uint32_t y, Uint32 clr) {
-		//  FIXME make abstract or move body out of declaration
-		throw wexception("set_pixel() not implemented");
-	}
-	//@}
-
-	//@{
-	/**
-	 * Locking and unlocking the surface for pixel access. This may be slow. So
-	 * use it with care.
-	 */
-
-	virtual void lock() {};
-	virtual void unlock() {};
-	//@}
-
-	/// This returns the pixel format for direct pixel access.
-	virtual SDL_PixelFormat const & format() const {
-		throw wexception("format() not implemented");
-	}
-
-	//@{
-	/**
-	 * Direct pixel access. lock() must be called before pixles may be access.
-	 * This is faster than indirect pixel access but also more dangerous.
-	 * get_pixels() gives a pointer to the pixel data. get_pitch() returns an
-	 * integer where the next row begins.
-	 */
-	virtual uint16_t get_pitch() const {
-		throw wexception("get_pitch() not implemented");
-	}
-	virtual uint8_t * get_pixels() const {
-		throw wexception("get_pixels() not implemented");
-	}
-	//@}
-
 	/// Clears the complete surface to black.
 	virtual void clear() {
 		fill_rect
@@ -123,36 +71,16 @@
 	virtual void brighten_rect(Rect, int32_t factor) = 0;
 
 	/// This draws a part aother surface to this surface
-	virtual void blit(Point, Surface *, Rect srcrc, bool enable_alpha = false) = 0;
+	virtual void blit(Point, PictureID, Rect srcrc, Composite cm = CM_Normal) = 0;
 	/// This draws another surface completely in the left
 	/// upper corner of this surface
-	virtual void fast_blit(Surface * surface) {
-		blit
-			(Point(0, 0),
-			 surface,
-			 Rect(Point(0, 0), surface->get_w(), surface->get_h()));
-	}
-
-	/// set the type of the surface
-	virtual void set_type(SurfaceType const type) {m_surf_type = type;}
-
-protected:
-	int32_t m_offsx;
-	int32_t m_offsy;
-	uint32_t m_w, m_h;
-
-	Surface():
-		m_offsx(0), m_offsy(0),
-		m_w(0), m_h(0),
-		m_surf_type(SURFACE_INVALID)
-	{}
-	Surface(int w, int h, SurfaceType t):
-		m_offsx(0), m_offsy(0),
-		m_w(w), m_h(h),
-		m_surf_type(t)
-	{}
-	SurfaceType m_surf_type;
+	virtual void fast_blit(PictureID surface) = 0;
+
+	virtual IPixelAccess & pixelaccess() = 0;
+
 private:
+	// surfaces cannot be copied
+	Surface(const Surface &);
 	Surface & operator= (Surface const &);
 };
 

=== added file 'src/graphic/surfaceptr.h'
--- src/graphic/surfaceptr.h	1970-01-01 00:00:00 +0000
+++ src/graphic/surfaceptr.h	2010-11-27 16:29:59 +0000
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2010 by the Widelands Development Team
+ *
+ * This program 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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef SURFACEPTR_H
+#define SURFACEPTR_H
+
+#include <boost/shared_ptr.hpp>
+
+struct IOffscreenSurface;
+struct Surface;
+
+typedef boost::shared_ptr<IOffscreenSurface> OffscreenSurfacePtr;
+typedef boost::shared_ptr<Surface> SurfacePtr;
+
+#endif // SURFACEPTR_H

=== modified file 'src/graphic/texture.cc'
--- src/graphic/texture.cc	2010-11-21 11:44:22 +0000
+++ src/graphic/texture.cc	2010-11-27 16:29:59 +0000
@@ -102,14 +102,14 @@
 
 #ifdef USE_OPENGL
 		if (g_opengl) {
-			SurfaceOpenGL * tsurface =
-				&dynamic_cast<SurfaceOpenGL &>
-				(g_gr->load_image(fname));
-			// SDL_ConvertSurface(surf, &fmt, 0);
-			m_glFrames.push_back(tsurface);
-			tsurface->lock();
-			m_mmap_color = tsurface->get_pixel(0, 0);
-			tsurface->unlock();
+			// Note: we except the constructor to free the SDL surface
+			boost::shared_ptr<GLPictureTexture> surface(new GLPictureTexture(surf));
+			m_glFrames.push_back(surface);
+
+			surface->lock(IPixelAccess::Lock_Normal);
+			m_mmap_color = surface->get_pixel(0, 0);
+			surface->unlock(IPixelAccess::Unlock_NoChange);
+
 			++m_nrframes;
 			continue;
 		}
@@ -181,11 +181,6 @@
 	delete m_colormap;
 	free(m_pixels);
 	free(m_texture_picture);
-
-#ifdef USE_OPENGL
-	container_iterate(std::vector<SurfaceOpenGL *>, m_glFrames, it)
-		delete *it.current;
-#endif
 }
 
 /**

=== modified file 'src/graphic/texture.h'
--- src/graphic/texture.h	2010-11-01 22:37:46 +0000
+++ src/graphic/texture.h	2010-11-27 16:29:59 +0000
@@ -23,7 +23,7 @@
 #include "colormap.h"
 #include "picture_id.h"
 
-#include "graphic/render/surface_opengl.h"
+#include "graphic/render/gl_picture_texture.h"
 
 #include <boost/shared_ptr.hpp>
 #include <stdint.h>
@@ -65,7 +65,7 @@
 	bool was_animated() const throw () {return m_was_animated;}
 #ifdef USE_OPENGL
 	uint32_t getTexture() const
-		{return m_glFrames.at(m_frame_num)->get_texture();}
+		{return m_glFrames.at(m_frame_num)->get_gl_texture();}
 #endif
 
 private:
@@ -80,7 +80,7 @@
 	bool       is_32bit;
 	bool       m_was_animated;
 #ifdef USE_OPENGL
-	std::vector<SurfaceOpenGL *> m_glFrames;
+	std::vector<boost::shared_ptr<GLPictureTexture> > m_glFrames;
 #endif
 };
 

=== modified file 'src/map_io/widelands_map_extradata_data_packet.cc'
--- src/map_io/widelands_map_extradata_data_packet.cc	2010-05-12 10:16:44 +0000
+++ src/map_io/widelands_map_extradata_data_packet.cc	2010-11-27 16:29:59 +0000
@@ -75,20 +75,19 @@
 					if (!surf)
 						continue; //  Illegal pic. Skip it.
 
-					Surface & picsurf = g_gr->create_surface(*surf);
+					PictureID const picture = g_gr->convert_sdl_surface_to_picture(surf);
 
 					std::string picname = FileSystem::FS_Filename(pname->c_str());
 					picname = "map:" + picname;
 
-					PictureID const data =
-						g_gr->get_picture(PicMod_Game, picsurf, picname.c_str());
+					g_gr->add_picture_to_cache(PicMod_Game, picname, picture);
 
 					//  OK, the pic is now known to the game. But when the game is
 					//  saved, this data has to be regenerated.
 					Map::Extradata_Info info;
 					info.type     = Map::Extradata_Info::PIC;
 					info.filename = *pname;
-					info.data     = data;
+					info.data     = picture;
 					map.m_extradatainfos.push_back(info);
 				}
 			}

=== modified file 'src/ui_basic/button.cc'
--- src/ui_basic/button.cc	2010-11-01 23:32:46 +0000
+++ src/ui_basic/button.cc	2010-11-27 16:29:59 +0000
@@ -22,6 +22,7 @@
 #include "mouse_constants.h"
 
 #include "graphic/font_handler.h"
+#include "graphic/offscreensurface.h"
 #include "graphic/rendertarget.h"
 #include "wlapplication.h"
 #include "log.h"
@@ -48,7 +49,6 @@
 	m_repeating     (false),
 	m_flat          (flat),
 	m_needredraw    (true),
-	m_cache_pic     (g_gr->get_no_picture()),
 	m_title         (title_text),
 	m_pic_background(background_picture_id),
 	m_pic_custom    (g_gr->get_no_picture()),
@@ -81,7 +81,6 @@
 	m_repeating     (false),
 	m_flat          (flat),
 	m_needredraw    (true),
-	m_cache_pic     (g_gr->get_no_picture()),
 	m_pic_background(background_picture_id),
 	m_pic_custom    (foreground_picture_id),
 	m_pic_custom_disabled(g_gr->create_grayed_out_pic(foreground_picture_id)),
@@ -94,9 +93,8 @@
 }
 
 
-Button::~Button() {
-	if (m_pic_custom_disabled != g_gr->get_no_picture())
-		g_gr->free_picture_surface(m_pic_custom_disabled);
+Button::~Button()
+{
 }
 
 
@@ -113,8 +111,6 @@
 	m_needredraw = true;
 
 	m_pic_custom = picid;
-	if (m_pic_custom_disabled != g_gr->get_no_picture())
-		g_gr->free_picture_surface(m_pic_custom_disabled);
 	m_pic_custom_disabled = g_gr->create_grayed_out_pic(picid);
 
 	update();
@@ -168,7 +164,7 @@
 */
 void Button::draw(RenderTarget & odst)
 {
-	RenderTarget * dst = &odst;
+	RenderTarget dst = odst;
 
 	if (g_gr->caps().offscreen_rendering) {
 		if (!m_needredraw)
@@ -176,18 +172,15 @@
 			odst.blit(Point(0, 0), m_cache_pic);
 			return;
 		} else {
-			if (m_cache_pic == g_gr->get_no_picture())
-				m_cache_pic =
-					g_gr->create_picture_surface(get_w(), get_h(), m_flat);
-			else if
-				(m_cache_pic->rendertarget->get_w() != get_w() or
-				 m_cache_pic->rendertarget->get_h() != get_h())
+			if
+				(!m_cache_pic ||
+				 (static_cast<IPicture *>(m_cache_pic.get())->get_w() != static_cast<uint32_t>(get_w()) or
+				  static_cast<IPicture *>(m_cache_pic.get())->get_h() != static_cast<uint32_t>(get_h())))
 			{
-				g_gr->free_picture_surface(m_cache_pic);
 				m_cache_pic =
-					g_gr->create_picture_surface(get_w(), get_h(), m_flat);
+					g_gr->create_offscreen_surface(get_w(), get_h(), m_flat);
 			}
-			dst = (g_gr->get_surface_renderer(m_cache_pic));
+			dst = RenderTarget(m_cache_pic);
 		}
 	}
 
@@ -195,18 +188,18 @@
 	// Draw the background
 	if (not m_flat) {
 		assert(m_pic_background != g_gr->get_no_picture());
-		dst->fill_rect
+		dst.fill_rect
 			(Rect(Point(0, 0), get_w(), get_h()), RGBAColor(0, 0, 0, 255));
-		dst->tile
+		dst.tile
 			(Rect(Point(0, 0), get_w(), get_h()),
 			 m_pic_background,
 			 Point(get_x(), get_y()));
 	} else if (g_gr->caps().offscreen_rendering)
-		dst->fill_rect
+		dst.fill_rect
 			(Rect(Point(0, 0), get_w(), get_h()), RGBAColor(0, 0, 0, 0));
 
 	if (m_enabled and m_highlighted and not m_flat)
-		dst->brighten_rect
+		dst.brighten_rect
 			(Rect(Point(0, 0), get_w(), get_h()), MOUSE_OVER_BRIGHT_FACTOR);
 
 	//  if we got a picture, draw it centered
@@ -217,13 +210,14 @@
 		//  ">> 1" is almost like "/ 2", but simpler for signed types (difference
 		//  is that -1 >> 1 is -1 but -1 / 2 is 0).
 		if (g_gr->caps().offscreen_rendering and m_flat)
-			dst->blit_copy
+			dst.blit
 				(Point
 				 	((get_w() - static_cast<int32_t>(cpw)) >> 1,
 				 	 (get_h() - static_cast<int32_t>(cph)) >> 1),
-				 m_enabled ? m_pic_custom : m_pic_custom_disabled);
+				 m_enabled ? m_pic_custom : m_pic_custom_disabled,
+				 CM_Copy);
 		else
-			dst->blit
+			dst.blit
 				(Point
 				 	((get_w() - static_cast<int32_t>(cpw)) >> 1,
 				 	 (get_h() - static_cast<int32_t>(cph)) >> 1),
@@ -231,7 +225,7 @@
 
 	} else if (m_title.length()) //  otherwise draw title string centered
 		UI::g_fh->draw_string
-			(*dst,
+			(dst,
 			 m_fontname,
 			 m_fontsize,
 			 m_enabled ? UI_FONT_CLR_FG : UI_FONT_CLR_DISABLED, UI_FONT_CLR_BG,
@@ -240,7 +234,7 @@
 			 Align_Center,
 			 std::numeric_limits<uint32_t>::max(),
 			 Widget_Cache_None,
-			 g_gr->get_no_picture(),
+			 0,
 			 m_draw_caret ? m_title.length() :
 			 std::numeric_limits<uint32_t>::max());
 
@@ -260,32 +254,32 @@
 		//  button is a normal one, not flat
 		if (not draw_pressed) {
 			//  top edge
-			dst->brighten_rect
+			dst.brighten_rect
 				(Rect(Point(0, 0), get_w(), 2), BUTTON_EDGE_BRIGHT_FACTOR);
 			//  left edge
-			dst->brighten_rect
+			dst.brighten_rect
 				(Rect(Point(0, 2), 2, get_h() - 2), BUTTON_EDGE_BRIGHT_FACTOR);
 			//  bottom edge
-			dst->fill_rect(Rect(Point(2, get_h() - 2), get_w() - 2, 1), black);
-			dst->fill_rect(Rect(Point(1, get_h() - 1), get_w() - 1, 1), black);
+			dst.fill_rect(Rect(Point(2, get_h() - 2), get_w() - 2, 1), black);
+			dst.fill_rect(Rect(Point(1, get_h() - 1), get_w() - 1, 1), black);
 			//  right edge
-			dst->fill_rect(Rect(Point(get_w() - 2, 2), 1, get_h() - 2), black);
-			dst->fill_rect(Rect(Point(get_w() - 1, 1), 1, get_h() - 1), black);
+			dst.fill_rect(Rect(Point(get_w() - 2, 2), 1, get_h() - 2), black);
+			dst.fill_rect(Rect(Point(get_w() - 1, 1), 1, get_h() - 1), black);
 		} else {
 			//  bottom edge
-			dst->brighten_rect
+			dst.brighten_rect
 				(Rect(Point(0, get_h() - 2), get_w(), 2),
 				 BUTTON_EDGE_BRIGHT_FACTOR);
 			//  right edge
-			dst->brighten_rect
+			dst.brighten_rect
 				(Rect(Point(get_w() - 2, 0), 2, get_h() - 2),
 				 BUTTON_EDGE_BRIGHT_FACTOR);
 			//  top edge
-			dst->fill_rect(Rect(Point(0, 0), get_w() - 1, 1), black);
-			dst->fill_rect(Rect(Point(0, 1), get_w() - 2, 1), black);
+			dst.fill_rect(Rect(Point(0, 0), get_w() - 1, 1), black);
+			dst.fill_rect(Rect(Point(0, 1), get_w() - 2, 1), black);
 			//  left edge
-			dst->fill_rect(Rect(Point(0, 0), 1, get_h() - 1), black);
-			dst->fill_rect(Rect(Point(1, 0), 1, get_h() - 2), black);
+			dst.fill_rect(Rect(Point(0, 0), 1, get_h() - 1), black);
+			dst.fill_rect(Rect(Point(1, 0), 1, get_h() - 2), black);
 		}
 	} else {
 		//  Button is flat, do not draw borders, instead, if it is pressed, draw
@@ -293,10 +287,10 @@
 		if (m_enabled and m_highlighted)
 		{
 			RGBAColor shade(100, 100, 100, 80);
-			dst->fill_rect(Rect(Point(0, 0), get_w(), 2), shade);
-			dst->fill_rect(Rect(Point(0, 2), 2, get_h() - 2), shade);
-			dst->fill_rect(Rect(Point(0, get_h() - 2), get_w(), get_h()), shade);
-			dst->fill_rect(Rect(Point(get_w() - 2, 0), get_w(), get_h()), shade);
+			dst.fill_rect(Rect(Point(0, 0), get_w(), 2), shade);
+			dst.fill_rect(Rect(Point(0, 2), 2, get_h() - 2), shade);
+			dst.fill_rect(Rect(Point(0, get_h() - 2), get_w(), get_h()), shade);
+			dst.fill_rect(Rect(Point(get_w() - 2, 0), get_w(), get_h()), shade);
 			//dst.draw_rect(Rect(Point(0, 0), get_w(), get_h()), m_clr_down);
 		}
 	}

=== modified file 'src/ui_basic/button.h'
--- src/ui_basic/button.h	2010-11-01 23:54:06 +0000
+++ src/ui_basic/button.h	2010-11-27 16:29:59 +0000
@@ -99,7 +99,7 @@
 	bool        m_repeating;
 	bool        m_flat;
 	bool        m_needredraw;
-	PictureID   m_cache_pic;
+	OffscreenSurfacePtr m_cache_pic;
 
 	int32_t     m_time_nextact;
 

=== modified file 'src/ui_basic/checkbox.cc'
--- src/ui_basic/checkbox.cc	2010-06-16 18:43:40 +0000
+++ src/ui_basic/checkbox.cc	2010-11-27 16:29:59 +0000
@@ -54,11 +54,8 @@
 }
 
 
-Statebox::~Statebox() {
-	if (m_flags & Owns_Custom_Picture) {
-		assert(m_flags & Has_Custom_Picture);
-		g_gr->free_picture_surface(m_pic_graphics);
-	}
+Statebox::~Statebox()
+{
 }
 
 

=== modified file 'src/ui_basic/editbox.cc'
--- src/ui_basic/editbox.cc	2010-11-01 23:54:06 +0000
+++ src/ui_basic/editbox.cc	2010-11-27 16:29:59 +0000
@@ -401,7 +401,7 @@
 		 align(),
 		 std::numeric_limits<uint32_t>::max(),
 		 Widget_Cache_None,
-		 g_gr->get_no_picture(),
+		 0,
 		 has_focus() ? static_cast<int32_t>(m->caret) :
 		 std::numeric_limits<uint32_t>::max());
 }

=== modified file 'src/ui_basic/icon.cc'
--- src/ui_basic/icon.cc	2010-11-02 20:11:05 +0000
+++ src/ui_basic/icon.cc	2010-11-27 16:29:59 +0000
@@ -19,7 +19,7 @@
 
 #include "icon.h"
 #include "graphic/rendertarget.h"
-#include "graphic/surface.h"
+#include "graphic/picture.h"
 
 namespace UI {
 
@@ -44,8 +44,8 @@
 
 void Icon::draw(RenderTarget & dst) {
 	assert(m_pic != g_gr->get_no_picture());
-	int32_t w = (m_w - m_pic->surface->get_w()) / 2;
-	int32_t h = (m_h - m_pic->surface->get_h()) / 2;
+	int32_t w = (m_w - m_pic->get_w()) / 2;
+	int32_t h = (m_h - m_pic->get_h()) / 2;
 	dst.blit(Point(w, h), m_pic);
 }
 

=== modified file 'src/ui_basic/listselect.cc'
--- src/ui_basic/listselect.cc	2010-06-16 18:43:40 +0000
+++ src/ui_basic/listselect.cc	2010-11-27 16:29:59 +0000
@@ -21,6 +21,7 @@
 
 #include "constants.h"
 #include "graphic/font_handler.h"
+#include "graphic/offscreensurface.h"
 #include "graphic/rendertarget.h"
 #include "wlapplication.h"
 #include "log.h"
@@ -55,8 +56,7 @@
 	m_show_check(show_check),
 	m_fontname(UI_FONT_NAME),
 	m_fontsize(UI_FONT_SIZE_SMALL),
-	m_needredraw(true),
-	m_cache_pic(g_gr->get_no_picture())
+	m_needredraw(true)
 {
 	set_think(false);
 
@@ -347,7 +347,7 @@
 */
 void BaseListselect::draw(RenderTarget & odst)
 {
-	RenderTarget * dst = &odst;
+	RenderTarget dst = odst;
 
 	// Render Caching is disable because it does not work good with the
 	// transparent background.
@@ -357,11 +357,11 @@
 			odst.blit(Point(0, 0), m_cache_pic);
 			return;
 		} else {
-			if (m_cache_pic == g_gr->get_no_picture())
+			if (!m_cache_pic)
 				m_cache_pic =
-					g_gr->create_picture_surface(get_w(), get_h());
+					g_gr->create_offscreen_surface(get_w(), get_h());
 			// TODO: Handle resize here
-			dst = (g_gr->get_surface_renderer(m_cache_pic));
+			dst = RenderTarget(m_cache_pic);
 		}
 	}
 
@@ -371,7 +371,7 @@
 	int32_t y = 1 + idx * lineheight - m_scrollpos;
 
 	//if (not g_gr->caps().offscreen_rendering)
-		dst->brighten_rect(Rect(Point(0, 0), get_w(), get_h()), ms_darken_value);
+		dst.brighten_rect(Rect(Point(0, 0), get_w(), get_h()), ms_darken_value);
 	//else
 	//dst->fill_rect
 	//(Rect(Point(0, 0), get_w(), get_h()), RGBAColor(20, 20, 20, 80));
@@ -403,7 +403,7 @@
 				//if (g_gr->caps().offscreen_rendering and false)
 				//dst->fill_rect(r, RGBAColor(100, 100, 100, 80));
 				//else
-					dst->brighten_rect
+					dst.brighten_rect
 						(r, - ms_darken_value * 2);
 						//(Rect(Point(1, y), get_eff_w() - 2,
 						// m_lineheight), -ms_darken_value*2);
@@ -423,7 +423,7 @@
 
 		// Horizontal center the string
 		UI::g_fh->draw_string
-			(*dst,
+			(dst,
 			 m_fontname, m_fontsize,
 			 col,
 			 RGBColor(107, 87, 55),
@@ -442,11 +442,9 @@
 			uint32_t w, h;
 			g_gr->get_picture_size(er.picid, w, h);
 			if (g_gr->caps().offscreen_rendering and false)
-				dst->blit_solid
-					(Point(1, y + (get_lineheight() - h) / 2), er.picid);
+				dst.blit(Point(1, y + (get_lineheight() - h) / 2), er.picid, CM_Solid);
 			else
-				dst->blit
-					(Point(1, y + (get_lineheight() - h) / 2), er.picid);
+				dst.blit(Point(1, y + (get_lineheight() - h) / 2), er.picid);
 		}
 
 		y += lineheight;

=== modified file 'src/ui_basic/listselect.h'
--- src/ui_basic/listselect.h	2010-05-16 14:57:40 +0000
+++ src/ui_basic/listselect.h	2010-11-27 16:29:59 +0000
@@ -149,7 +149,7 @@
 	uint32_t    m_fontsize;
 
 	bool        m_needredraw;
-	PictureID   m_cache_pic;
+	OffscreenSurfacePtr m_cache_pic;
 };
 
 template<typename Entry>

=== modified file 'src/ui_basic/multilineeditbox.cc'
--- src/ui_basic/multilineeditbox.cc	2010-05-12 11:20:58 +0000
+++ src/ui_basic/multilineeditbox.cc	2010-11-27 16:29:59 +0000
@@ -297,7 +297,7 @@
 			 m_align,
 			 get_eff_w(),
 			 m_cache_mode,
-			 m_cache_id,
+			 &m_cache_id,
 			 //  explicit cast is necessary to avoid a compiler warning
 			 has_focus() ? static_cast<int32_t>(m_cur_pos) :
 			 std::numeric_limits<uint32_t>::max());

=== modified file 'src/ui_basic/multilinetextarea.cc'
--- src/ui_basic/multilinetextarea.cc	2010-09-25 08:11:16 +0000
+++ src/ui_basic/multilinetextarea.cc	2010-11-27 16:29:59 +0000
@@ -62,9 +62,8 @@
 /**
  * Free allocated resources
 */
-Multiline_Textarea::~Multiline_Textarea() {
-	if (m_cache_id != g_gr->get_no_picture())
-		UI::g_fh->delete_widget_cache(m_cache_id);
+Multiline_Textarea::~Multiline_Textarea()
+{
 }
 
 
@@ -132,7 +131,7 @@
 				 m_text,
 				 m_align,
 				 get_eff_w(),
-				 m_cache_mode, m_cache_id);
+				 m_cache_mode, &m_cache_id);
 		else
 			UI::g_fh->draw_richtext
 				(dst,
@@ -140,7 +139,7 @@
 				 Point(get_halign(), 0 - m_textpos),
 				 m_text,
 				 get_eff_w(),
-				 m_cache_mode, m_cache_id);
+				 m_cache_mode, &m_cache_id);
 		draw_scrollbar();
 		m_cache_mode = Widget_Cache_Use;
 	}

=== modified file 'src/ui_basic/panel.cc'
--- src/ui_basic/panel.cc	2010-11-02 20:11:05 +0000
+++ src/ui_basic/panel.cc	2010-11-27 16:29:59 +0000
@@ -51,7 +51,7 @@
 	:
 	_parent(nparent), _fchild(0), _lchild(0), _mousein(0), _focus(0),
 	_flags(pf_handle_mouse|pf_think|pf_visible),
-	_cache(g_gr->get_no_picture()), _needdraw(false),
+	_needdraw(false),
 	_x(nx), _y(ny), _w(nw), _h(nh),
 	_lborder(0), _rborder(0), _tborder(0), _bborder(0),
 	_border_snap_distance(0), _panel_snap_distance(0),
@@ -80,9 +80,6 @@
 {
 	update();
 
-	if (_cache != g_gr->get_no_picture())
-		g_gr->free_picture_surface(_cache);
-
 	// Release pointers to this object
 	if (_g_mousegrab == this)
 		_g_mousegrab = 0;
@@ -254,9 +251,9 @@
 	_w = nw;
 	_h = nh;
 
-	if (_cache != g_gr->get_no_picture()) {
-		g_gr->free_picture_surface(_cache);
-		_cache = g_gr->create_picture_surface(_w, _h);
+	if (_cache) {
+		// The old surface is freed automatically
+		_cache = g_gr->create_offscreen_surface(_w, _h);
 	}
 
 	if (_parent)
@@ -775,7 +772,7 @@
 	if (!is_visible())
 		return;
 
-	if (_cache == g_gr->get_no_picture())
+	if (!_cache)
 	{
 		Rect outerrc;
 		Point outerofs;
@@ -1100,7 +1097,7 @@
 		 Align_Left,
 		 TIP_WIDTH_MAX,
 		 Widget_Cache_None,
-		 g_gr->get_no_picture(),
+		 0,
 		 std::numeric_limits<uint32_t>::max(),
 		 false);
 }

=== modified file 'src/ui_basic/panel.h'
--- src/ui_basic/panel.h	2010-11-02 20:11:05 +0000
+++ src/ui_basic/panel.h	2010-11-27 16:29:59 +0000
@@ -25,6 +25,7 @@
 
 #include "point.h"
 #include "graphic/picture_id.h"
+#include "graphic/surfaceptr.h"
 #include "graphic/graphic.h"
 
 #include <SDL_keyboard.h>
@@ -258,7 +259,7 @@
 	Panel * _focus; //  keyboard focus
 
 	uint32_t _flags;
-	PictureID _cache;
+	OffscreenSurfacePtr _cache;
 	bool _needdraw;
 
 	/**

=== modified file 'src/ui_basic/progresswindow.cc'
--- src/ui_basic/progresswindow.cc	2010-11-01 23:54:06 +0000
+++ src/ui_basic/progresswindow.cc	2010-11-27 16:29:59 +0000
@@ -50,8 +50,6 @@
 }
 
 ProgressWindow::~ProgressWindow() {
-	if (m_background_pic != g_gr->get_no_picture())
-		g_gr->free_picture_surface(m_background_pic);
 	const VisualizationArray & visualizations = m_visualizations;
 	container_iterate_const(VisualizationArray, visualizations, i)
 		(*i.current)->stop(); //  inform visualizations
@@ -68,27 +66,17 @@
 		(m_background_pic == g_gr->get_no_picture()
 		 or xres != m_xres or yres != m_yres)
 	{
-		if (m_background_pic != g_gr->get_no_picture())
-			g_gr->free_picture_surface(m_background_pic);
-
-		// Load background graphics
+		// (Re-)Load background graphics
+		// Note that the old pic is freed automatically
 		PictureID const background_original =
 			g_gr->get_picture(PicMod_Menu, m_background.c_str());
 
-		if (g_gr->caps().resize_surfaces and not g_gr->caps().blit_resized) {
-			PictureID const background_resized  =
-				g_gr->get_resized_picture
-					(background_original, xres, yres,
-					 Graphic::ResizeMode_Loose);
+		PictureID const background_resized  =
+			g_gr->get_resized_picture
+				(background_original, xres, yres,
+				 Graphic::ResizeMode_Loose);
 
-			if (background_resized != g_gr->get_no_picture()) {
-				m_background_pic = background_resized;
-				if (background_resized != background_original)
-					g_gr->free_picture_surface(background_original);
-			} else
-				m_background_pic = background_original;
-		} else
-			m_background_pic = background_original;
+		m_background_pic = background_resized;
 
 		const uint32_t h = g_fh->get_fontheight (UI_FONT_SMALL);
 		m_label_rectangle.x = xres / 4;
@@ -101,12 +89,7 @@
 		m_yres = yres;
 	}
 
-	if (g_gr->caps().resize_surfaces and not g_gr->caps().blit_resized)
-		rt.blit
-			(Point(0, 0), m_background_pic);
-	else
-		rt.blit
-			(Rect(Point(0, 0), rt.get_w(), rt.get_h()), m_background_pic);
+	rt.blit(Point(0, 0), m_background_pic);
 
 	Rect border_rect = m_label_rectangle;
 	border_rect.x -= PROGRESS_STATUS_BORDER_X;
@@ -144,7 +127,6 @@
 	} else
 		m_background = "pics/progress.png";
 	if (m_background_pic != g_gr->get_no_picture()) {
-		g_gr->free_picture_surface(m_background_pic);
 		m_background_pic = g_gr->get_no_picture();
 	}
 	draw_background(rt, g_gr->get_xres(), g_gr->get_yres());

=== modified file 'src/ui_basic/slider.cc'
--- src/ui_basic/slider.cc	2010-09-27 15:56:07 +0000
+++ src/ui_basic/slider.cc	2010-11-27 16:29:59 +0000
@@ -20,8 +20,8 @@
 #include "slider.h"
 
 #include "mouse_constants.h"
+#include "graphic/offscreensurface.h"
 #include "graphic/rendertarget.h"
-#include "graphic/surface.h"
 
 #include <cmath>
 
@@ -73,8 +73,7 @@
 		 m_value >= m_max_value ? get_bar_size() :
 		 (m_value - m_min_value) * get_bar_size() / (m_max_value - m_min_value)),
 	m_cursor_size (cursor_size),
-	m_needredraw     (true),
-	m_cache_pic      (g_gr->get_no_picture())
+	m_needredraw     (true)
 {
 	//  cursor initial position
 
@@ -142,7 +141,7 @@
 
 	// Make the slider button opaque
 	if (g_gr->caps().offscreen_rendering)
-		m_cache_pic->surface->fill_rect
+		m_cache_pic->fill_rect
 			(Rect(Point(x, y), w, h), RGBAColor(0, 0, 0, 255));
 	dst.tile //  background
 		(Rect(Point(x, y), w, h), m_pic_background, Point(get_x(), get_y()));
@@ -356,7 +355,7 @@
  * \param dst The graphic destination.
  */
 void HorizontalSlider::draw(RenderTarget & odst) {
-	RenderTarget * dst = &odst;
+	RenderTarget dst = odst;
 	if (g_gr->caps().offscreen_rendering) {
 		if (!m_needredraw)
 		{
@@ -364,37 +363,37 @@
 			return;
 		}
 
-		if (m_cache_pic == g_gr->get_no_picture())
+		if (m_cache_pic)
 		{
-			m_cache_pic = g_gr->create_picture_surface
+			m_cache_pic = g_gr->create_offscreen_surface
 				(get_w(), get_h(), true);
 		}
 
-		dst = g_gr->get_surface_renderer(m_cache_pic);
-		dst->fill_rect
+		dst = RenderTarget(m_cache_pic);
+		dst.fill_rect
 			(Rect(Point(0, 0), get_w(), get_h()), RGBAColor(0, 0, 0, 0));
 	}
 
 	RGBAColor black(0, 0, 0, 255);
 
-	dst->brighten_rect //  bottom edge
+	dst.brighten_rect //  bottom edge
 		(Rect(Point(get_x_gap(), get_h() / 2), get_bar_size(), 2),
 		 BUTTON_EDGE_BRIGHT_FACTOR);
-	dst->brighten_rect //  right edge
+	dst.brighten_rect //  right edge
 		(Rect(Point(get_x_gap() + get_bar_size() - 2, get_y_gap()), 2, 2),
 		 BUTTON_EDGE_BRIGHT_FACTOR);
 
 	//  top edge
-	dst->fill_rect
+	dst.fill_rect
 		(Rect(Point(get_x_gap(), get_y_gap()),     get_bar_size() - 1, 1), black);
-	dst->fill_rect
+	dst.fill_rect
 		(Rect(Point(get_x_gap(), get_y_gap() + 1), get_bar_size() - 2, 1), black);
 
 	//  left edge
-	dst->fill_rect(Rect(Point(get_x_gap(),     get_y_gap()), 1, 4), black);
-	dst->fill_rect(Rect(Point(get_x_gap() + 1, get_y_gap()), 1, 3), black);
+	dst.fill_rect(Rect(Point(get_x_gap(),     get_y_gap()), 1, 4), black);
+	dst.fill_rect(Rect(Point(get_x_gap() + 1, get_y_gap()), 1, 3), black);
 
-	draw_cursor(*dst, m_cursor_pos, 0, m_cursor_size, get_h());
+	draw_cursor(dst, m_cursor_pos, 0, m_cursor_size, get_h());
 
 	if (g_gr->caps().offscreen_rendering)
 		odst.blit(Point(0, 0), m_cache_pic);
@@ -457,7 +456,7 @@
  * \param dst The graphic destination.
  */
 void VerticalSlider::draw(RenderTarget & odst) {
-	RenderTarget * dst = &odst;
+	RenderTarget dst = odst;
 	if (g_gr->caps().offscreen_rendering)
 	{
 		if (!m_needredraw)
@@ -465,34 +464,34 @@
 			odst.blit(Point(0, 0), m_cache_pic);
 			return;
 		}
-	if (m_cache_pic == g_gr->get_no_picture())
-		m_cache_pic = g_gr->create_picture_surface
-			(get_w(), get_h(), true);
-	dst = g_gr->get_surface_renderer(m_cache_pic);
+		if (m_cache_pic)
+			m_cache_pic = g_gr->create_offscreen_surface
+				(get_w(), get_h(), true);
+		dst = RenderTarget(m_cache_pic);
 
-	dst->fill_rect(Rect(Point(0, 0), get_w(), get_h()), RGBAColor(0, 0, 0, 0));
+		dst.fill_rect(Rect(Point(0, 0), get_w(), get_h()), RGBAColor(0, 0, 0, 0));
 	}
 
 	RGBAColor black(0, 0, 0, 255);
 
-	dst->brighten_rect //  right edge
+	dst.brighten_rect //  right edge
 		(Rect(Point(get_w() / 2, get_y_gap()), 2, get_bar_size()),
 		 BUTTON_EDGE_BRIGHT_FACTOR);
-	dst->brighten_rect //  bottom edge
+	dst.brighten_rect //  bottom edge
 		(Rect(Point(get_x_gap(), get_y_gap() + get_bar_size() - 2), 2, 2),
 		 BUTTON_EDGE_BRIGHT_FACTOR);
 
 	//  left edge
-	dst->fill_rect
+	dst.fill_rect
 		(Rect(Point(get_x_gap(),     get_y_gap()), 1, get_bar_size() - 1), black);
-	dst->fill_rect
+	dst.fill_rect
 		(Rect(Point(get_x_gap() + 1, get_y_gap()), 1, get_bar_size() - 2), black);
 
 	//  top edge
-	dst->fill_rect(Rect(Point(get_x_gap(), get_y_gap()),     4, 1), black);
-	dst->fill_rect(Rect(Point(get_x_gap(), get_y_gap() + 1), 3, 1), black);
+	dst.fill_rect(Rect(Point(get_x_gap(), get_y_gap()),     4, 1), black);
+	dst.fill_rect(Rect(Point(get_x_gap(), get_y_gap() + 1), 3, 1), black);
 
-	draw_cursor(*dst, 0, m_cursor_pos, get_w(), m_cursor_size);
+	draw_cursor(dst, 0, m_cursor_pos, get_w(), m_cursor_size);
 
 	if (g_gr->caps().offscreen_rendering)
 		odst.blit(Point(0, 0), m_cache_pic);

=== modified file 'src/ui_basic/slider.h'
--- src/ui_basic/slider.h	2010-05-19 13:25:43 +0000
+++ src/ui_basic/slider.h	2010-11-27 16:29:59 +0000
@@ -97,8 +97,8 @@
 protected:
 	int32_t m_cursor_pos;         //  cursor position
 	int32_t m_cursor_size;        //  cursor width
-	bool        m_needredraw;
-	PictureID   m_cache_pic;
+	bool m_needredraw;
+	OffscreenSurfacePtr m_cache_pic;
 };
 
 

=== modified file 'src/ui_fsmenu/base.cc'
--- src/ui_fsmenu/base.cc	2010-11-02 20:11:05 +0000
+++ src/ui_fsmenu/base.cc	2010-11-27 16:29:59 +0000
@@ -67,23 +67,18 @@
 	// Load background graphics
 	char buffer[256];
 	snprintf(buffer, sizeof(buffer), "pics/%s", bgpic);
-	m_pic_background = g_gr->get_picture(PicMod_Menu, buffer, false);
-	if (m_pic_background == g_gr->get_no_picture())
+	PictureID background = g_gr->get_picture(PicMod_Menu, buffer, false);
+	if (!background || background == g_gr->get_no_picture())
 		throw wexception
 			("could not open splash screen; make sure that all data files are "
 			 "installed");
 
-	m_res_background = g_gr->get_no_picture();
-	if (g_gr->caps().resize_surfaces)
-		m_res_background = g_gr->get_resized_picture
-			(m_pic_background, m_xres, m_yres, Graphic::ResizeMode_Loose);
+	m_res_background = g_gr->get_resized_picture
+			(background, m_xres, m_yres, Graphic::ResizeMode_Loose);
 }
 
-Fullscreen_Menu_Base::~Fullscreen_Menu_Base() {
-	if
-		(m_res_background != g_gr->get_no_picture() and
-		 m_res_background != m_pic_background)
-		g_gr->free_picture_surface(m_res_background);
+Fullscreen_Menu_Base::~Fullscreen_Menu_Base()
+{
 }
 
 
@@ -91,10 +86,7 @@
  * Draw the background / splash screen
 */
 void Fullscreen_Menu_Base::draw(RenderTarget & dst) {
-	if (g_gr->caps().blit_resized)
-		dst.blit(Rect(Point(0, 0), dst.get_w(), dst.get_h()), m_pic_background);
-	else
-		dst.blit(Point(0, 0), m_res_background);
+	dst.blit(Point(0, 0), m_res_background);
 }
 
 

=== modified file 'src/ui_fsmenu/base.h'
--- src/ui_fsmenu/base.h	2010-11-02 20:11:05 +0000
+++ src/ui_fsmenu/base.h	2010-11-27 16:29:59 +0000
@@ -47,7 +47,6 @@
 	uint32_t m_xres;
 	uint32_t m_yres;
 private:
-	PictureID m_pic_background;
 	PictureID m_res_background;
 };
 

=== modified file 'src/wui/interactive_gamebase.h'
--- src/wui/interactive_gamebase.h	2010-01-07 10:51:25 +0000
+++ src/wui/interactive_gamebase.h	2010-11-27 16:29:59 +0000
@@ -31,8 +31,6 @@
 	ChatDisplay(UI::Panel * parent, int32_t x, int32_t y, int32_t w, int32_t h);
 	~ChatDisplay();
 
-	void delete_all_left_message_pictures();
-
 	void setChatProvider(ChatProvider &);
 	virtual void draw(RenderTarget &);
 

=== modified file 'src/wui/interactive_player.cc'
--- src/wui/interactive_player.cc	2010-11-21 11:44:22 +0000
+++ src/wui/interactive_player.cc	2010-11-27 16:29:59 +0000
@@ -76,13 +76,6 @@
 {}
 ChatDisplay::~ChatDisplay()
 {
-	delete_all_left_message_pictures();
-}
-
-void ChatDisplay::delete_all_left_message_pictures() {
-	container_iterate_const(std::vector<PictureID>, m_cache_id, i)
-		if (*i.current != g_gr->get_no_picture())
-			UI::g_fh->delete_widget_cache(*i.current);
 }
 
 void ChatDisplay::setChatProvider(ChatProvider & chat)
@@ -102,7 +95,6 @@
 
 	// delete pictures of all old messages that we won't use again
 	// this is important to save space
-	delete_all_left_message_pictures();
 	m_cache_id.resize(0);
 
 	int32_t const now = time(0);
@@ -137,7 +129,7 @@
 			 Point(0, get_inner_h() -60 -y),
 			 "<rt>" + i.current->text + "</rt>",
 			 get_w(),
-			 m_cache_mode, picid, transparent_chat);
+			 m_cache_mode, &picid, transparent_chat);
 		y += i.current->h;
 		m_cache_id.push_back(picid);
 	}

=== modified file 'src/wui/plot_area.cc'
--- src/wui/plot_area.cc	2010-05-12 10:16:44 +0000
+++ src/wui/plot_area.cc	2010-11-27 16:29:59 +0000
@@ -143,7 +143,7 @@
 			 UI::Align_Center,
 			 std::numeric_limits<uint32_t>::max(),
 			 UI::Widget_Cache_None,
-			 g_gr->get_no_picture(),
+			 0,
 			 std::numeric_limits<uint32_t>::max(),
 			 false);
 		posx -= sub;
@@ -209,7 +209,7 @@
 		 UI::Align_CenterRight,
 		 std::numeric_limits<uint32_t>::max(),
 		 UI::Widget_Cache_None,
-		 g_gr->get_no_picture(),
+		 0,
 		 std::numeric_limits<uint32_t>::max(),
 		 false);
 

=== modified file 'src/wui/waresqueuedisplay.cc'
--- src/wui/waresqueuedisplay.cc	2010-11-21 11:44:22 +0000
+++ src/wui/waresqueuedisplay.cc	2010-11-27 16:29:59 +0000
@@ -98,8 +98,8 @@
 	set_think(true);
 }
 
-WaresQueueDisplay::~WaresQueueDisplay() {
-	g_gr->free_picture_surface(m_pic_background);
+WaresQueueDisplay::~WaresQueueDisplay()
+{
 }
 
 /**


Follow ups