diff options
| -rw-r--r-- | queen/graphics.cpp | 419 | ||||
| -rw-r--r-- | queen/graphics.h | 105 | 
2 files changed, 503 insertions, 21 deletions
| diff --git a/queen/graphics.cpp b/queen/graphics.cpp index cdf8b48b70..6cf9a82371 100644 --- a/queen/graphics.cpp +++ b/queen/graphics.cpp @@ -21,11 +21,14 @@  #include "queen/graphics.h" +  QueenGraphics::QueenGraphics(QueenResource *resource)  	:_resource(resource) {  	memset(_frames, 0, sizeof(_frames)); -	memset(_banks, 0, sizeof(_banks));	 +	memset(_banks, 0, sizeof(_banks)); +	memset(_sortedBobs, 0, sizeof(_sortedBobs)); +  } @@ -56,25 +59,27 @@ void QueenGraphics::bankLoad(const char *bankname, uint32 bankslot) {  	debug(5, "Loaded bank '%s' in slot %d, %d entries", bankname, bankslot, entries);   } +  void QueenGraphics::bankUnpack(uint32 srcframe, uint32 dstframe, uint32 bankslot) {  	uint8 *p = _banks[bankslot].data + _banks[bankslot].indexes[srcframe]; -	ObjectFrame *pof = &_frames[dstframe]; -	delete[] pof->data; +	BobFrame *pbf = &_frames[dstframe]; +	delete[] pbf->data; -	pof->width    = READ_LE_UINT16(p + 0); -	pof->height   = READ_LE_UINT16(p + 2); -	pof->xhotspot = READ_LE_UINT16(p + 4); -	pof->yhotspot = READ_LE_UINT16(p + 6); +	pbf->width    = READ_LE_UINT16(p + 0); +	pbf->height   = READ_LE_UINT16(p + 2); +	pbf->xhotspot = READ_LE_UINT16(p + 4); +	pbf->yhotspot = READ_LE_UINT16(p + 6); -	uint32 size = pof->width * pof->height; -	pof->data = new uint8[ size ]; -	memcpy(pof->data, p, size); +	uint32 size = pbf->width * pbf->height; +	pbf->data = new uint8[ size ]; +	memcpy(pbf->data, p, size);  	debug(5, "Unpacked frame %d from bank slot %d to frame slot %d", srcframe, bankslot, dstframe);  } +  void QueenGraphics::bankOverpack(uint32 srcframe, uint32 dstframe, uint32 bankslot) {  	uint8 *p = _banks[bankslot].data + _banks[bankslot].indexes[srcframe]; @@ -93,6 +98,7 @@ void QueenGraphics::bankOverpack(uint32 srcframe, uint32 dstframe, uint32 banksl  	debug(5, "Overpacked frame %d from bank slot %d to frame slot %d", srcframe, bankslot, dstframe);  } +  void QueenGraphics::bankErase(uint32 bankslot) {  	delete[] _banks[bankslot].data; @@ -101,3 +107,396 @@ void QueenGraphics::bankErase(uint32 bankslot) {  	debug(5, "Erased bank in slot %d", bankslot);  } + +void QueenGraphics::bobAnimString(uint32 bobnum, uint8* animBuf) { + +	BobSlot *pbs = &_bobs[bobnum]; +	pbs->active = true; +	pbs->animating = true; +	pbs->anim.string.buffer = animBuf; +	pbs->anim.string.curPos = animBuf; +	pbs->frameNum = READ_LE_UINT16(animBuf); +	pbs->anim.speed = READ_LE_UINT16(animBuf + 2) / 4; +} + + +void QueenGraphics::bobAnimNormal(uint32 bobnum, uint16 firstFrame, uint16 lastFrame, uint16 speed, bool rebound, bool xflip) { + +	BobSlot *pbs = &_bobs[bobnum]; +	pbs->active = true; +	pbs->animating = true; +	pbs->frameNum = firstFrame; +	pbs->anim.speed = speed; +	pbs->anim.speedBak = speed; +	pbs->anim.string.buffer = NULL; +	pbs->anim.normal.firstFrame = firstFrame; +	pbs->anim.normal.lastFrame = lastFrame; +	pbs->anim.normal.rebound = rebound; +	pbs->frameDir = 1; +	pbs->xflip = xflip; +} + + +void QueenGraphics::bobMove(uint32 bobnum, uint16 endx, uint16 endy, int16 speed) { + +	BobSlot *pbs = &_bobs[bobnum]; + +	pbs->active = true; +	pbs->moving = true; + +	pbs->endx = endx; +	pbs->endy = endy; + +	// FIXME: can speed be negative or =0 ? the original sources does the check +	pbs->speed = (speed < 1) ? 1 : speed; + +	int16 dx = endx - pbs->x; +	if (dx < 0) { +		pbs->dx   = -dx; +		pbs->xdir = -1; +	} +	else { +		pbs->dx   = dx; +		pbs->xdir = 1; +	} +	int16 dy = endy - pbs->y; +	if (dy < 0) { +		pbs->dy   = -dy; +		pbs->ydir = -1; +	} +	else { +		pbs->dy   = dy; +		pbs->ydir = 1; +	} + +	if (pbs->dx > pbs->dy) { +		pbs->total = pbs->dy / 2; +		pbs->xmajor = true; +	} +	else { +		pbs->total = pbs->dx / 2; +		pbs->xmajor = false; +	} + +	// move one step along line to avoid glitching +	pbs->moveOneStep(); +} + + +void BobSlot::moveOneStep() { + +	if(xmajor) { +		if(x == endx) { +			y = endy; +			moving = false; +		} +		else { +			x += xdir; +			total += dy; +			if(total > dx) { +				y += ydir; +				total -= dx; +			} +		} +	} +	else { +		if(y == endy) { +			x = endx; +			moving = false; +		} +		else { +			y += ydir; +			total += dx; +			if(total > dy) { +				x += xdir; +				total -= dy; +			} +		} +	} +} + + +void BobSlot::animOneStep() { + +	if (anim.string.buffer != NULL) { +		--anim.speed; +		if(anim.speed == 0) { +			anim.string.curPos += 4; +			uint16 nextFrame = READ_LE_UINT16(anim.string.curPos); +			if (nextFrame == 0) { +				anim.string.curPos = anim.string.buffer; +				frameNum = READ_LE_UINT16(anim.string.curPos); +			} +			else { +				frameNum = nextFrame; +			} +			anim.speed = READ_LE_UINT16(anim.string.curPos + 2) / 4; + +			// FIXME: handle that when QueenSound class is ready +			// play memory sfx and move on to next frame +			if(frameNum > 500) { +				frameNum -= 500; +				// _sound->sfxplay(NULLstr); +			} +		} +	} +	else { +		// normal looping animation +		--anim.speed; +		if(anim.speed == 0) { +			anim.speed = anim.speedBak; + +			uint16 nextFrame = frameNum + frameDir; +			if (nextFrame > anim.normal.lastFrame || nextFrame < anim.normal.firstFrame) { +				if (anim.normal.rebound) { +					frameDir *= -1; +				} +				else { +					frameNum = anim.normal.lastFrame - 1; +				} +				frameNum += frameDir; +			} +		} +	} +} +             + +void QueenGraphics::bobDraw(uint32 bobnum, uint16 x, uint16 y, uint16 scale, bool xflip, const Box& box) { + +	uint16 w, h; +	uint8 *src; + +	BobFrame *pbf = &_frames[bobnum]; +	if(scale >= 0 && scale < 100) { +		bobShrink(pbf, scale); +		src = _shrinkBuffer.data; +		w   = _shrinkBuffer.width; +		h   = _shrinkBuffer.height; +	} +	else { +		src = pbf->data; +		w   = pbf->width; +		h   = pbf->height; +	} + +	if(w != 0 && h != 0 && box.intersects(x, y, w, h)) { + +		uint16 x_skip = 0; +		uint16 y_skip = 0; +		uint16 w_new = w; +		uint16 h_new = h; + +		// compute bounding box intersection with frame +		if (x < box.x1) { +			x_skip = box.x1 - x; +			w_new -= x_skip; +			x = box.x1; +		} + +		if (y < box.y1) { +			y_skip = box.y1 - y; +			h_new -= y_skip; +			y = box.y1; +		} + +		if (x + w_new > box.x2 + 1) { +			w_new = box.x2 - x + 1; +		} + +		if (y + h_new > box.y2 + 1) { +			h_new = box.y2 - y + 1; +		} + +		uint16 j; +		for (j = 0; j < h_new; ++j) { +			memset(_ulines[y + j], 2, w_new / 16); +		} + +		src += w * y_skip; +		if (!xflip) { +			src += x_skip; +//			_display->blit(hidden, x, y, 320, src, w_new, h_new, w, xflip, true); +		} +		else { +			src += w - w_new - x_skip; +			x += w_new - 1; +//			_display->blit(hidden, x, y, 320, src, x_new, h_new, w, xflip, true); +		} +    } + +} + + +void QueenGraphics::bobDrawInventoryItem(uint32 bobnum, uint16 x, uint16 y) { +	if (bobnum == 0) { +		// clear panel area +		uint8 *p = _panel + y * 320 + x; +		for(uint32 j = 0; j < 32; ++j) { +			for(uint32 i = 0; i < 32; ++i) { +				*p++ = INK_BG_PANEL; +			} +			p += 320 - 32; +		} +	} +	else { +		BobFrame *pbf = &_frames[bobnum]; +//		_display->blit(panel, x, y, 320, pbf->data, pbf->width, pbf->height, false, false); +	} +} + + +void QueenGraphics::bobPaste(uint32 bobnum, uint16 x, uint16 y) { + +	BobFrame *pbf = &_frames[bobnum]; +//	_display->blit(backdrop, x, y, 640, pbf->data, pbf->width, pbf->height, pbf->width, false, true); +	frameErase(bobnum); +} + + +void QueenGraphics::bobShrink(const BobFrame* pbf, uint16 percentage) { + +	// computing new size, rounding to upper value +	uint16 new_w = (pbf->width  * percentage + 50) / 100; +	uint16 new_h = (pbf->height * percentage + 50) / 100; + +	if (new_w != 0 && new_h != 0) { + +		_shrinkBuffer.width  = new_w; +		_shrinkBuffer.height = new_h; + +		uint32 shrinker = (100 << 0x10) / percentage; +		uint16 x_scale = shrinker >> 0x10; +		uint16 y_scale = x_scale * pbf->width;    +		shrinker &= 0xFFFF; + +		uint8* src = pbf->data; +		uint8* dst = _shrinkBuffer.data; + +		for (uint32 y_count = 0; new_h != 0; --new_h) { + +			uint8 *p = src; +			for (uint32 x_count = 0; new_w != 0; --new_w) { +				*dst++ = *p; +				p += x_scale; +				x_count += shrinker; +				if (x_count > 0xFFFF) { +					++p; +					x_count &= 0xFFFF; +				} +			} +   	   +			src += y_scale; +			y_count += shrinker; +			if (y_count > 0xFFFF) { +				src += pbf->width; +				y_count &= 0xFFFF; +			} +		}  +	} +} + + +void QueenGraphics::bobClear(uint32 bobnum) { + +	BobSlot *pbs = &_bobs[bobnum]; + +	pbs->active = 0; +	pbs->xflip  = false; +	pbs->anim.string.buffer = NULL; +	pbs->moving = false; +	pbs->scale  = 100; +	pbs->box.x1 = 0; +	pbs->box.y1 = 0; +	pbs->box.y1 = 319; +	pbs->box.y2 = (bobnum == 16) ? 199 : 149; // FIXME: does bob number 16 really used ? +} + + +void QueenGraphics::bobSortAll() { + +	int32 _sorted = 0; + +	// animate/move the bobs +	for (int32 i = 0; i < ARRAYSIZE(_bobs); ++i) { + +		BobSlot *pbs = &_bobs[i]; +		if (pbs->active) { +			_sortedBobs[_sorted] = pbs; +			++_sorted; + +			if (pbs->animating) { +				pbs->animOneStep(); +			} +			if (pbs->moving) { +				for (uint32 j = 0; pbs->moving && j < pbs->speed; ++j) { +					pbs->moveOneStep(); +				} +			} +		} +	} + +	_sortedBobs[_sorted] = 0; + +	// bubble sort the bobs +	for (int32 index = 0; index < _sorted - 1; ++index) { +		int32 smallest = index; +		for (int32 compare = index + 1; compare <= _sorted - 1; ++compare) { +			if (_sortedBobs[compare]->y < _sortedBobs[compare]->y) { +				smallest = compare; +			} +		} +		if (index != smallest) { +			SWAP(_sortedBobs[index], _sortedBobs[smallest]); +		} +	} + +} + + +void QueenGraphics::bobDrawAll() { +	 +	for (BobSlot *pbs = _sortedBobs[0]; pbs; ++pbs) { +		if (pbs->active) { + +			BobFrame *pbf = &_frames[ pbs->frameNum ]; +			uint16 xh, yh, x, y; + +			xh = pbf->xhotspot; +			yh = pbf->yhotspot; + +			if (pbs->xflip) { +				xh = pbf->width - xh; +			} + +			// adjusts hot spots when object is scaled +			if (pbs->scale != 100) { +				xh = (xh * pbs->scale) / 100; +				yh = (yh * pbs->scale) / 100; +			} + +			// adjusts position to hot-spot and screen scroll +			x = pbs->x - xh; // - _display->scrollx; +			y = pbs->y - yh; + +			bobDraw(pbs->frameNum, x, y, pbs->scale, pbs->xflip, pbs->box); +		} +	} +} + + +void QueenGraphics::bobClearAll() { + +	for(int32 i = 0; i < ARRAYSIZE(_bobs); ++i) { +		bobClear(i); +	} +} + + +void QueenGraphics::frameErase(uint32 fslot) { + +	BobFrame *pbf = &_frames[fslot]; +	pbf->width  = 0; +	pbf->height = 0; +	delete[] pbf->data; + +} diff --git a/queen/graphics.h b/queen/graphics.h index 0cd8ea95fb..7091224878 100644 --- a/queen/graphics.h +++ b/queen/graphics.h @@ -28,12 +28,69 @@  #define MAX_BANK_SIZE      110  #define MAX_FRAMES_NUMBER  256  #define MAX_BANKS_NUMBER    18 +#define MAX_BOBS_NUMBER     64 -struct ObjectFrame { -  uint16 width, height; -  uint16 xhotspot, yhotspot; -  uint8 *data; +struct BobFrame { +	uint16 width, height; +	uint16 xhotspot, yhotspot; +	uint8 *data; +}; + +// FIXME: share that with logic.h (ObjectData) ? +struct Box { +	uint16 x1, y1, x2, y2; + +	bool intersects(uint16 x, uint16 y, uint16 w, uint16 h) const { +		return (x + w > x1) && (y + h > y1) && (x <= x2) && (y <= y2); +	} +}; + + +struct BobSlot { +	bool active;  +	uint16 x, y;     //! current position +	Box box;         //! bounding box +	bool xflip;  +	uint16 scale;    //! shrinking percentage +	uint16 frameNum; //! associated BobFrame +	uint8 frameDir;  //! 'direction' for the next frame (-1, 1) + +	//! animation stuff +	bool animating; +	struct { +		uint16 speed, speedBak; + +		//! string based animation +		struct { +			uint8* buffer; +			uint8* curPos; +		} string; + +		//! normal moving animation +		struct { +			bool rebound; +			uint16 firstFrame, lastFrame; +		} normal; + +	} anim; + +	bool moving; +	uint16 speed;      //! moving speed +	bool xmajor;       //! move along x axis instead of y +	int8 xdir, ydir;   //! moving direction +	uint16 endx, endy; //! destination point +	uint16 dx, dy; +	uint16 total; + +	void moveOneStep(); +	void animOneStep(); +}; + + +//! Inks indexes +enum { +	INK_BG_PANEL = 0xE2  }; @@ -42,11 +99,26 @@ public:  	QueenGraphics(QueenResource *resource); -	void bankLoad(const char *bankname, uint32 bankslot); -	void bankUnpack(uint32 srcframe, uint32 dstframe, uint32 bankslot); -	void bankOverpack(uint32 srcframe, uint32 dstframe, uint32 bankslot); -	void bankErase(uint32 bankslot); -	 +	void bankLoad(const char *bankname, uint32 bankslot); // loadbank() +	void bankUnpack(uint32 srcframe, uint32 dstframe, uint32 bankslot); // unpackbank() +	void bankOverpack(uint32 srcframe, uint32 dstframe, uint32 bankslot); // overpackbank() +	void bankErase(uint32 bankslot); // erase() + +	void bobAnimString(uint32 bobnum, uint8* animBuf); // stringanim() +	void bobAnimNormal(uint32 bobnum, uint16 firstFrame, uint16 lastFrame, uint16 speed, bool rebound, bool xflip); // makeanim() +	void bobMove(uint32 bobnum, uint16 endx, uint16 endy, int16 speed); // movebob() +	void bobDraw(uint32 bobnum, uint16 x, uint16 y, uint16 scale, bool xflip, const Box& box); // bob() +	void bobDrawInventoryItem(uint32 bobnum, uint16 x, uint16 y); // invbob() +	void bobPaste(uint32 bobnum, uint16 x, uint16 y); // bobpaste() +	void bobShrink(const BobFrame* pbf, uint16 percentage); // shrinkbob() +	void bobClear(uint32 bobnum); // clearbob() +	void bobSortAll(); // sortbobs() +	void bobDrawAll(); // drawbobs() +	void bobClearAll(); // clearallbobs() + +	void frameErase(uint32 fslot); + +  private:  	struct PackedBank { @@ -54,8 +126,19 @@ private:  		uint8 *data;  	}; -	ObjectFrame _frames[MAX_FRAMES_NUMBER]; -	PackedBank _banks[MAX_BANKS_NUMBER]; +	struct ShrunkBobFrame { +		uint16 width; +		uint16 height; +		uint8 data[60000]; // FIXME: original buffer size, maybe it can be smaller +	}; + +	BobFrame _frames[MAX_FRAMES_NUMBER]; //! unbanked bob frames +	PackedBank _banks[MAX_BANKS_NUMBER]; //! banked bob frames +	BobSlot _bobs[MAX_BOBS_NUMBER]; +	BobSlot* _sortedBobs[MAX_BOBS_NUMBER + 1]; //! bobs displayed +	ShrunkBobFrame _shrinkBuffer; +	uint8 _ulines[201][20]; +	uint8 _panel[320 * 50]; // FIXME: rather in QueenDisplay ?  	QueenResource *_resource; | 
