changeset 150:6e7d228def30

Lazy loading for animations. Uses a Resource-Pointer class that behaves like a pointer to an IResource, but only loads the resource on demand. There's a slight change of API, which is already adapted to in the XML loaders. If you use Animation.addFrame directly, either adapt to the change or wait a few hours for a backwards compatibility solution.
author phoku@33b003aa-7bff-0310-803a-e67f0ece8222
date Sat, 11 Oct 2008 12:03:59 +0000
parents 823544621b5b
children afcd83f7fac8
files doc/dependencies/filedeps.dot engine/core/util/resource/resource.i engine/core/util/resource/resource_ptr.h engine/core/video/animation.cpp engine/core/video/animation.h engine/core/video/image_location.cpp engine/core/video/video.i engine/extensions/serializers/xmlanimation.py engine/extensions/serializers/xmlmap.py
diffstat 9 files changed, 207 insertions(+), 31 deletions(-) [+]
line wrap: on
line diff
--- a/doc/dependencies/filedeps.dot	Sat Oct 11 06:23:45 2008 +0000
+++ b/doc/dependencies/filedeps.dot	Sat Oct 11 12:03:59 2008 +0000
@@ -350,6 +350,8 @@
     "engine/core/util/resource/pool.h" -> "resource.h"
     "engine/core/util/resource/pool.h" -> "resource_location.h"
     "engine/core/util/resource/resource.h" -> "resource_location.h"
+    "engine/core/util/resource/resource_ptr.h" -> "pool.h"
+    "engine/core/util/resource/resource_ptr.h" -> "resource.h"
     "engine/core/util/structures/point.h" -> "util/base/fife_stdint.h"
     "engine/core/util/structures/point.h" -> "util/math/fife_math.h"
     "engine/core/util/structures/quadtree.h" -> "rect.h"
@@ -455,6 +457,7 @@
     "engine/core/video/animation.cpp" -> "util/time/timemanager.h"
     "engine/core/video/animation.h" -> "util/base/fife_stdint.h"
     "engine/core/video/animation.h" -> "util/base/resourceclass.h"
+    "engine/core/video/animation.h" -> "util/resource/resource_ptr.h"
     "engine/core/video/animationpool.h" -> "animation.h"
     "engine/core/video/animationpool.h" -> "util/resource/pool.h"
     "engine/core/video/cursor.cpp" -> "animation.h"
--- a/engine/core/util/resource/resource.i	Sat Oct 11 06:23:45 2008 +0000
+++ b/engine/core/util/resource/resource.i	Sat Oct 11 12:03:59 2008 +0000
@@ -22,6 +22,7 @@
 
 %{
 #include "util/resource/resource.h"
+#include "util/resource/resource_ptr.h"
 #include "util/resource/resource_location.h"
 #include "util/resource/pool.h"
 %}
@@ -96,4 +97,14 @@
 	private:
 		Pool();
 	};	
