[Scummvm-cvs-logs] SF.net SVN: scummvm:[49150] scummvm/trunk/engines/m4

dreammaster at users.sourceforge.net dreammaster at users.sourceforge.net
Sun May 23 09:20:40 CEST 2010


Revision: 49150
          http://scummvm.svn.sourceforge.net/scummvm/?rev=49150&view=rev
Author:   dreammaster
Date:     2010-05-23 07:20:40 +0000 (Sun, 23 May 2010)

Log Message:
-----------
Major work done on the animation and support classes to match the original

Modified Paths:
--------------
    scummvm/trunk/engines/m4/assets.cpp
    scummvm/trunk/engines/m4/assets.h
    scummvm/trunk/engines/m4/globals.h
    scummvm/trunk/engines/m4/graphics.cpp
    scummvm/trunk/engines/m4/graphics.h
    scummvm/trunk/engines/m4/mads_logic.cpp
    scummvm/trunk/engines/m4/mads_menus.cpp
    scummvm/trunk/engines/m4/mads_scene.cpp
    scummvm/trunk/engines/m4/mads_scene.h
    scummvm/trunk/engines/m4/mads_views.cpp
    scummvm/trunk/engines/m4/mads_views.h
    scummvm/trunk/engines/m4/sprite.h

Modified: scummvm/trunk/engines/m4/assets.cpp
===================================================================
--- scummvm/trunk/engines/m4/assets.cpp	2010-05-23 05:51:32 UTC (rev 49149)
+++ scummvm/trunk/engines/m4/assets.cpp	2010-05-23 07:20:40 UTC (rev 49150)
@@ -195,7 +195,9 @@
 	_maxHeight = 0;
 
 	Common::SeekableReadStream *spriteStream = sprite.getItemStream(0);
-	for (int i = 0; i < 19; i++) {
+
+	_assetType = spriteStream->readUint16LE();
+	for (int i = 0; i < 18; i++) {
 		spriteStream->readUint16LE();
 	}
 	_frameCount = spriteStream->readUint16LE();

Modified: scummvm/trunk/engines/m4/assets.h
===================================================================
--- scummvm/trunk/engines/m4/assets.h	2010-05-23 05:51:32 UTC (rev 49149)
+++ scummvm/trunk/engines/m4/assets.h	2010-05-23 07:20:40 UTC (rev 49150)
@@ -113,6 +113,7 @@
 	int32 getFrameHeight(int index);
 	int32 getMaxFrameWidth() const { return _maxWidth; }
 	int32 getMaxFrameHeight() const { return _maxHeight; }
+	uint16 getAssetType() const { return _assetType; }
 	M4Sprite *getFrame(int frameIndex);
 	void loadStreamingFrame(M4Sprite *frame, int frameIndex, int destX, int destY);
 	RGB8* getPalette() { return _palette; }
@@ -123,6 +124,7 @@
 	int32 getFrameSize(int index);
 	M4Sprite *operator[](int index) { return getFrame(index); }
 protected:
+	Common::SeekableReadStream *_stream;
 	RGB8 _palette[256];
 	uint32 _colorCount;
 	uint32 _srcSize;
@@ -132,7 +134,10 @@
 	Common::Array<uint32> _frameOffsets;
 	Common::Array<SpriteAssetFrame> _frames;
 	uint32 _frameStartOffset;
-	Common::SeekableReadStream *_stream;
+	
+	// MADS sprite set fields
+	uint16 _assetType;
+
 	int32 parseSprite(bool isBigEndian = false);
 	void loadFrameHeader(SpriteAssetFrame &frameHeader, bool isBigEndian = false);
 private:

Modified: scummvm/trunk/engines/m4/globals.h
===================================================================
--- scummvm/trunk/engines/m4/globals.h	2010-05-23 05:51:32 UTC (rev 49149)
+++ scummvm/trunk/engines/m4/globals.h	2010-05-23 07:20:40 UTC (rev 49150)
@@ -264,6 +264,7 @@
 	// DEPRECATED: ScummVM re-implementation keeps all the quotes loaded, so the methods below are stubs
 	void clearQuotes() {}
 	void loadQuoteRange(int startNum, int endNum) {}
+	void loadQuoteSet(...) {}
 	void loadQuote(int quoteNum) {}
 
 	void loadMadsMessagesInfo();

Modified: scummvm/trunk/engines/m4/graphics.cpp
===================================================================
--- scummvm/trunk/engines/m4/graphics.cpp	2010-05-23 05:51:32 UTC (rev 49149)
+++ scummvm/trunk/engines/m4/graphics.cpp	2010-05-23 07:20:40 UTC (rev 49150)
@@ -333,7 +333,7 @@
 }
 
 void M4Surface::copyFrom(M4Surface *src, const Common::Rect &srcBounds, int destX, int destY,
-						 int transparentColor) {
+						 int transparentColour) {
 	// Validation of the rectangle and position
 	if ((destX >= w) || (destY >= h))
 		return;
@@ -362,13 +362,13 @@
 	byte *destPtr = (byte *)pixels + (destY * width()) + destX;
 
 	for (int rowCtr = 0; rowCtr < copyRect.height(); ++rowCtr) {
-		if (transparentColor == -1)
+		if (transparentColour == -1)
 			// No transparency, so copy line over
 			Common::copy(srcPtr, srcPtr + copyRect.width(), destPtr);
 		else {
 			// Copy each byte one at a time checking for the transparency color
 			for (int xCtr = 0; xCtr < copyRect.width(); ++xCtr)
-				if (srcPtr[xCtr] != transparentColor) destPtr[xCtr] = srcPtr[xCtr];
+				if (srcPtr[xCtr] != transparentColour) destPtr[xCtr] = srcPtr[xCtr];
 		}
 
 		srcPtr += src->width();
@@ -378,6 +378,81 @@
 	src->freeData();
 }
 
+/**
+ * Copies a given image onto a destination surface with scaling, transferring only pixels that meet
+ * the specified depth requirement on a secondary surface contain depth information
+ */
+void M4Surface::copyFrom(M4Surface *src, int destX, int destY, int depth, M4Surface *depthsSurface, 
+						 int scale, int transparentColour) {
+	/* TODO: This isn't a straight re-implementation of the original draw routine. Double check in future
+	 * whether this implementation provides equivalent functionality
+	 */
+	Common::Rect copyRect(0, 0, src->width(), src->height());
+
+	if (destX < 0) {
+		copyRect.left += -destX;
+		destX = 0;
+	} else if (destX + copyRect.width() > w) {
+		copyRect.right -= destX + copyRect.width() - w;
+	}
+	if (destY < 0) {
+		copyRect.top += -destY;
+		destY = 0;
+	} else if (destY + copyRect.height() > h) {
+		copyRect.bottom -= destY + copyRect.height() - h;
+	}
+
+	if (!copyRect.isValidRect())
+		return;
+
+	// Copy the specified area
+
+	byte *data = src->getBasePtr();
+	byte *srcPtr = data + (src->width() * copyRect.top + copyRect.left);
+	byte *depthsData = depthsSurface->getBasePtr();
+	byte *depthsPtr = depthsData + (src->width() * copyRect.top + copyRect.left);
+	byte *destPtr = (byte *)pixels + (destY * width()) + destX;
+
+	if (scale == 100) {
+		// 100% scaling variation
+		for (int rowCtr = 0; rowCtr < copyRect.height(); ++rowCtr) {
+			// Copy each byte one at a time checking against the depth
+			for (int xCtr = 0; xCtr < copyRect.width(); ++xCtr) {
+				if ((depthsPtr[xCtr] > depth) && (srcPtr[xCtr] != transparentColour))
+					destPtr[xCtr] = srcPtr[xCtr];
+			}
+
+			srcPtr += src->width();
+			depthsPtr += depthsSurface->width();
+			destPtr += width();
+		}
+	} else {
+		// Scaled variation
+		for (int rowCtr = 0; rowCtr < copyRect.height(); ++rowCtr) {
+			int currX = -1;
+
+			// Loop through the source pixels
+			for (int xCtr = 0, xTotal = 0; xCtr < copyRect.width(); ++xCtr, xTotal += (100 - scale)) {
+				int srcX = xTotal / 100;
+
+				if (srcX != currX) {
+					currX = srcX;
+
+					if ((depthsPtr[currX] > depth) && (srcPtr[xCtr] != transparentColour))
+						destPtr[currX] = srcPtr[xCtr];
+				}
+			}
+
+			srcPtr += src->width();
+			depthsPtr += depthsSurface->width();
+			destPtr += width();
+		}
+	}
+
+	src->freeData();
+	depthsSurface->freeData();	
+}
+
 void M4Surface::loadBackgroundRiddle(const char *sceneName) {
 	char resourceName[20];
 	Common::SeekableReadStream *stream;

Modified: scummvm/trunk/engines/m4/graphics.h
===================================================================
--- scummvm/trunk/engines/m4/graphics.h	2010-05-23 05:51:32 UTC (rev 49149)
+++ scummvm/trunk/engines/m4/graphics.h	2010-05-23 07:20:40 UTC (rev 49150)
@@ -145,8 +145,10 @@
 	void clear();
 	void frameRect(const Common::Rect &r, uint8 color);
 	void fillRect(const Common::Rect &r, uint8 color);
-	void copyFrom(M4Surface *src, const Common::Rect &srcBounds, int destX, int destY,
-		int transparentColor = -1);
+	void copyFrom(M4Surface *src, const Common::Rect &srcBounds, int destX, int destY, 
+			int transparentColour = -1);
+	void copyFrom(M4Surface *src, int destX, int destY, int depth, M4Surface *depthSurface, int scale,
+			int transparentColour = -1);
 
 	void update() {
 		if (_isScreen) {
@@ -156,17 +158,23 @@
 	}
 
 	// copyTo methods
-	inline void copyTo(M4Surface *dest, int transparentColor = -1) {
-		dest->copyFrom(this, Common::Rect(width(), height()), 0, 0, transparentColor);
+	inline void copyTo(M4Surface *dest, int transparentColour = -1) {
+		dest->copyFrom(this, Common::Rect(width(), height()), 0, 0, transparentColour);
 	}
-	inline void copyTo(M4Surface *dest, int x, int y, int transparentColor = -1) {
-		dest->copyFrom(this, Common::Rect(width(), height()), x, y, transparentColor);
+	inline void copyTo(M4Surface *dest, int x, int y, int transparentColour = -1) {
+		dest->copyFrom(this, Common::Rect(width(), height()), x, y, transparentColour);
 	}
 	inline void copyTo(M4Surface *dest, const Common::Rect &srcBounds, int destX, int destY,
-				int transparentColor = -1) {
-		dest->copyFrom(this, srcBounds, destX, destY, transparentColor);
+				int transparentColour = -1) {
+		dest->copyFrom(this, srcBounds, destX, destY, transparentColour);
 	}
+	inline void copyTo(M4Surface *dest, int destX, int destY, int depth, M4Surface *depthsSurface, int scale,
+				int transparentColour = -1) {
+		dest->copyFrom(this, destX, destY, depth, depthsSurface, scale, transparentColour);
+	}
 
+
+
 	void translate(RGBList *list, bool isTransparent = false);
 };
 

Modified: scummvm/trunk/engines/m4/mads_logic.cpp
===================================================================
--- scummvm/trunk/engines/m4/mads_logic.cpp	2010-05-23 05:51:32 UTC (rev 49149)
+++ scummvm/trunk/engines/m4/mads_logic.cpp	2010-05-23 07:20:40 UTC (rev 49150)
@@ -78,7 +78,7 @@
 }
 
 uint16 MadsSceneLogic::startReversibleSpriteSequence(uint16 srcSpriteIdx, int v0, int numTicks, int triggerCountdown, int timeoutTicks, int extraTicks) {
-	M4Sprite *spriteFrame = _madsVm->scene()->_spriteSlots.getSprite(srcSpriteIdx).getFrame(1);
+	M4Sprite *spriteFrame = _madsVm->scene()->_spriteSlots.getSprite(srcSpriteIdx).getFrame(0);
 	uint8 depth = _madsVm->_rails->getDepth(Common::Point(spriteFrame->x + (spriteFrame->width() / 2),
 		spriteFrame->y + (spriteFrame->height() / 2)));
 
@@ -87,8 +87,7 @@
 }
 
 uint16 MadsSceneLogic::startCycledSpriteSequence(uint16 srcSpriteIdx, int v0, int numTicks, int triggerCountdown, int timeoutTicks, int extraTicks) {
-	M4Sprite *spriteFrame = _madsVm->scene()->_spriteSlots.getSprite(srcSpriteIdx).getFrame(1);
-warning("%d %dx%d %d/%d", srcSpriteIdx, spriteFrame->x, spriteFrame->y, spriteFrame->width(), spriteFrame->height());
+	M4Sprite *spriteFrame = _madsVm->scene()->_spriteSlots.getSprite(srcSpriteIdx).getFrame(0);
 	uint8 depth = _madsVm->_rails->getDepth(Common::Point(spriteFrame->x + (spriteFrame->width() / 2),
 		spriteFrame->y + (spriteFrame->height() / 2)));
 
@@ -97,7 +96,7 @@
 }
 
 uint16 MadsSceneLogic::startSpriteSequence3(uint16 srcSpriteIdx, int v0, int numTicks, int triggerCountdown, int timeoutTicks, int extraTicks) {
-	M4Sprite *spriteFrame = _madsVm->scene()->_spriteSlots.getSprite(srcSpriteIdx).getFrame(1);
+	M4Sprite *spriteFrame = _madsVm->scene()->_spriteSlots.getSprite(srcSpriteIdx).getFrame(0);
 	uint8 depth = _madsVm->_rails->getDepth(Common::Point(spriteFrame->x + (spriteFrame->width() / 2),
 		spriteFrame->y + (spriteFrame->height() / 2)));
 
@@ -160,7 +159,7 @@
 	assert(sceneNum == 101);
 	_sceneNumber = sceneNum;
 
-
+	Common::set_to(&_spriteIndexes[0], &_spriteIndexes[50], 0);
 }
 
 void MadsSceneLogic::setupScene() {
@@ -206,11 +205,39 @@
 	if (_madsVm->globals()->previousScene != -1)
 		_madsVm->globals()->_globals[10] = 0;
 	if (_madsVm->globals()->previousScene != -2) {
-		//playerPos = (100, 152);
+		_madsVm->scene()->getSceneResources().playerPos = Common::Point(100, 152);
 	}
 	
-	// TODO: EXTRA STUFF
+	if ((_madsVm->globals()->previousScene == 112) || 
+		((_madsVm->globals()->previousScene != -2) && (_spriteIndexes[29] != 0))) {
+		// Returning from probe cutscene?
+		_spriteIndexes[29] = -1;
+		_madsVm->scene()->getSceneResources().playerPos = Common::Point(161, 123);
+		_madsVm->scene()->getSceneResources().playerDir = 9;
 
+		// TODO: Extra flags setting
+		_spriteIndexes[25] = startCycledSpriteSequence(_spriteIndexes[10], 0, 3, 0, 0, 0);
+		_madsVm->scene()->_sequenceList.setAnimRange(_spriteIndexes[25], 17, 17);
+		activateHotspot(0x47, false);	// CHAIR
+		/*timer_unk1 = */_madsVm->scene()->_dynamicHotspots.add(0x47, 0x13F /*SIT_IN*/, -1,
+			Common::Rect(159, 84, 159+33, 84+36));
+		
+		//if (_madsVm->globals()->previousScene == 112)
+		//	room101Check();
+	} else {
+		_spriteIndexes[26] = startCycledSpriteSequence(_spriteIndexes[11], 0, 6, 0, 0, 0);
+	}
+
+	_madsVm->globals()->loadQuoteSet(0x31, 0x32, 0x37, 0x38, 0x39, -1);
+
+	if (_madsVm->globals()->_globals[10]) {
+		// TODO: Load scene animation
+
+		_madsVm->scene()->getSceneResources().playerPos = Common::Point(68, 140);
+		_madsVm->scene()->getSceneResources().playerDir = 4;
+		// TODO: Flags setting
+	}
+
 	lowRoomsEntrySound();
 }
 

Modified: scummvm/trunk/engines/m4/mads_menus.cpp
===================================================================
--- scummvm/trunk/engines/m4/mads_menus.cpp	2010-05-23 05:51:32 UTC (rev 49149)
+++ scummvm/trunk/engines/m4/mads_menus.cpp	2010-05-23 07:20:40 UTC (rev 49150)
@@ -616,9 +616,9 @@
 	}
 	_totalTextEntries = 0;
 
-	// Set up a default sprite slot entry
+	// Set up a default sprite slot entry for a full screen refresh
 	_spriteSlots.startIndex = 1;
-	_spriteSlots[0].spriteId = -2;
+	_spriteSlots[0].spriteType = FULL_SCREEN_REFRESH;
 	_spriteSlots[0].timerIndex = -1;
 }
 
@@ -795,7 +795,7 @@
 
 void RexDialogView::setFrame(int frameNumber, int depth) {
 	int slotIndex = _spriteSlots.getIndex();
-	_spriteSlots[slotIndex].spriteId = 1;
+	_spriteSlots[slotIndex].spriteType = FOREGROUND_SPRITE;
 	_spriteSlots[slotIndex].timerIndex = 1;
 	_spriteSlots[slotIndex].spriteListIndex = 0; //_menuSpritesIndex;
 	_spriteSlots[slotIndex].frameNumber = frameNumber;

Modified: scummvm/trunk/engines/m4/mads_scene.cpp
===================================================================
--- scummvm/trunk/engines/m4/mads_scene.cpp	2010-05-23 05:51:32 UTC (rev 49149)
+++ scummvm/trunk/engines/m4/mads_scene.cpp	2010-05-23 07:20:40 UTC (rev 49150)
@@ -43,6 +43,8 @@
 MadsScene::MadsScene(MadsEngine *vm): _sceneResources(), Scene(vm, &_sceneResources), MadsView(this) {
 	_vm = vm;
 
+	MadsView::_bgSurface = Scene::_backgroundSurface;
+	MadsView::_depthSurface = Scene::_walkSurface;
 	_interfaceSurface = new MadsInterfaceView(vm);
 	for (int i = 0; i < 3; ++i)
 		actionNouns[i] = 0;
@@ -277,9 +279,6 @@
 
 
 void MadsScene::update() {
-	// Copy the bare scene in
-	_backgroundSurface->copyTo(this);
-
 	// Draw all the various elements
 	drawElements();
 

Modified: scummvm/trunk/engines/m4/mads_scene.h
===================================================================
--- scummvm/trunk/engines/m4/mads_scene.h	2010-05-23 05:51:32 UTC (rev 49149)
+++ scummvm/trunk/engines/m4/mads_scene.h	2010-05-23 07:20:40 UTC (rev 49150)
@@ -34,19 +34,7 @@
 
 #define INTERFACE_HEIGHT 106
 
-struct SpriteSlot {
-	int16 spriteId;
-	int16 scale;
-	uint16 spriteListIndex;
-};
 
-struct DirtyArea {
-	bool active;
-	bool active2;
-	Common::Rect bounds;
-};
-
-
 class MadsSceneResources: public SceneResources {
 public:
 	int sceneId;
@@ -60,8 +48,10 @@
 	
 	int walkSize;
 	byte *walkData;
+	Common::Point playerPos;
+	int playerDir;
 
-	MadsSceneResources() { walkSize = 0; walkData = NULL; }
+	MadsSceneResources() { walkSize = 0; walkData = NULL; playerDir = 0; }
 	~MadsSceneResources() { delete walkData; }
 	void load(int sceneId);	
 };
@@ -101,8 +91,6 @@
 	const char *statusText() const { return _statusText; }
 };
 
-#define DIRTY_AREA_SIZE 90
-
 class MadsScene : public Scene, public MadsView {
 private:
 	MadsEngine *_vm;
@@ -111,7 +99,6 @@
 
 	MadsSceneLogic _sceneLogic;
 	SpriteAsset *_playerSprites;
-	DirtyArea _dirtyAreas[DIRTY_AREA_SIZE];
 
 	void drawElements();
 	void loadScene2(const char *aaName);

Modified: scummvm/trunk/engines/m4/mads_views.cpp
===================================================================
--- scummvm/trunk/engines/m4/mads_views.cpp	2010-05-23 05:51:32 UTC (rev 49149)
+++ scummvm/trunk/engines/m4/mads_views.cpp	2010-05-23 07:20:40 UTC (rev 49150)
@@ -43,7 +43,7 @@
 
 //--------------------------------------------------------------------------
 
-MadsSpriteSlots::MadsSpriteSlots() {
+MadsSpriteSlots::MadsSpriteSlots(MadsView &owner): _owner(owner) {
 	for (int i = 0; i < SPRITE_SLOTS_SIZE; ++i) {
 		MadsSpriteSlot rec;
 		_entries.push_back(rec);
@@ -52,6 +52,16 @@
 	startIndex = 0;
 }
 
+void MadsSpriteSlots::clear() {
+	_owner._textDisplay.clear();
+	_sprites.clear();
+
+	// Reset the sprite slots list back to a single entry for a full screen refresh
+	startIndex = 1;
+	_entries[0].spriteType = FULL_SCREEN_REFRESH;
+	_entries[0].timerIndex = -1;
+}
+
 int MadsSpriteSlots::getIndex() {
 	if (startIndex == SPRITE_SLOTS_SIZE)
 		error("Run out of sprite slots");
@@ -77,7 +87,7 @@
 void MadsSpriteSlots::deleteTimer(int timerIndex) {
 	for (int idx = 0; idx < startIndex; ++idx) {
 		if (_entries[idx].timerIndex == timerIndex)
-			_entries[idx].spriteId = -1;
+			_entries[idx].spriteType = -1;
 	}
 }
 
@@ -95,12 +105,49 @@
 
 typedef Common::List<DepthEntry> DepthList;
 
-void MadsSpriteSlots::draw(View *view) {
+void MadsSpriteSlots::drawBackground() {
+	// Draw all active sprites onto the background surface
+	for (int i = 0; i < startIndex; ++i) {
+		if (_entries[i].spriteType >= 0) {
+			_owner._dirtyAreas[i].active = false;
+		} else {
+			_owner._dirtyAreas[i].textActive = true;
+			_owner._dirtyAreas.setSpriteSlot(i, _entries[i]);
+
+			if (_entries[i].spriteType == BACKGROUND_SPRITE) {
+				SpriteAsset &spriteSet = getSprite(_entries[i].spriteListIndex);
+				M4Sprite *frame = spriteSet.getFrame((_entries[i].frameNumber & 0x7fff) - 1);
+				int xp = _entries[i].xp;
+				int yp = _entries[i].yp;
+
+				if (_entries[i].scale != -1) {
+					// Adjust position based on frame size
+					xp -= frame->width() / 2;
+					yp -= frame->height() / 2;
+				}
+
+				if (_entries[i].depth <= 1) {
+					// No depth, so simply copy the frame onto the background
+					frame->copyTo(_owner._bgSurface, xp, yp);
+				} else {
+					// Depth was specified, so draw frame using scene's depth information
+					frame->copyTo(_owner._bgSurface, xp, yp, _entries[i].depth, _owner._depthSurface, 100);
+				}
+			}
+		}
+	}
+
+	// Flag any remaining dirty areas as inactive
+	for (uint i = startIndex; i < DIRTY_AREAS_TEXT_DISPLAY_IDX; ++i)
+		_owner._dirtyAreas[i].active = false;
+}
+
+void MadsSpriteSlots::drawForeground(View *view) {
 	DepthList depthList;
 
 	// Get a list of sprite object depths for active objects
 	for (int i = 0; i < startIndex; ++i) {
-		if (_entries[i].spriteId >= 0) {
+		if (_entries[i].spriteType >= 0) {
 			DepthEntry rec(_entries[i].depth, i);
 			depthList.push_back(rec);
 		}
@@ -121,28 +168,41 @@
 			// Minimalised drawing
 			assert(slot.spriteListIndex < (int)_sprites.size());
 			M4Sprite *spr = spriteSet.getFrame(slot.frameNumber - 1);
-			spr->draw1(view, slot.scale, slot.depth, slot.xp, slot.yp);
+			spr->copyTo(view, slot.xp, slot.yp, slot.depth, _owner._depthSurface, slot.scale, 0);
 		} else {
 			int xp, yp;
 			M4Sprite *spr = spriteSet.getFrame(slot.frameNumber - 1);
 
 			if (slot.scale == -1) {
-				xp = slot.xp; // - widthAdjust;
-				yp = slot.yp; // - heightAdjust;
+				xp = slot.xp - _owner._posAdjust.x;
+				yp = slot.yp - _owner._posAdjust.y;
 			} else {
-				xp = slot.xp - (spr->width() / 2); // - widthAdjust;
-				yp = slot.yp - spr->height() + 1; // - heightAdjust;
+				xp = slot.xp - (spr->width() / 2) - _owner._posAdjust.x;
+				yp = slot.yp - spr->height() - _owner._posAdjust.y + 1;
 			}
 
 			if (slot.depth > 1) {
-				spr->draw2(view, slot.depth, xp, yp);
+				// Draw the frame with depth processing
+				spr->copyTo(view, xp, yp, slot.depth, _owner._depthSurface, 100, 0);
 			} else {
-				spr->draw3(view, xp, yp);
+				// No depth, so simply draw the image
+				spr->copyTo(view, xp, yp, 0);
 			}
 		}
 	}
 }
 
+void MadsSpriteSlots::setDirtyAreas() {
+	for (int i = 0; i < startIndex; ++i) {
+		if (_entries[i].spriteType >= 0) {
+			_owner._dirtyAreas.setSpriteSlot(i, _entries[i]);
+
+			_owner._dirtyAreas[i].textActive = (_entries[i].spriteType <= 0) ? 0 : 1;
+			_entries[i].spriteType = 0;
+		}
+	}
+}
+
 /**
  * Removes any sprite slots that are no longer needed
  */
@@ -150,7 +210,7 @@
 	// Delete any entries that aren't needed
 	int idx = 0;
 	while (idx < startIndex) {
-		if (_entries[idx].spriteId >= 0) {
+		if (_entries[idx].spriteType < 0) {
 			_entries.remove_at(idx);
 			--startIndex;
 		} else {
@@ -168,7 +228,7 @@
 
 //--------------------------------------------------------------------------
 
-MadsTextDisplay::MadsTextDisplay() {
+MadsTextDisplay::MadsTextDisplay(MadsView &owner): _owner(owner) {
 	for (int i = 0; i < TEXT_DISPLAY_SIZE; ++i) {
 		MadsTextDisplayEntry rec;
 		rec.active = false;
@@ -206,6 +266,28 @@
 	return usedSlot;
 }
 
+void MadsTextDisplay::setDirtyAreas() {
+	// Determine dirty areas for active text areas
+	for (uint idx = 0, dirtyIdx = DIRTY_AREAS_TEXT_DISPLAY_IDX; dirtyIdx < DIRTY_AREAS_SIZE; ++idx, ++dirtyIdx) {
+		if ((_entries[idx].expire < 0) || !_entries[idx].active)
+			_owner._dirtyAreas[dirtyIdx].active = false;
+		else {
+			_owner._dirtyAreas[dirtyIdx].textActive = true;
+			_owner._dirtyAreas.setTextDisplay(dirtyIdx, _entries[idx]);
+		}
+	}
+}
+
+void MadsTextDisplay::setDirtyAreas2() {
+	// Determine dirty areas for active text areas
+	for (uint idx = 0, dirtyIdx = DIRTY_AREAS_TEXT_DISPLAY_IDX; dirtyIdx < DIRTY_AREAS_SIZE; ++idx, ++dirtyIdx) {
+		if (_entries[idx].active && (_entries[idx].expire >= 0)) {
+			_owner._dirtyAreas.setTextDisplay(dirtyIdx, _entries[idx]);
+			_owner._dirtyAreas[dirtyIdx].textActive = (_entries[idx].expire <= 0) ? 0 : 1;
+		}
+	}
+}
+
 void MadsTextDisplay::draw(View *view) {
 	for (uint idx = 0; idx < _entries.size(); ++idx) {
 		if (_entries[idx].active && (_entries[idx].expire >= 0)) {
@@ -405,21 +487,23 @@
 	for (int i = 0; i < DYNAMIC_HOTSPOTS_SIZE; ++i) {
 		DynamicHotspot rec;
 		rec.active = false;
+		_entries.push_back(rec);
 	}
 	_flag = true;
 	_count = 0;
 }
 
-int MadsDynamicHotspots::add(int descId, int field14, int timerIndex, const Common::Rect &bounds) {
+int MadsDynamicHotspots::add(int descId, int field14, int seqIndex, const Common::Rect &bounds) {
 	// Find a free slot
 	uint idx = 0;
-	while ((idx < _entries.size()) && !_entries[idx].active)
+	while ((idx < _entries.size()) && _entries[idx].active)
 		++idx;
 	if (idx == _entries.size())
 		error("MadsDynamicHotspots overflow");
 
 	_entries[idx].active = true;
 	_entries[idx].descId = descId;
+	_entries[idx].seqIndex = seqIndex;
 	_entries[idx].bounds = bounds;
 	_entries[idx].pos.x = -3;
 	_entries[idx].pos.y = 0;
@@ -430,8 +514,10 @@
 
 	++_count;
 	_flag = true;
-	_owner._sequenceList[timerIndex].dynamicHotspotIndex = idx;
 
+	if (seqIndex >= 0)
+		_owner._sequenceList[seqIndex].dynamicHotspotIndex = idx;
+
 	return idx;
 }
 
@@ -454,8 +540,8 @@
 
 void MadsDynamicHotspots::remove(int index) {
 	if (_entries[index].active) {
-		if (_entries[index].timerIndex >= 0)
-			_owner._sequenceList[_entries[index].timerIndex].dynamicHotspotIndex = -1;
+		if (_entries[index].seqIndex >= 0)
+			_owner._sequenceList[_entries[index].seqIndex].dynamicHotspotIndex = -1;
 		_entries[index].active = false;
 
 		--_count;
@@ -473,6 +559,143 @@
 
 /*--------------------------------------------------------------------------*/
 
+void MadsDirtyArea::setArea(int width, int height, int maxWidth, int maxHeight) {
+	if (bounds.left % 2) {
+		--bounds.left;
+		++width;
+	}
+	int right = bounds.left + width;
+	if (bounds.left < 0)
+		bounds.left = 0;
+	if (right < 0)
+		right = 0;
+	if (right > maxWidth)
+		right = maxWidth;
+
+	bounds.right = right;
+	bounds2.left = bounds.width() / 2;
+	bounds2.right = bounds.left + (bounds.width() + 1) / 2 - 1;
+
+	if (bounds.top < 0)
+		bounds.top = 0;
+	int bottom = bounds.top + height;
+	if (bottom < 0)
+		bottom = 0;
+	if (bottom > maxHeight)
+		bottom = maxHeight;
+
+	bounds.bottom = bottom;
+	bounds2.top = bounds.height() / 2;
+	bounds2.bottom = bounds.top + (bounds.height() + 1) / 2 - 1;
+
+	active = true;
+}
+
+/*--------------------------------------------------------------------------*/
+
+MadsDirtyAreas::MadsDirtyAreas(MadsView &owner): _owner(owner) {
+	for (int i = 0; i < DIRTY_AREAS_SIZE; ++i) {
+		MadsDirtyArea rec;
+		rec.active = false;
+		_entries.push_back(rec);
+	}
+}
+
+void MadsDirtyAreas::setSpriteSlot(int dirtyIdx, const MadsSpriteSlot &spriteSlot) {
+	int width, height;
+	MadsDirtyArea &dirtyArea = _entries[dirtyIdx];
+
+	if (spriteSlot.spriteType == FULL_SCREEN_REFRESH) {
+		// Special entry to refresh the entire screen
+		dirtyArea.bounds.left = 0;
+		dirtyArea.bounds.top = 0;
+		width = MADS_SURFACE_WIDTH;
+		height = MADS_SURFACE_HEIGHT;
+	} else {
+		// Standard sprite slots
+		dirtyArea.bounds.left = spriteSlot.xp - _owner._posAdjust.x;
+		dirtyArea.bounds.top = spriteSlot.yp - _owner._posAdjust.y;
+
+		SpriteAsset &spriteSet = _owner._spriteSlots.getSprite(spriteSlot.spriteListIndex);
+		M4Sprite *frame = spriteSet.getFrame(((spriteSlot.frameNumber & 0x7fff) - 1) & 0x7f);
+		
+		if (spriteSlot.scale == -1) {
+			width = frame->width();
+			height = frame->height();
+		} else {
+			width = frame->width() * spriteSlot.scale / 100;
+			height = frame->height() * spriteSlot.scale / 100;
+
+			dirtyArea.bounds.left -= width / 2;
+			dirtyArea.bounds.top += -(height - 1);
+		}
+	}
+
+	dirtyArea.setArea(width, height, MADS_SURFACE_WIDTH, MADS_SURFACE_HEIGHT);
+}
+
+void MadsDirtyAreas::setTextDisplay(int dirtyIdx, const MadsTextDisplayEntry &textDisplay) {
+	MadsDirtyArea &dirtyArea = _entries[dirtyIdx];
+	dirtyArea.bounds.left = textDisplay.bounds.left;
+	dirtyArea.bounds.top = textDisplay.bounds.top;
+
+	dirtyArea.setArea(textDisplay.bounds.width(), textDisplay.bounds.height(), MADS_SURFACE_WIDTH, MADS_SURFACE_HEIGHT);
+}
+
+/**
+ * Merge together any designated dirty areas that overlap
+ * @param startIndex	1-based starting dirty area starting index
+ * @param count			Number of entries to process
+ */
+void MadsDirtyAreas::merge(int startIndex, int count) {
+	if (startIndex >= count)
+		return;
+
+	for (int outerCtr = startIndex - 1, idx = 0; idx < count; ++outerCtr, ++idx) {
+		if (!_entries[outerCtr].active)
+			continue;
+
+		for (int innerCtr = outerCtr + 1; innerCtr < count; ++innerCtr) {
+			if (!_entries[innerCtr].active || !intersects(outerCtr, innerCtr))
+				continue;
+
+			if (_entries[outerCtr].textActive && _entries[innerCtr].textActive)
+				mergeAreas(outerCtr, innerCtr);
+		}
+	}
+}
+
+/**
+ * Returns true if two dirty areas intersect
+ */
+bool MadsDirtyAreas::intersects(int idx1, int idx2) {
+	return _entries[idx1].bounds2.intersects(_entries[idx2].bounds2);
+}
+
+void MadsDirtyAreas::mergeAreas(int idx1, int idx2) {
+	MadsDirtyArea &da1 = _entries[idx1];
+	MadsDirtyArea &da2 = _entries[idx2];
+
+	da1.bounds.extend(da2.bounds);
+
+	da1.bounds2.left = da1.bounds.width() / 2;
+	da1.bounds2.right = da1.bounds.left + (da1.bounds.width() + 1) / 2 - 1;
+	da1.bounds2.top = da1.bounds.height() / 2;
+	da1.bounds2.bottom = da1.bounds.top + (da1.bounds.height() + 1) / 2 - 1;
+
+	da2.active = false;
+	da1.textActive = true;
+}
+
+void MadsDirtyAreas::copy(M4Surface *dest, M4Surface *src) {
+	for (uint i = 0; i < _entries.size(); ++i) {
+		if (_entries[i].active && _entries[i].bounds.isValidRect())
+			src->copyTo(dest, _entries[i].bounds, _entries[i].bounds.left, _entries[i].bounds.top);
+	}
+}
+
+/*--------------------------------------------------------------------------*/
+
 MadsSequenceList::MadsSequenceList(MadsView &owner): _owner(owner) {
 	for (int i = 0; i < TIMER_LIST_SIZE; ++i) {
 		MadsSequenceEntry rec;
@@ -565,8 +788,7 @@
 	MadsSequenceEntry &timerEntry = _entries[timerIndex];
 	SpriteAsset &sprite = _owner._spriteSlots.getSprite(timerEntry.spriteListIndex);
 
-	// TODO: Figure out logic for spriteId value based on SPRITE_SLOT.field_0
-	spriteSlot.spriteId = (0 /*field 0*/ == 1) ? -4 : 1;
+	spriteSlot.spriteType = sprite.getAssetType() == 1 ? BACKGROUND_SPRITE : FOREGROUND_SPRITE;
 	spriteSlot.timerIndex = timerIndex;
 	spriteSlot.spriteListIndex = timerEntry.spriteListIndex;
 	spriteSlot.frameNumber = ((timerEntry.field_2 == 1) ? 0x8000 : 0) | timerEntry.frameIndex;
@@ -727,10 +949,44 @@
 	}
 }
 
+void MadsSequenceList::setAnimRange(int timerIndex, int startVal, int endVal) {
+	MadsSequenceEntry &seqEntry = _entries[timerIndex];
+	SpriteAsset &spriteSet = _owner._spriteSlots.getSprite(seqEntry.spriteListIndex);
+	int numSprites = spriteSet.getCount();
+	int tempStart = startVal, tempEnd = endVal;
+
+	switch (startVal) {
+	case -2:
+		tempStart = numSprites;
+		break;
+	case -1:
+		tempStart = 1;
+		break;
+	}
+	
+	switch (endVal) {
+	case -2:
+	case 0:
+		tempEnd = numSprites;
+		break;
+	case -1:
+		tempEnd = 1;
+		break;
+	default:
+		tempEnd = numSprites;
+		break;
+	}
+
+	seqEntry.frameStart = tempStart;
+	seqEntry.numSprites = tempEnd;
+
+	seqEntry.frameIndex = (seqEntry.frameInc < 0) ? tempStart : tempEnd;
+}
+
 //--------------------------------------------------------------------------
 
 MadsView::MadsView(View *view): _view(view), _dynamicHotspots(*this), _sequenceList(*this),
-		_kernelMessages(*this) {
+		_kernelMessages(*this), _spriteSlots(*this), _dirtyAreas(*this), _textDisplay(*this) {
 	_textSpacing = -1;
 	_ticksAmount = 3;
 	_newTimeout = 0;
@@ -738,12 +994,32 @@
 	_abortTimers2 = 0;
 	_abortTimersMode = ABORTMODE_0;
 	_abortTimersMode2 = ABORTMODE_0;
+	
+	_depthSurface = NULL;
+	_bgSurface = NULL;
 }
 
 void MadsView::refresh() {
 	// Draw any sprites
-	_spriteSlots.draw(_view);
+	_spriteSlots.drawBackground();
 
+	// Process dirty areas
+	_textDisplay.setDirtyAreas();
+
+	// Merge any identified dirty areas
+	_dirtyAreas.merge(1, DIRTY_AREAS_SIZE);
+	
+	// Copy dirty areas to the main display surface 
+	_dirtyAreas.copy(_view, _bgSurface);
+
+	// Handle dirty areas for foreground objects
+	_spriteSlots.setDirtyAreas();
+	_textDisplay.setDirtyAreas2();
+	_dirtyAreas.merge(1, DIRTY_AREAS_SIZE);
+
+	// Draw foreground sprites
+	_spriteSlots.drawForeground(_view);
+
 	// Draw text elements onto the view
 	_textDisplay.draw(_view);
 

Modified: scummvm/trunk/engines/m4/mads_views.h
===================================================================
--- scummvm/trunk/engines/m4/mads_views.h	2010-05-23 05:51:32 UTC (rev 49149)
+++ scummvm/trunk/engines/m4/mads_views.h	2010-05-23 07:20:40 UTC (rev 49150)
@@ -34,6 +34,7 @@
 
 namespace M4 {
 
+#define MADS_SURFACE_WIDTH 320
 #define MADS_SURFACE_HEIGHT 156
 #define MADS_SCREEN_HEIGHT 200
 #define MADS_Y_OFFSET ((MADS_SCREEN_HEIGHT - MADS_SURFACE_HEIGHT) / 2)
@@ -44,7 +45,7 @@
 
 class MadsSpriteSlot {
 public:
-	int spriteId;
+	int spriteType;
 	int timerIndex;
 	int spriteListIndex;
 	int frameNumber;
@@ -58,16 +59,21 @@
 
 #define SPRITE_SLOTS_SIZE 50
 
+enum SpriteIdSpecial {
+	BACKGROUND_SPRITE = -4, FULL_SCREEN_REFRESH = -2, FOREGROUND_SPRITE = 1
+};
+
 typedef Common::Array<Common::SharedPtr<SpriteAsset> > SpriteList;
 
 class MadsSpriteSlots {
 private:
+	MadsView &_owner;
 	Common::Array<MadsSpriteSlot> _entries;
 	SpriteList _sprites;
 public:
 	int startIndex;
 
-	MadsSpriteSlots();
+	MadsSpriteSlots(MadsView &owner);
 
 	MadsSpriteSlot &operator[](int idx) {
 		assert(idx < SPRITE_SLOTS_SIZE);
@@ -80,13 +86,12 @@
 
 	int getIndex();
 	int addSprites(const char *resName);
-	void clear() {
-		startIndex = 0;
-		_sprites.clear();
-	}
+	void clear();
 	void deleteTimer(int timerIndex);
 
-	void draw(View *view);
+	void drawBackground();
+	void drawForeground(View *view);
+	void setDirtyAreas();
 	void cleanUp();
 };
 
@@ -108,9 +113,10 @@
 
 class MadsTextDisplay {
 private:
+	MadsView &_owner;
 	Common::Array<MadsTextDisplayEntry> _entries;
 public:
-	MadsTextDisplay();
+	MadsTextDisplay(MadsView &owner);
 
 	MadsTextDisplayEntry &operator[](int idx) {
 		assert(idx < TEXT_DISPLAY_SIZE);
@@ -125,6 +131,8 @@
 	int add(int xp, int yp, uint fontColour, int charSpacing, const char *msg, Font *font);
 	void clear();
 	void draw(View *view);
+	void setDirtyAreas();
+	void setDirtyAreas2();
 	void cleanUp();
 };
 
@@ -204,7 +212,7 @@
 class DynamicHotspot {
 public:
 	bool active;
-	int timerIndex;
+	int seqIndex;
 	Common::Rect bounds;
 	Common::Point pos;
 	int facing;
@@ -229,13 +237,47 @@
 	MadsDynamicHotspots(MadsView &owner);
 
 	DynamicHotspot &operator[](uint idx) { return _entries[idx]; }
-	int add(int descId, int field14, int timerIndex, const Common::Rect &bounds);
+	int add(int descId, int field14, int seqIndex, const Common::Rect &bounds);
 	int setPosition(int index, int xp, int yp, int facing);
 	int set17(int index, int v);
 	void remove(int index);
 	void reset();
 };
 
+class MadsDirtyArea {
+public:
+	Common::Rect bounds;
+	Common::Rect bounds2;
+	bool textActive;
+	bool active;
+
+	MadsDirtyArea() { active = false; }
+	void setArea(int width, int height, int maxWidth, int maxHeight);
+};
+
+#define DIRTY_AREAS_SIZE 90
+#define DIRTY_AREAS_TEXT_DISPLAY_IDX 50
+
+class MadsDirtyAreas {
+private:
+	MadsView &_owner;
+	Common::Array<MadsDirtyArea> _entries;
+public:
+	MadsDirtyAreas(MadsView &owner);
+
+	MadsDirtyArea &operator[](uint idx) {
+		assert(idx < _entries.size());
+		return _entries[idx];
+	}
+
+	void setSpriteSlot(int dirtyIdx, const MadsSpriteSlot &spriteSlot);
+	void setTextDisplay(int dirtyIdx, const MadsTextDisplayEntry &textDisplay);
+	void merge(int startIndex, int count);
+	bool intersects(int idx1, int idx2);
+	void mergeAreas(int idx1, int idx2);
+	void copy(M4Surface *dest, M4Surface *src);
+};
+
 enum SpriteAnimType {ANIMTYPE_CYCLED = 1, ANIMTYPE_REVERSIBLE = 2};
 
 enum SequenceSubEntryMode {SM_0 = 0, SM_1 = 1, SM_FRAME_INDEX = 2};
@@ -303,6 +345,7 @@
 	bool loadSprites(int timerIndex);
 	void tick();
 	void delay(uint32 v1, uint32 v2);
+	void setAnimRange(int timerIndex, int startVal, int endVal);
 };
 
 class MadsView {
@@ -315,6 +358,7 @@
 	ScreenObjects _screenObjects;
 	MadsDynamicHotspots _dynamicHotspots;
 	MadsSequenceList _sequenceList;
+	MadsDirtyAreas _dirtyAreas;
 
 	int _textSpacing;
 	int _ticksAmount;
@@ -323,6 +367,10 @@
 	int8 _abortTimers2;
 	AbortTimerMode _abortTimersMode;
 	AbortTimerMode _abortTimersMode2;
+	Common::Point _posAdjust;
+
+	M4Surface *_depthSurface;
+	M4Surface *_bgSurface;
 public:
 	MadsView(View *view);
 

Modified: scummvm/trunk/engines/m4/sprite.h
===================================================================
--- scummvm/trunk/engines/m4/sprite.h	2010-05-23 05:51:32 UTC (rev 49149)
+++ scummvm/trunk/engines/m4/sprite.h	2010-05-23 07:20:40 UTC (rev 49150)
@@ -115,18 +115,6 @@
 	void loadDeltaRle(Common::SeekableReadStream* rleData, int destX, int destY);
 	void loadMadsSprite(Common::SeekableReadStream* source);
 
-	void draw1(M4Surface *destSurface, int scale, int depth, int xp, int yp) {
-		// TODO: Properly implement drawing
-		copyTo(destSurface, xp, yp, 0);
-	}
-	void draw2(M4Surface *destSurface, int depth, int xp, int yp) {
-		// TODO: Properly implement drawing
-		copyTo(destSurface, xp, yp, 0);
-	}
-	void draw3(M4Surface *destSurface, int xp, int yp) {
-		// TODO: Properly implement drawing
-		copyTo(destSurface, xp, yp, 0);
-	}
 	byte getTransparentColor() const;
 protected:
 };


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the Scummvm-git-logs mailing list