+
+	class ResourcePtr {
+	public:
+		ResourcePtr(IResource* ptr = 0);
+		ResourcePtr(Pool* pool,int index);
+		ResourcePtr(const ResourcePtr& r);
+		void release();
+		void load();
+		void unload();
+	};
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/engine/core/util/resource/resource_ptr.h	Sat Oct 11 12:03:59 2008 +0000
@@ -0,0 +1,154 @@
+/***************************************************************************
+ *   Copyright (C) 2005-2008 by the FIFE team                              *
+ *   http://www.fifengine.de                                               *
+ *   This file is part of FIFE.                                            *
+ *                                                                         *
+ *   FIFE is free software; you can redistribute it and/or                 *
+ *   modify it under the terms of the GNU Lesser General Public            *
+ *   License as published by the Free Software Foundation; either          *
+ *   version 2.1 of the License, or (at your option) any later version.    *
+ *                                                                         *
+ *   This library 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     *
+ *   Lesser General Public License for more details.                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU Lesser General Public      *
+ *   License along with this library; if not, write to the                 *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA          *
+ ***************************************************************************/
+
+#ifndef FIFE_RESOURE_PTR_H
+#define FIFE_RESOURE_PTR_H
+
+// Standard C++ library includes
+
+// 3rd party library includes
+
+// FIFE includes
+// These includes are split up in two parts, separated by one empty line
+// First block: files included from the FIFE root src directory
+// Second block: files included from the same folder
+#include "resource.h"
+#include "pool.h"
+
+namespace FIFE {
+
+	/** A lazy loading resource.
+	 */
+	class ResourcePtr {
+	public:
+		ResourcePtr(IResource* ptr = 0) : m_ptr(ptr),m_pool(0),m_index(Pool::INVALID_ID) {
+			if( m_ptr )
+				m_ptr->addRef();
+		}
+
+		ResourcePtr(Pool* pool,int index) : m_ptr(0),m_pool(pool),m_index(index) {
+		}
+
+		ResourcePtr(const ResourcePtr& r)
+		: m_ptr(r.m_ptr),m_pool(r.m_pool),m_index(r.m_index) {
+			if(m_ptr) {
+				 m_ptr->addRef();
+			}
+		}
+
+		ResourcePtr& operator=(const ResourcePtr& r) {
+			if( this == &r )
+				return *this;
+			release();
+			m_ptr = r.m_ptr;
+			m_pool = r.m_pool;
+			m_index = r.m_index;
+			if(m_ptr) {
+				 m_ptr->addRef();
+			}
+			return *this;
+		}
+
+		~ResourcePtr() {
+			release();
+		}
+
+		IResource& operator->() {
+			load();
+			return *m_ptr;
+		}
+
+		const IResource& operator->() const {
+			constLoad();
+			return *m_ptr;
+		}
+
+		operator bool() const {
+			return isValid();
+		}
+
+		bool isValid() const {
+			return m_ptr || isLoadable();
+		}
+
+		bool isLoadable() const {
+			return m_pool && m_index != Pool::INVALID_ID;
+		}
+
+		bool operator==(const ResourcePtr& r) const {
+			if( isLoadable() && r.isLoadable() )
+				return m_index == r.m_index && m_pool == r.m_pool;
+			if( !isLoadable() && !r.isLoadable() )
+				return m_ptr == r.m_ptr;
+			return false;
+		}
+
+		bool operator<(const ResourcePtr& r) const {
+			if( isLoadable() && r.isLoadable() )
+			{
+				if( m_pool == r.m_pool )
+					return m_index < r.m_index;
+				return m_pool < r.m_pool;
+			}
+			if( !isLoadable() && !r.isLoadable() )
+				return m_ptr < r.m_ptr;
+			return isLoadable() < r.isLoadable();
+		}
+
+		void release() {
+			if(m_ptr) {
+				 m_ptr->decRef();
+			}
+			m_ptr = 0;
+		}
+
+		void load() {
+			constLoad();
+		}
+
+		void unload() {
+			release();
+			if( isLoadable() ) {
+				m_pool->release(m_index);
+			}
+		}
+
+		template<class T>
+		T* get() {
+			if( isValid() )
+				load();
+			return dynamic_cast<T*>(m_ptr);
+		}
+
+	private:
+		void constLoad() const {
+			if( m_ptr )
+				return;
+			m_ptr = &m_pool->get(m_index);
+			m_ptr->addRef();
+		}
+		mutable IResource* m_ptr;
+		Pool* m_pool;
+		int m_index;
+	};
+}
+#endif
+
--- a/engine/core/video/animation.cpp	Sat Oct 11 06:23:45 2008 +0000
+++ b/engine/core/video/animation.cpp	Sat Oct 11 12:03:59 2008 +0000
@@ -46,20 +46,22 @@
 		}
 	
 	Animation::~Animation() {
-		std::vector<FrameInfo>::const_iterator i(m_frames.begin());
-		while (i != m_frames.end()) {
-			i->img->decRef();
-			i++;
-		}
+// 		std::vector<FrameInfo>::const_iterator i(m_frames.begin());
+// 		while (i != m_frames.end()) {
+// 			i->img->decRef();
+// 			i++;
+// 		}
 	}
 	
-	void Animation::addFrame(Image* image, unsigned int duration) {
-		image->addRef();
+// 	void Animation::addFrame(Image* image, unsigned int duration) {
+// 		addFrame(ResourcePtr(image),duration);
+// 	}
 
+	void Animation::addFrame(ResourcePtr image, unsigned int duration) {
 		FrameInfo info;
 		info.index = m_frames.size();
 		info.duration = duration;
-		info.img = image;
+		info.image = image;
 		m_frames.push_back(info);
 
 		std::map<unsigned int, FrameInfo>::const_iterator i(m_framemap.end());
@@ -95,7 +97,7 @@
 
 	Image* Animation::getFrame(int index) {
 		if (isValidIndex(index)) {
-			return m_frames[index].img;
+			return m_frames[index].image.get<Image>();
 		} else {
 			return NULL;
 		}
--- a/engine/core/video/animation.h	Sat Oct 11 06:23:45 2008 +0000
+++ b/engine/core/video/animation.h	Sat Oct 11 12:03:59 2008 +0000
@@ -37,6 +37,7 @@
 // First block: files included from the FIFE root src directory
 // Second block: files included from the same folder
 #include "util/base/resourceclass.h"
+#include "util/resource/resource_ptr.h"
 
 namespace FIFE {
 
@@ -72,7 +73,7 @@
 		 * @param image Pointer to Image. Does not transfer the ownership
 		 * @param duration Duration for given frame in the animation
 		 */
-		void addFrame(Image* image, unsigned int duration);
+		void addFrame(ResourcePtr image, unsigned int duration);
 
 		/** Get the frame index that matches given timestamp. In case there is no exact match,
 		 * correct frame is calculated. E.g. if there are frames for timestamps 50 and 100
@@ -137,7 +138,7 @@
 		struct FrameInfo {
 			unsigned int index;
 			unsigned int duration;
-			Image* img;
+			ResourcePtr image;
 		};
 
 		ResourceLocation m_location;
--- a/engine/core/video/image_location.cpp	Sat Oct 11 06:23:45 2008 +0000
+++ b/engine/core/video/image_location.cpp	Sat Oct 11 12:03:59 2008 +0000
@@ -41,9 +41,9 @@
 	}
 
 	bool ImageLocation::operator ==(const ResourceLocation& loc) const {
-		if (!ResourceLocation::operator==(loc)) {
+		if( m_type != loc.getType() )
 			return false;
-		}
+
 		const ImageLocation* r = dynamic_cast<const ImageLocation*>(&loc);
 		if (!r) {
 			return false;
@@ -64,6 +64,8 @@
 		if (m_parent_image != r->m_parent_image) {
 			return false;
 		}
+		if( getFilename() != loc.getFilename() )
+			return false;
  		return true;
 	}
 
--- a/engine/core/video/video.i	Sat Oct 11 06:23:45 2008 +0000
+++ b/engine/core/video/video.i	Sat Oct 11 12:03:59 2008 +0000
@@ -89,7 +89,7 @@
 	public:
 		explicit Animation();
 		~Animation();
-		void addFrame(Image* image, unsigned int duration);
+		void addFrame(ResourcePtr image, unsigned int duration);
 		int getFrameIndex(unsigned int timestamp);
 		Image* getFrame(int index);
 		Image* getFrameByTimestamp(unsigned int timestamp);
--- a/engine/extensions/serializers/xmlanimation.py	Sat Oct 11 06:23:45 2008 +0000
+++ b/engine/extensions/serializers/xmlanimation.py	Sat Oct 11 12:03:59 2008 +0000
@@ -44,10 +44,13 @@
 			path.pop()
 			path.append(str(source))
 
-			image = self.imagepool.getImage(self.imagepool.getIndex('/'.join(path)))
-			image.setXShift(frame_x_offset)
-			image.setYShift(frame_y_offset)
-			animation.addFrame(image, frame_delay);
+			image_location = fife.ImageLocation('/'.join(path))
+			image_location.setXShift(frame_x_offset)
+			image_location.setYShift(frame_y_offset)
+
+			image_index = self.imagepool.addResourceFromLocation(image_location)
+			animation.addFrame(fife.ResourcePtr(self.imagepool,image_index), frame_delay)
+			#print "...",image_index,image_location.getFilename()
 
 		animation.thisown = 0
 		return animation
--- a/engine/extensions/serializers/xmlmap.py	Sat Oct 11 06:23:45 2008 +0000
+++ b/engine/extensions/serializers/xmlmap.py	Sat Oct 11 12:03:59 2008 +0000
@@ -85,7 +85,9 @@
 		return self.map
 
 	def parse_imports(self, mapelt, map):
-		if self.callback is not None:		
+		parsedImports = {}
+
+		if self.callback:		
 			tmplist = mapelt.findall('import')
 			i = float(0)
 		
@@ -97,6 +99,12 @@
 			if dir:
 				dir = reverse_root_subfile(self.source, dir)
 
+			# Don't parse duplicate imports
+			if (dir,file) in parsedImports:
+				print "Duplicate import:" ,(dir,file)
+				continue
+			parsedImports[(dir,file)] = 1
+
 			if file and dir:
 				loaders.loadImportFile('/'.join(dir, file), self.engine)
 			elif file:
@@ -107,14 +115,10 @@
 			else:
 				print 'Empty import statement?'
 				
-			if self.callback is not None:
+			if self.callback:
 				i += 1				
 				self.callback('loaded imports', float( i / float(len(tmplist)) * 0.25 + 0.25 ) )
-				
-		# cleanup
-		if self.callback is not None:
-			del tmplist
-			del i
+
 
 	def parse_layers(self, mapelt, map):
 		if self.callback is not None:		
@@ -261,7 +265,7 @@
 				inst.act('default', target, True)
 
 	def parse_cameras(self, mapelt, map):
-		if self.callback is not None:		
+		if self.callback:		
 			tmplist = mapelt.findall('camera')
 			i = float(0)
 
@@ -297,11 +301,7 @@
 			except fife.Exception, e:
 				print e.getMessage()
 				
-			if self.callback is not None:
+			if self.callback:
 				i += 1
 				self.callback('loaded camera: ' +  str(id), float( i / len(tmplist) * 0.25 + 0.75 ) )	
 			
-		# cleanup
-		if self.callback is not None:
-			del tmplist
-			del i