diff options
| author | Max Horn | 2002-12-15 23:40:37 +0000 | 
|---|---|---|
| committer | Max Horn | 2002-12-15 23:40:37 +0000 | 
| commit | 20c501ea587ac03167fca87b6cbccf2b51f1c135 (patch) | |
| tree | 1224510a3193492f043a7e8b975034171aad3876 | |
| parent | cfc4bc586a732eb0c3c660e380d747c4f90eecd3 (diff) | |
| download | scummvm-rg350-20c501ea587ac03167fca87b6cbccf2b51f1c135.tar.gz scummvm-rg350-20c501ea587ac03167fca87b6cbccf2b51f1c135.tar.bz2 scummvm-rg350-20c501ea587ac03167fca87b6cbccf2b51f1c135.zip | |
cleanup; reordering stuff in gfx.cpp, trying to group code into logical groups (cursor, bomp, camera, palette, fades)
svn-id: r5985
| -rw-r--r-- | scumm/gfx.cpp | 1825 | ||||
| -rw-r--r-- | scumm/gfx.h | 7 | ||||
| -rw-r--r-- | scumm/scumm.h | 11 | 
3 files changed, 920 insertions, 923 deletions
| diff --git a/scumm/gfx.cpp b/scumm/gfx.cpp index 4ecb60ee86..4e648e270c 100644 --- a/scumm/gfx.cpp +++ b/scumm/gfx.cpp @@ -26,11 +26,84 @@  #include "resource.h"  #include "util.h" + +#ifdef _MSC_VER +#	pragma warning( disable : 4068 ) // turn off "unknown pragma" warning +#endif + +  enum {  	kScrolltime = 500,  // ms scrolling is supposed to take  	kPictureDelay = 20  }; +#define NUM_SHAKE_POSITIONS 8 +static const int8 shake_positions[NUM_SHAKE_POSITIONS] = { +	0, 1 * 2, 2 * 2, 1 * 2, 0 * 2, 2 * 2, 3 * 2, 1 * 2 +}; + +static const uint32 zplane_tags[] = { +	MKID('ZP00'), +	MKID('ZP01'), +	MKID('ZP02'), +	MKID('ZP03'), +	MKID('ZP04') +}; + +static const int8 screen_eff7_table1[4][16] = { +	{ 1,  1, -1,  1, -1,  1, -1, -1, +	  1, -1, -1, -1,  1,  1,  1, -1}, +	{ 0,  1,  2,  1,  2,  0,  2,  1, +	  2,  0,  2,  1,  0,  0,  0,  0}, +	{-2, -1,  0, -1, -2, -1, -2,  0, -2, -1, -2, 0, 0, 0, 0, 0}, +	{ 0, -1, -2, -1, -2,  0, -2, -1, -2, 0, -2, -1, 0, 0, 0, 0} +}; + +static const byte screen_eff7_table2[4][16] = { +	{ 0,  0, 39,  0,  39,  0, 39, 24, +	  0, 24, 39, 24,   0,  0,  0, 24}, +	{ 0,  0,  0,  0,   0,  0,  0,  0, +	  1,  0,  1,  0, 255,  0,  0,  0}, +	{39, 24, 39, 24,  39, 24, 39, 24, +	 38, 24, 38, 24, 255,  0,  0,  0}, +	{ 0, 24, 39, 24,  39,  0, 39, 24, +	 38,  0, 38, 24, 255,  0,  0,  0} +}; + +static const byte transition_num_of_iterations[4] = { +	13, 25, 25, 25 +}; + + +static const byte default_cursor_colors[4] = { +	15, 15, 7, 8 +}; + +static const uint16 default_cursor_images[4][16] = { +	/* cross-hair */ +	{ 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0000, 0x7e3f, +	  0x0000, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0000 }, +	/* hourglass */ +	{ 0x0000, 0x7ffe, 0x6006, 0x300c, 0x1818, 0x0c30, 0x0660, 0x03c0, +	  0x0660, 0x0c30, 0x1998, 0x33cc, 0x67e6, 0x7ffe, 0x0000, 0x0000 }, +	/* arrow */ +	{ 0x0000, 0x4000, 0x6000, 0x7000, 0x7800, 0x7c00, 0x7e00, 0x7f00, +	  0x7f80, 0x78c0, 0x7c00, 0x4600, 0x0600, 0x0300, 0x0300, 0x0180 }, +	/* hand */ +	{ 0x1e00, 0x1200, 0x1200, 0x1200, 0x1200, 0x13ff, 0x1249, 0x1249, +	  0xf249, 0x9001, 0x9001, 0x9001, 0x8001, 0x8001, 0x8001, 0xffff }, +}; + +static const byte default_cursor_hotspots[8] = { +	8, 7,   8, 7,   1, 1,   5, 0 +}; + + +static inline uint colorWeight(int red, int green, int blue) +{ +	return 3 * red * red + 6 * green * green + 2 * blue * blue; +} +  void Scumm::getGraphicsPerformance()  {  	int i; @@ -131,6 +204,83 @@ void Scumm::initVirtScreen(int slot, int number, int top, int width, int height,  	}  } +VirtScreen *Scumm::findVirtScreen(int y) +{ +	VirtScreen *vs = virtscr; +	int i; + +	for (i = 0; i < 3; i++, vs++) { +		if (y >= vs->topline && y < vs->topline + vs->height) { +			return _curVirtScreen = vs; +		} +	} +	return _curVirtScreen = NULL; +} + +void Scumm::updateDirtyRect(int virt, int left, int right, int top, int bottom, uint32 dirtybits) +{ +	VirtScreen *vs = &virtscr[virt]; +	int lp, rp; +	uint32 *sp; +	int num; + +	if (top > vs->height || left > vs->width || right < 0 || bottom < 0) +		return; + +	if (top < 0) +		top = 0; +	if (left < 0) +		left = 0; +	if (bottom > vs->height) +		bottom = vs->height; +	if (right > vs->width) +		right = vs->width; + +	if (virt == 0 && dirtybits) { +		rp = (right >> 3) + _screenStartStrip; +		lp = (left >> 3) + _screenStartStrip; +		if (lp < 0) +			lp = 0; +		if (_features & GF_AFTER_V7) { +			if (rp > 409) +				rp = 409; +		} else { +			if (rp >= 200) +				rp = 200; +		} +		if (lp <= rp) { +			num = rp - lp + 1; +			sp = &gfxUsageBits[lp]; +			do { +				*sp++ |= dirtybits; +			} while (--num); +		} +	} + +	setVirtscreenDirty(vs, left, top, right, bottom); +} + +void Scumm::setVirtscreenDirty(VirtScreen *vs, int left, int top, int right, int bottom) +{ +	int lp = left >> 3; +	int rp = right >> 3; + +	if ((lp >= gdi._numStrips) || (rp < 0)) +		return; +	if (lp < 0) +		lp = 0; +	if (rp >= gdi._numStrips) +		rp = gdi._numStrips - 1; + +	while (lp <= rp) { +		if (top < vs->tdirty[lp]) +			vs->tdirty[lp] = top; +		if (bottom > vs->bdirty[lp]) +			vs->bdirty[lp] = bottom; +		lp++; +	} +} +  void Scumm::setDirtyRange(int slot, int top, int bottom)  {  	int i; @@ -141,13 +291,6 @@ void Scumm::setDirtyRange(int slot, int top, int bottom)  	}  } -/* power of 2 */ -#define NUM_SHAKE_POSITIONS 8 - -static const int8 shake_positions[NUM_SHAKE_POSITIONS] = { -	0, 1 * 2, 2 * 2, 1 * 2, 0 * 2, 2 * 2, 3 * 2, 1 * 2 -}; -  void Scumm::drawDirtyScreenParts()  {  	int i; @@ -217,9 +360,9 @@ void Gdi::updateDirtyScreen(VirtScreen *vs)  					continue;  				}  				if (_vm->_features & GF_AFTER_V7) -					drawStripToScreen(vs, start, w, 0, vs->height); +					drawStripToScreen(vs, start * 8, w, 0, vs->height);  				else -					drawStripToScreen(vs, start, w, top, bottom); +					drawStripToScreen(vs, start * 8, w, top, bottom);  				w = 8;  			}  			start = i + 1; @@ -249,136 +392,59 @@ void Gdi::drawStripToScreen(VirtScreen *vs, int x, int w, int t, int b)  	assert(_vm->_screenTop >= 0);  	scrollY = _vm->_screenTop; -	ptr = vs->screenPtr + (t * _numStrips + x) * 8 + _readOffs + scrollY * _vm->_realWidth; -	_vm->_system->copy_rect(ptr, _vm->_realWidth, x * 8, vs->topline + t, w, height); +	ptr = vs->screenPtr + t * _numStrips * 8 + x + _readOffs + scrollY * _vm->_realWidth; +	_vm->_system->copy_rect(ptr, _vm->_realWidth, x, vs->topline + t, w, height);  } -void Scumm::blit(byte *dst, byte *src, int w, int h) -{ -	assert(h > 0); -	assert(src != NULL); -	assert(dst != NULL); - -	do { -		memcpy(dst, src, w); -		dst += _realWidth; -		src += _realWidth; -	} while (--h); -} - -void Scumm::setCursor(int cursor) -{ -	if (cursor >= 0 && cursor <= 3) -		_currentCursor = cursor; -	else -		warning("setCursor(%d)", cursor); -} - -void Scumm::setCameraAtEx(int at) +void Gdi::clearUpperMask()  { -	if (!(_features & GF_AFTER_V7)) { -		camera._mode = CM_NORMAL; -		camera._cur.x = at; -		setCameraAt(at, 0); -		camera._movingToActor = false; -	} +	memset(_vm->getResourceAddress(rtBuffer, 9), 0, _imgBufOffs[1] - _imgBufOffs[0]);  } -void Scumm::setCameraAt(int pos_x, int pos_y) +void Gdi::resetBackground(int top, int bottom, int strip)  { -	if (_features & GF_AFTER_V7) { -		ScummPoint old; - -		old = camera._cur; - -		camera._cur.x = pos_x; -		camera._cur.y = pos_y; - -		clampCameraPos(&camera._cur); - -		camera._dest = camera._cur; - -		assert(camera._cur.x >= (_realWidth / 2) && camera._cur.y >= (_realHeight / 2)); - -		if ((camera._cur.x != old.x || camera._cur.y != old.y) -				&& _vars[VAR_SCROLL_SCRIPT]) { -			_vars[VAR_CAMERA_POS_X] = camera._cur.x; -			_vars[VAR_CAMERA_POS_Y] = camera._cur.y; -			runScript(_vars[VAR_SCROLL_SCRIPT], 0, 0, 0); -		} -	} else { -		int t; +	VirtScreen *vs = &_vm->virtscr[0]; +	int offs; -		if (camera._mode != CM_FOLLOW_ACTOR || abs(pos_x - camera._cur.x) > (_realWidth / 2)) { -			camera._cur.x = pos_x; -		} -		camera._dest.x = pos_x; +	if (top < vs->tdirty[strip]) +		vs->tdirty[strip] = top; -		t = _vars[VAR_CAMERA_MIN_X]; -		if (camera._cur.x < t) -			camera._cur.x = t; +	if (bottom > vs->bdirty[strip]) +		vs->bdirty[strip] = bottom; -		t = _vars[VAR_CAMERA_MAX_X]; -		if (camera._cur.x > t) -			camera._cur.x = t; +	offs = (top * _numStrips + _vm->_screenStartStrip + strip); +	_mask_ptr = _vm->getResourceAddress(rtBuffer, 9) + offs; +	_bgbak_ptr = _vm->getResourceAddress(rtBuffer, 5) + (offs << 3); +	_backbuff_ptr = vs->screenPtr + (offs << 3); -		if (_vars[VAR_SCROLL_SCRIPT]) { -			_vars[VAR_CAMERA_POS_X] = camera._cur.x; -			runScript(_vars[VAR_SCROLL_SCRIPT], 0, 0, 0); +	_numLinesToProcess = bottom - top; +	if (_numLinesToProcess) { +		if ((_vm->_features & GF_AFTER_V6) || (_vm->_vars[_vm->VAR_CURRENT_LIGHTS] & LIGHTMODE_screen)) { +			if (_vm->hasCharsetMask(strip << 3, top, (strip + 1) << 3, bottom)) +				draw8ColWithMasking(_backbuff_ptr, _bgbak_ptr, _numLinesToProcess, _mask_ptr); +			else +				draw8Col(_backbuff_ptr, _bgbak_ptr, _numLinesToProcess); +		} else { +			clear8Col(_backbuff_ptr, _numLinesToProcess);  		} - -		if (camera._cur.x != camera._last.x && charset._hasMask) -			stopTalk();  	}  } -void Scumm::setCameraFollows(Actor *a) +void Scumm::blit(byte *dst, byte *src, int w, int h)  { -	if (_features & GF_AFTER_V7) { -		byte oldfollow = camera._follows; -		int ax, ay; - -		camera._follows = a->number; - -		if (!a->isInCurrentRoom()) { -			startScene(a->getRoom(), 0, 0); -		} - -		ax = abs(a->x - camera._cur.x); -		ay = abs(a->y - camera._cur.y); - -		if (ax > _vars[VAR_CAMERA_THRESHOLD_X] || ay > _vars[VAR_CAMERA_THRESHOLD_Y] || ax > (_realWidth / 2) || ay > (_realHeight / 2)) { -			setCameraAt(a->x, a->y); -		} - -		if (a->number != oldfollow) -			runHook(0); -	} else { -		int t, i; - -		camera._mode = CM_FOLLOW_ACTOR; -		camera._follows = a->number; - -		if (!a->isInCurrentRoom()) { -			startScene(a->getRoom(), 0, 0); -			camera._mode = CM_FOLLOW_ACTOR; -			camera._cur.x = a->x; -			setCameraAt(camera._cur.x, 0); -		} - -		t = (a->x >> 3); - -		if (t - _screenStartStrip < camera._leftTrigger || t - _screenStartStrip > camera._rightTrigger) -			setCameraAt(a->x, 0); +	assert(h > 0); +	assert(src != NULL); +	assert(dst != NULL); -		for (i = 1, a = getFirstActor(); ++a, i < NUM_ACTORS; i++) { -			if (a->isInCurrentRoom()) -				a->needRedraw = true; -		} -		runHook(0); -	} +	do { +		memcpy(dst, src, w); +		dst += _realWidth; +		src += _realWidth; +	} while (--h);  } +#pragma mark - +  void Scumm::initBGBuffers(int height)  {  	byte *ptr; @@ -427,183 +493,6 @@ void Scumm::initBGBuffers(int height)  	}  } -void Scumm::setPaletteFromPtr(byte *ptr) -{ -	int i; -	byte *dest, r, g, b; -	int numcolor; - -	if (_features & GF_SMALL_HEADER) { -		if (_features & GF_OLD256) -			numcolor = 256; -		else -			numcolor = READ_LE_UINT16(ptr + 6) / 3; -		ptr += 8; -	} else { -		numcolor = getResourceDataSize(ptr) / 3; -	} - -	checkRange(256, 0, numcolor, "Too many colors (%d) in Palette"); - -	dest = _currentPalette; - -	for (i = 0; i < numcolor; i++) { -		r = *ptr++; -		g = *ptr++; -		b = *ptr++; - -		// This comparison might look wierd, but it's what the disassembly (DOTT) says! -		// FIXME: Fingolfin still thinks it looks weird: the value 252 = 4*63 clearly comes from -		// the days 6/6/6 palettes were used, OK. But it breaks MonkeyVGA, so I had to add a -		// check for that. And somebody before me added a check for V7 games, turning this -		// off there, too... I wonder if it hurts other games, too? What exactly is broken -		// if we remove this patch? -		if ((_gameId == GID_MONKEY_VGA) || (_features & GF_AFTER_V7) || (i <= 15 || r < 252 || g < 252 || b < 252)) { -			*dest++ = r; -			*dest++ = g; -			*dest++ = b; -		} else { -			dest += 3; -		} -	} -	setDirtyColors(0, numcolor - 1); -} - -void Scumm::setPaletteFromRes() -{ -	byte *ptr; -	ptr = getResourceAddress(rtRoom, _roomResource) + _CLUT_offs; -	setPaletteFromPtr(ptr); -} - - -void Scumm::setDirtyColors(int min, int max) -{ -	if (_palDirtyMin > min) -		_palDirtyMin = min; -	if (_palDirtyMax < max) -		_palDirtyMax = max; -} - -void Scumm::initCycl(byte *ptr) -{ -	int j; -	ColorCycle *cycl; - -	memset(_colorCycle, 0, sizeof(_colorCycle)); - -	while ((j = *ptr++) != 0) { -		if (j < 1 || j > 16) { -			error("Invalid color cycle index %d", j); -		} -		cycl = &_colorCycle[j - 1]; - -		ptr += 2; -		cycl->counter = 0; -		cycl->delay = 16384 / READ_BE_UINT16_UNALIGNED(ptr); -		ptr += 2; -		cycl->flags = READ_BE_UINT16_UNALIGNED(ptr); -		ptr += 2; -		cycl->start = *ptr++; -		cycl->end = *ptr++; -	} -} - -void Scumm::stopCycle(int i) -{ -	ColorCycle *cycl; - -	checkRange(16, 0, i, "Stop Cycle %d Out Of Range"); -	if (i != 0) { -		_colorCycle[i - 1].delay = 0; -		return; -	} - -	for (i = 0, cycl = _colorCycle; i < 16; i++, cycl++) -		cycl->delay = 0; -} - -void Scumm::cyclePalette() -{ -	ColorCycle *cycl; -	int valueToAdd; -	int i, num; -	byte *start, *end; -	byte tmp[3]; - -	valueToAdd = _vars[VAR_TIMER]; -	if (valueToAdd < _vars[VAR_TIMER_NEXT]) -		valueToAdd = _vars[VAR_TIMER_NEXT]; - -	if (!_colorCycle)							// FIXME -		return; - -	for (i = 0, cycl = _colorCycle; i < 16; i++, cycl++) { -		if (cycl->delay && (cycl->counter += valueToAdd) >= cycl->delay) { -			do { -				cycl->counter -= cycl->delay; -			} while (cycl->delay <= cycl->counter); - -			setDirtyColors(cycl->start, cycl->end); -			moveMemInPalRes(cycl->start, cycl->end, cycl->flags & 2); -			start = &_currentPalette[cycl->start * 3]; -			end = &_currentPalette[cycl->end * 3]; - -			num = cycl->end - cycl->start; - -			if (!(cycl->flags & 2)) { -				memmove(tmp, end, 3); -				memmove(start + 3, start, num * 3); -				memmove(start, tmp, 3); -			} else { -				memmove(tmp, start, 3); -				memmove(start, start + 3, num * 3); -				memmove(end, tmp, 3); -			} -		} -	} -} - -// Perform color cycling on the palManipulate data, too, otherwise -// color cycling will be disturbed by the palette fade. -void Scumm::moveMemInPalRes(int start, int end, byte direction) -{ -	byte *startptr, *endptr; -	byte *startptr2, *endptr2; -	int num; -	byte tmp[6]; - -	if (!_palManipCounter) -		return; - -	startptr = _palManipPalette + start * 3; -	endptr = _palManipPalette + end * 3; -	startptr2 = _palManipIntermediatePal + start * 6; -	endptr2 = _palManipIntermediatePal + end * 6; -	num = end - start; - -	if (!endptr) { -		warning("moveMemInPalRes(%d,%d): Bad end pointer\n", start, end); -		return; -	} - -	if (!direction) { -		memmove(tmp, endptr, 3); -		memmove(startptr + 3, startptr, num * 3); -		memmove(startptr, tmp, 3); -		memmove(tmp, endptr2, 6); -		memmove(startptr2 + 6, startptr2, num * 6); -		memmove(startptr2, tmp, 6); -	} else { -		memmove(tmp, startptr, 3); -		memmove(startptr, startptr + 3, num * 3); -		memmove(endptr, tmp, 3); -		memmove(tmp, startptr2, 6); -		memmove(startptr2, startptr2 + 6, num * 6); -		memmove(endptr2, tmp, 6); -	} -} -  void Scumm::drawFlashlight()  {  	int i, j, offset, x, y; @@ -643,8 +532,8 @@ void Scumm::drawFlashlight()  	// Clip the flashlight at the borders  	if (_flashlight.x < 0)  		_flashlight.x = 0; -	else if (_flashlight.x + _flashlight.w > gdi._numStrips*8) -		_flashlight.x = gdi._numStrips*8 - _flashlight.w; +	else if (_flashlight.x + _flashlight.w > gdi._numStrips * 8) +		_flashlight.x = gdi._numStrips * 8 - _flashlight.w;  	if (_flashlight.y < 0)  		_flashlight.y = 0;  	else if (_flashlight.y + _flashlight.h> virtscr[0].height) @@ -685,84 +574,6 @@ void Scumm::drawFlashlight()  	_flashlightIsDrawn = true;  } -void Scumm::fadeIn(int effect) -{ -	switch (effect) { -	case 1: -	case 2: -	case 3: -	case 4: -		transitionEffect(effect - 1); -		break; -	case 128: -		unkScreenEffect6(); -		break; -	case 130: -	case 131: -	case 132: -	case 133: -		scrollEffect(133 - effect); -		break; -	case 134: -		dissolveEffect(1, 1); -		break; -	case 135: -		unkScreenEffect5(1); -		break; -	case 129: -		break; -	default: -		warning("Unknown screen effect, %d", effect); -	} -	_screenEffectFlag = true; -} - -void Scumm::fadeOut(int effect) -{ -	VirtScreen *vs; - -	setDirtyRange(0, 0, 0); -	if (!(_features & GF_AFTER_V7)) -		camera._last.x = camera._cur.x; - -	if (!_screenEffectFlag) -		return; -	_screenEffectFlag = false; - -	if (effect == 0) -		return; - -	// Fill screen 0 with black -	vs = &virtscr[0]; -	memset(vs->screenPtr + vs->xstart, 0, vs->size); - -	// Fade to black with the specified effect, if any. -	switch (effect) { -	case 1: -	case 2: -	case 3: -	case 4: -		transitionEffect(effect - 1); -		break; -	case 128: -		unkScreenEffect6(); -		break; -	case 129: -		// Just blit screen 0 to the display (i.e. display will be black) -		setDirtyRange(0, 0, vs->height); -		updateDirtyScreen(0); -		break; -	case 134: -		dissolveEffect(1, 1); -		break; -	case 135: -		unkScreenEffect5(1); -		break; -	default: -		warning("fadeOut: default case %d", effect); -	} -} -  void Scumm::redrawBGAreas()  {  	int i; @@ -814,13 +625,142 @@ void Scumm::redrawBGAreas()  	_BgNeedsRedraw = false;  } -static const uint32 zplane_tags[] = { -	MKID('ZP00'), -	MKID('ZP01'), -	MKID('ZP02'), -	MKID('ZP03'), -	MKID('ZP04') -}; +void Scumm::redrawBGStrip(int start, int num) +{ +	int s = _screenStartStrip + start; + +	assert(s >= 0 && (size_t) s < sizeof(gfxUsageBits) / sizeof(gfxUsageBits[0])); + +	_curVirtScreen = &virtscr[0]; + +	for (int i = 0; i < num; i++) +		gfxUsageBits[s + i] |= 0x80000000; + +	/*if (_curVirtScreen->height < _scrHeight) {   +	   warning("Screen Y size %d < Room height %d", +	   _curVirtScreen->height, +	   _scrHeight); +	   } */ + +	gdi.drawBitmap(getResourceAddress(rtRoom, _roomResource) + _IM00_offs, +								 _curVirtScreen, s, 0, _curVirtScreen->height, s, num, 0); +} + +void Scumm::restoreCharsetBg() +{ +	if (gdi._mask_left != -1) { +		restoreBG(gdi._mask_left, gdi._mask_top, gdi._mask_right, gdi._mask_bottom); +		charset._hasMask = false; +		gdi._mask_left = -1; +		charset._strLeft = -1; +		charset._left = -1; +	} + +	charset._nextLeft = _string[0].xpos; +	charset._nextTop = _string[0].ypos; +} + +void Scumm::restoreBG(int left, int top, int right, int bottom, byte backColor) +{ +	VirtScreen *vs; +	int topline, height, width; +	byte *backbuff, *bgbak; + +	if (left == right || top == bottom) +		return; +	if (top < 0) +		top = 0; + +	if ((vs = findVirtScreen(top)) == NULL) +		return; + +	topline = vs->topline; +	height = topline + vs->height; + +//	right++;		// FIXME - why did we increment here?!? it caused bug  +	if (left < 0) +		left = 0; +	if (right < 0) +		right = 0; +	if (left > _realWidth) +		return; +	if (right > _realWidth) +		right = _realWidth; +	if (bottom >= height) +		bottom = height; + +	updateDirtyRect(vs->number, left, right, top - topline, bottom - topline, 0x40000000); + +	int offset = (top - topline) * _realWidth + vs->xstart + left; +	backbuff = vs->screenPtr + offset; +	bgbak = getResourceAddress(rtBuffer, vs->number + 5) + offset; + +	height = bottom - top; +	width = right - left; + +	if (vs->alloctwobuffers && _currentRoom != 0 /*&& _vars[VAR_V5_DRAWFLAGS]&2 */ ) { +		blit(backbuff, bgbak, width, height); +		if (vs->number == 0 && charset._hasMask && height) { +			byte *mask; +			int mask_width = (width >> 3); + +			if (width & 0x07) +				mask_width++; + +			mask = getResourceAddress(rtBuffer, 9) + top * gdi._numStrips + (left >> 3) + _screenStartStrip; +			if (vs->number == 0) +				mask += vs->topline * gdi._numStrips; + +			do { +				memset(mask, 0, mask_width); +				mask += gdi._numStrips; +			} while (--height); +		} +	} else { +		while (height--) { +			memset(backbuff, backColor, width); +			backbuff += _realWidth; +		} +	} +} + +int Scumm::hasCharsetMask(int x, int y, int x2, int y2) +{ +	if (!charset._hasMask || y > gdi._mask_bottom || x > gdi._mask_right || +			y2 < gdi._mask_top || x2 < gdi._mask_left) +		return 0; +	return 1; +} + +byte Scumm::isMaskActiveAt(int l, int t, int r, int b, byte *mem) +{ +	int w, h, i; + +	l >>= 3; +	if (l < 0) +		l = 0; +	if (t < 0) +		t = 0; + +	r >>= 3; +	if (r > gdi._numStrips - 1) +		r = gdi._numStrips - 1; + +	mem += l + t * gdi._numStrips; + +	w = r - l; +	h = b - t + 1; + +	do { +		for (i = 0; i <= w; i++) +			if (mem[i]) { +				return true; +			} +		mem += gdi._numStrips; +	} while (--h); + +	return false; +}  void Gdi::drawBitmap(byte *ptr, VirtScreen *vs, int x, int y, int h,  										 int stripnr, int numstrip, byte flag) @@ -1132,14 +1072,6 @@ void Gdi::decompressBitmap()  	}  } -int Scumm::hasCharsetMask(int x, int y, int x2, int y2) -{ -	if (!charset._hasMask || y > gdi._mask_bottom || x > gdi._mask_right || -			y2 < gdi._mask_top || x2 < gdi._mask_left) -		return 0; -	return 1; -} -  void Gdi::draw8ColWithMasking(byte *dst, byte *src, int height, byte *mask)  {  	byte maskbits; @@ -1213,34 +1145,33 @@ void Gdi::clear8ColWithMasking(byte *dst, int height, byte *mask)  	} while (--height);  } -void Gdi::clear8Col(byte *dst, int height) + +void Gdi::draw8Col(byte *dst, byte *src, int height)  {  	do {  #if defined(SCUMM_NEED_ALIGNMENT) -		memset(dst, 0, 8); +		memcpy(dst, src, 8);  #else -		((uint32 *)dst)[0] = 0; -		((uint32 *)dst)[1] = 0; +		((uint32 *)dst)[0] = ((uint32 *)src)[0]; +		((uint32 *)dst)[1] = ((uint32 *)src)[1];  #endif  		dst += _vm->_realWidth; +		src += _vm->_realWidth;  	} while (--height);  } - -void Gdi::draw8Col(byte *dst, byte *src, int height) +void Gdi::clear8Col(byte *dst, int height)  {  	do {  #if defined(SCUMM_NEED_ALIGNMENT) -		memcpy(dst, src, 8); +		memset(dst, 0, 8);  #else -		((uint32 *)dst)[0] = ((uint32 *)src)[0]; -		((uint32 *)dst)[1] = ((uint32 *)src)[1]; +		((uint32 *)dst)[0] = 0; +		((uint32 *)dst)[1] = 0;  #endif  		dst += _vm->_realWidth; -		src += _vm->_realWidth;  	} while (--height);  } -  void Gdi::decompressMaskImg(byte *dst, byte *src, int height)  {  	byte b, c; @@ -1297,27 +1228,6 @@ void Gdi::decompressMaskImgOr(byte *dst, byte *src, int height)  	}  } -void Scumm::redrawBGStrip(int start, int num) -{ -	int s = _screenStartStrip + start; - -	assert(s >= 0 && (size_t) s < sizeof(gfxUsageBits) / sizeof(gfxUsageBits[0])); - -	_curVirtScreen = &virtscr[0]; - -	for (int i = 0; i < num; i++) -		gfxUsageBits[s + i] |= 0x80000000; - -	/*if (_curVirtScreen->height < _scrHeight) {   -	   warning("Screen Y size %d < Room height %d", -	   _curVirtScreen->height, -	   _scrHeight); -	   } */ - -	gdi.drawBitmap(getResourceAddress(rtRoom, _roomResource) + _IM00_offs, -								 _curVirtScreen, s, 0, _curVirtScreen->height, s, num, 0); -} -  #define READ_BIT (cl--,bit = bits&1, bits>>=1,bit)  #define FILL_BITS if (cl <= 8) { bits |= (*src++ << cl); cl += 8;} @@ -1753,218 +1663,451 @@ void Gdi::unkDecode11()  	} while (--_currentX);  } -  #undef NEXT_ROW  #undef READ_256BIT  #undef READ_BIT  #undef FILL_BITS -void Scumm::restoreCharsetBg() + +#pragma mark - +#pragma mark ### Camera ### +#pragma mark - + +void Scumm::setCameraAtEx(int at)  { -	if (gdi._mask_left != -1) { -		restoreBG(gdi._mask_left, gdi._mask_top, gdi._mask_right, gdi._mask_bottom); -		charset._hasMask = false; -		gdi._mask_left = -1; -		charset._strLeft = -1; -		charset._left = -1; +	if (!(_features & GF_AFTER_V7)) { +		camera._mode = CM_NORMAL; +		camera._cur.x = at; +		setCameraAt(at, 0); +		camera._movingToActor = false;  	} - -	charset._nextLeft = _string[0].xpos; -	charset._nextTop = _string[0].ypos;  } -void Scumm::restoreBG(int left, int top, int right, int bottom, byte backColor) +void Scumm::setCameraAt(int pos_x, int pos_y)  { -	VirtScreen *vs; -	int topline, height, width; -	byte *backbuff, *bgbak; +	if (_features & GF_AFTER_V7) { +		ScummPoint old; -	if (left == right || top == bottom) -		return; -	if (top < 0) -		top = 0; +		old = camera._cur; -	if ((vs = findVirtScreen(top)) == NULL) -		return; +		camera._cur.x = pos_x; +		camera._cur.y = pos_y; -	topline = vs->topline; -	height = topline + vs->height; +		clampCameraPos(&camera._cur); -//	right++;		// FIXME - why did we increment here?!? it caused bug  -	if (left < 0) -		left = 0; -	if (right < 0) -		right = 0; -	if (left > _realWidth) -		return; -	if (right > _realWidth) -		right = _realWidth; -	if (bottom >= height) -		bottom = height; +		camera._dest = camera._cur; -	updateDirtyRect(vs->number, left, right, top - topline, bottom - topline, 0x40000000); +		assert(camera._cur.x >= (_realWidth / 2) && camera._cur.y >= (_realHeight / 2)); -	int offset = (top - topline) * _realWidth + vs->xstart + left; -	backbuff = vs->screenPtr + offset; -	bgbak = getResourceAddress(rtBuffer, vs->number + 5) + offset; +		if ((camera._cur.x != old.x || camera._cur.y != old.y) +				&& _vars[VAR_SCROLL_SCRIPT]) { +			_vars[VAR_CAMERA_POS_X] = camera._cur.x; +			_vars[VAR_CAMERA_POS_Y] = camera._cur.y; +			runScript(_vars[VAR_SCROLL_SCRIPT], 0, 0, 0); +		} +	} else { +		int t; -	height = bottom - top; -	width = right - left; +		if (camera._mode != CM_FOLLOW_ACTOR || abs(pos_x - camera._cur.x) > (_realWidth / 2)) { +			camera._cur.x = pos_x; +		} +		camera._dest.x = pos_x; -	if (vs->alloctwobuffers && _currentRoom != 0 /*&& _vars[VAR_V5_DRAWFLAGS]&2 */ ) { -		blit(backbuff, bgbak, width, height); -		if (vs->number == 0 && charset._hasMask && height) { -			byte *mask; -			int mask_width = (width >> 3); +		t = _vars[VAR_CAMERA_MIN_X]; +		if (camera._cur.x < t) +			camera._cur.x = t; -			if (width & 0x07) -				mask_width++; +		t = _vars[VAR_CAMERA_MAX_X]; +		if (camera._cur.x > t) +			camera._cur.x = t; -			mask = getResourceAddress(rtBuffer, 9) + top * gdi._numStrips + (left >> 3) + _screenStartStrip; -			if (vs->number == 0) -				mask += vs->topline * gdi._numStrips; +		if (_vars[VAR_SCROLL_SCRIPT]) { +			_vars[VAR_CAMERA_POS_X] = camera._cur.x; +			runScript(_vars[VAR_SCROLL_SCRIPT], 0, 0, 0); +		} -			do { -				memset(mask, 0, mask_width); -				mask += gdi._numStrips; -			} while (--height); +		if (camera._cur.x != camera._last.x && charset._hasMask) +			stopTalk(); +	} +} + +void Scumm::setCameraFollows(Actor *a) +{ +	if (_features & GF_AFTER_V7) { +		byte oldfollow = camera._follows; +		int ax, ay; + +		camera._follows = a->number; + +		if (!a->isInCurrentRoom()) { +			startScene(a->getRoom(), 0, 0); +		} + +		ax = abs(a->x - camera._cur.x); +		ay = abs(a->y - camera._cur.y); + +		if (ax > _vars[VAR_CAMERA_THRESHOLD_X] || ay > _vars[VAR_CAMERA_THRESHOLD_Y] || ax > (_realWidth / 2) || ay > (_realHeight / 2)) { +			setCameraAt(a->x, a->y);  		} + +		if (a->number != oldfollow) +			runHook(0);  	} else { -		while (height--) { -			memset(backbuff, backColor, width); -			backbuff += _realWidth; +		int t, i; + +		camera._mode = CM_FOLLOW_ACTOR; +		camera._follows = a->number; + +		if (!a->isInCurrentRoom()) { +			startScene(a->getRoom(), 0, 0); +			camera._mode = CM_FOLLOW_ACTOR; +			camera._cur.x = a->x; +			setCameraAt(camera._cur.x, 0);  		} + +		t = (a->x >> 3); + +		if (t - _screenStartStrip < camera._leftTrigger || t - _screenStartStrip > camera._rightTrigger) +			setCameraAt(a->x, 0); + +		for (i = 1, a = getFirstActor(); ++a, i < NUM_ACTORS; i++) { +			if (a->isInCurrentRoom()) +				a->needRedraw = true; +		} +		runHook(0);  	}  } -void Scumm::updateDirtyRect(int virt, int left, int right, int top, int bottom, uint32 dirtybits) +void Scumm::clampCameraPos(ScummPoint *pt)  { -	VirtScreen *vs = &virtscr[virt]; -	int lp, rp; -	uint32 *sp; -	int num; +	if (pt->x < _vars[VAR_CAMERA_MIN_X]) +		pt->x = _vars[VAR_CAMERA_MIN_X]; -	if (top > vs->height || left > vs->width || right < 0 || bottom < 0) -		return; +	if (pt->x > _vars[VAR_CAMERA_MAX_X]) +		pt->x = _vars[VAR_CAMERA_MAX_X]; -	if (top < 0) -		top = 0; -	if (left < 0) -		left = 0; -	if (bottom > vs->height) -		bottom = vs->height; -	if (right > vs->width) -		right = vs->width; +	if (pt->y < _vars[VAR_CAMERA_MIN_Y]) +		pt->y = _vars[VAR_CAMERA_MIN_Y]; -	if (virt == 0 && dirtybits) { -		rp = (right >> 3) + _screenStartStrip; -		lp = (left >> 3) + _screenStartStrip; -		if (lp < 0) -			lp = 0; -		if (_features & GF_AFTER_V7) { -			if (rp > 409) -				rp = 409; +	if (pt->y > _vars[VAR_CAMERA_MAX_Y]) +		pt->y = _vars[VAR_CAMERA_MAX_Y]; +} + +void Scumm::moveCamera() +{ +	if (_features & GF_AFTER_V7) { +		ScummPoint old = camera._cur; +		Actor *a = NULL; + +		if (camera._follows) { +			a = derefActorSafe(camera._follows, "moveCamera"); +			if (abs(camera._cur.x - a->x) > _vars[VAR_CAMERA_THRESHOLD_X] || +					abs(camera._cur.y - a->y) > _vars[VAR_CAMERA_THRESHOLD_Y]) { +				camera._movingToActor = true; +				if (_vars[VAR_CAMERA_THRESHOLD_X] == 0) +					camera._cur.x = a->x; +				if (_vars[VAR_CAMERA_THRESHOLD_Y] == 0) +					camera._cur.y = a->y; +				clampCameraPos(&camera._cur); +			}  		} else { -			if (rp >= 200) -				rp = 200; +			camera._movingToActor = false;  		} -		if (lp <= rp) { -			num = rp - lp + 1; -			sp = &gfxUsageBits[lp]; -			do { -				*sp++ |= dirtybits; -			} while (--num); + +		if (camera._movingToActor) { +			camera._dest.x = a->x; +			camera._dest.y = a->y;  		} -	} -	setVirtscreenDirty(vs, left, top, right, bottom); -} +		assert(camera._cur.x >= (_realWidth / 2) && camera._cur.y >= (_realHeight / 2)); -void Scumm::setVirtscreenDirty(VirtScreen *vs, int left, int top, int right, int bottom) -{ -	int lp = left >> 3; -	int rp = right >> 3; +		clampCameraPos(&camera._dest); -	if ((lp >= gdi._numStrips) || (rp < 0)) -		return; -	if (lp < 0) -		lp = 0; -	if (rp >= gdi._numStrips) -		rp = gdi._numStrips - 1; +		if (camera._cur.x < camera._dest.x) { +			camera._cur.x += _vars[VAR_CAMERA_SPEED_X]; +			if (camera._cur.x > camera._dest.x) +				camera._cur.x = camera._dest.x; +		} -	while (lp <= rp) { -		if (top < vs->tdirty[lp]) -			vs->tdirty[lp] = top; -		if (bottom > vs->bdirty[lp]) -			vs->bdirty[lp] = bottom; -		lp++; +		if (camera._cur.x > camera._dest.x) { +			camera._cur.x -= _vars[VAR_CAMERA_SPEED_X]; +			if (camera._cur.x < camera._dest.x) +				camera._cur.x = camera._dest.x; +		} + +		if (camera._cur.y < camera._dest.y) { +			camera._cur.y += _vars[VAR_CAMERA_SPEED_Y]; +			if (camera._cur.y > camera._dest.y) +				camera._cur.y = camera._dest.y; +		} + +		if (camera._cur.y > camera._dest.y) { +			camera._cur.y -= _vars[VAR_CAMERA_SPEED_Y]; +			if (camera._cur.y < camera._dest.y) +				camera._cur.y = camera._dest.y; +		} + +		if (camera._cur.x == camera._dest.x && camera._cur.y == camera._dest.y) { + +			camera._movingToActor = false; +			camera._accel.x = camera._accel.y = 0; +			_vars[VAR_CAMERA_SPEED_X] = _vars[VAR_CAMERA_SPEED_Y] = 0; +		} else { + +			camera._accel.x += _vars[VAR_CAMERA_ACCEL_X]; +			camera._accel.y += _vars[VAR_CAMERA_ACCEL_Y]; + +			_vars[VAR_CAMERA_SPEED_X] += camera._accel.x / 100; +			_vars[VAR_CAMERA_SPEED_Y] += camera._accel.y / 100; + +			if (_vars[VAR_CAMERA_SPEED_X] < 8) +				_vars[VAR_CAMERA_SPEED_X] = 8; + +			if (_vars[VAR_CAMERA_SPEED_Y] < 8) +				_vars[VAR_CAMERA_SPEED_Y] = 8; + +		} + +		cameraMoved(); + +		if (camera._cur.x != old.x || camera._cur.y != old.y) { +			_vars[VAR_CAMERA_POS_X] = camera._cur.x; +			_vars[VAR_CAMERA_POS_Y] = camera._cur.y; + +			_vars[VAR_CAMERA_DEST_X] = camera._dest.x; + +			_vars[VAR_CAMERA_DEST_Y] = camera._dest.y; + +			_vars[VAR_CAMERA_FOLLOWED_ACTOR] = camera._follows; + +			if (_vars[VAR_SCROLL_SCRIPT]) +				runScript(_vars[VAR_SCROLL_SCRIPT], 0, 0, 0); +		} +	} else { +		int pos = camera._cur.x; +		int actorx, t; +		Actor *a = NULL; + +		camera._cur.x &= 0xFFF8; + +		if (camera._cur.x < _vars[VAR_CAMERA_MIN_X]) { +			if (_vars[VAR_CAMERA_FAST_X]) +				camera._cur.x = _vars[VAR_CAMERA_MIN_X]; +			else +				camera._cur.x += 8; +			cameraMoved(); +			return; +		} + +		if (camera._cur.x > _vars[VAR_CAMERA_MAX_X]) { +			if (_vars[VAR_CAMERA_FAST_X]) +				camera._cur.x = _vars[VAR_CAMERA_MAX_X]; +			else +				camera._cur.x -= 8; +			cameraMoved(); +			return; +		} + +		if (camera._mode == CM_FOLLOW_ACTOR) { +			a = derefActorSafe(camera._follows, "moveCamera"); + +			actorx = a->x; +			t = (actorx >> 3) - _screenStartStrip; + +			if (t < camera._leftTrigger || t > camera._rightTrigger) { +				if (_vars[VAR_CAMERA_FAST_X]) { +					if (t > 35) +						camera._dest.x = actorx + 80; +					if (t < 5) +						camera._dest.x = actorx - 80; +				} else +					camera._movingToActor = true; +			} +		} + +		if (camera._movingToActor) { +			a = derefActorSafe(camera._follows, "moveCamera(2)"); +			camera._dest.x = a->x; +		} + +		if (camera._dest.x < _vars[VAR_CAMERA_MIN_X]) +			camera._dest.x = _vars[VAR_CAMERA_MIN_X]; + +		if (camera._dest.x > _vars[VAR_CAMERA_MAX_X]) +			camera._dest.x = _vars[VAR_CAMERA_MAX_X]; + +		if (_vars[VAR_CAMERA_FAST_X]) { +			camera._cur.x = camera._dest.x; +		} else { +			if (camera._cur.x < camera._dest.x) +				camera._cur.x += 8; +			if (camera._cur.x > camera._dest.x) +				camera._cur.x -= 8; +		} + +		/* a is set a bit above */ +		if (camera._movingToActor && (camera._cur.x >> 3) == (a->x >> 3)) { +			camera._movingToActor = false; +		} + +		cameraMoved(); + +		if (pos != camera._cur.x && _vars[VAR_SCROLL_SCRIPT]) { +			_vars[VAR_CAMERA_POS_X] = camera._cur.x; +			runScript(_vars[VAR_SCROLL_SCRIPT], 0, 0, 0); +		}  	}  } -VirtScreen *Scumm::findVirtScreen(int y) +void Scumm::cameraMoved()  { -	VirtScreen *vs = virtscr; -	int i; +	if (_features & GF_AFTER_V7) { -	for (i = 0; i < 3; i++, vs++) { -		if (y >= vs->topline && y < vs->topline + vs->height) { -			return _curVirtScreen = vs; +		assert(camera._cur.x >= (_realWidth / 2) && camera._cur.y >= (_realHeight / 2)); + +	} else { + +		if (camera._cur.x < (_realWidth / 2)) { +			camera._cur.x = (_realWidth / 2); +		} else if (camera._cur.x > _scrWidth - (_realWidth / 2)) { +			camera._cur.x = _scrWidth - (_realWidth / 2);  		}  	} -	return _curVirtScreen = NULL; + +	_screenStartStrip = (camera._cur.x - (_realWidth / 2)) >> 3; +	_screenEndStrip = _screenStartStrip + gdi._numStrips - 1; +	virtscr[0].xstart = _screenStartStrip << 3; + + +	_screenTop = camera._cur.y - (_realHeight / 2); +	if (_features & GF_AFTER_V7) { + +		_screenLeft = camera._cur.x - (_realWidth / 2); +	} else { + +		_screenLeft = _screenStartStrip << 3; +	} +  } -void Scumm::unkScreenEffect1() +void Scumm::panCameraTo(int x, int y)  { -	/* XXX: not implemented */ -	warning("stub unkScreenEffect1()"); +	if (_features & GF_AFTER_V7) { + +		camera._follows = 0; +		camera._dest.x = x; +		camera._dest.y = y; +	} else { + +		camera._dest.x = x; +		camera._mode = CM_PANNING; +		camera._movingToActor = false; +	}  } -void Scumm::unkScreenEffect2() +void Scumm::actorFollowCamera(int act)  { -	/* XXX: not implemented */ -	warning("stub unkScreenEffect2()"); +	if (!(_features & GF_AFTER_V7)) { +		int old; + +		/* mi1 compatibilty */ +		if (act == 0) { +			camera._mode = CM_NORMAL; +			camera._follows = 0; +			camera._movingToActor = false; +			return; +		} + +		old = camera._follows; +		setCameraFollows(derefActorSafe(act, "actorFollowCamera")); +		if (camera._follows != old) +			runHook(0); + +		camera._movingToActor = false; +	}  } -void Scumm::unkScreenEffect3() +#pragma mark - +#pragma mark ### Transition effects ### +#pragma mark - + +void Scumm::fadeIn(int effect)  { -	/* XXX: not implemented */ -	warning("stub unkScreenEffect3()"); +	switch (effect) { +	case 1: +	case 2: +	case 3: +	case 4: +		transitionEffect(effect - 1); +		break; +	case 128: +		unkScreenEffect6(); +		break; +	case 130: +	case 131: +	case 132: +	case 133: +		scrollEffect(133 - effect); +		break; +	case 134: +		dissolveEffect(1, 1); +		break; +	case 135: +		unkScreenEffect5(1); +		break; +	case 129: +		break; +	default: +		warning("Unknown screen effect, %d", effect); +	} +	_screenEffectFlag = true;  } -void Scumm::unkScreenEffect4() +void Scumm::fadeOut(int effect)  { -	/* XXX: not implemented */ -	warning("stub unkScreenEffect4()"); -} +	VirtScreen *vs; -/* *INDENT-OFF* */ +	setDirtyRange(0, 0, 0); +	if (!(_features & GF_AFTER_V7)) +		camera._last.x = camera._cur.x; -static const int8 screen_eff7_table1[4][16] = { -	{ 1,  1, -1,  1, -1,  1, -1, -1, -	  1, -1, -1, -1,  1,  1,  1, -1}, -	{ 0,  1,  2,  1,  2,  0,  2,  1, -	  2,  0,  2,  1,  0,  0,  0,  0}, -	{-2, -1,  0, -1, -2, -1, -2,  0, -2, -1, -2, 0, 0, 0, 0, 0}, -	{ 0, -1, -2, -1, -2,  0, -2, -1, -2, 0, -2, -1, 0, 0, 0, 0} -}; +	if (!_screenEffectFlag) +		return; +	_screenEffectFlag = false; -static const byte screen_eff7_table2[4][16] = { -	{ 0,  0, 39,  0,  39,  0, 39, 24, -	  0, 24, 39, 24,   0,  0,  0, 24}, -	{ 0,  0,  0,  0,   0,  0,  0,  0, -	  1,  0,  1,  0, 255,  0,  0,  0}, -	{39, 24, 39, 24,  39, 24, 39, 24, -	 38, 24, 38, 24, 255,  0,  0,  0}, -	{ 0, 24, 39, 24,  39,  0, 39, 24, -	 38,  0, 38, 24, 255,  0,  0,  0} -}; +	if (effect == 0) +		return; -static const byte transition_num_of_iterations[4] = { -	13, 25, 25, 25 -}; +	// Fill screen 0 with black +	vs = &virtscr[0]; +	memset(vs->screenPtr + vs->xstart, 0, vs->size); -/* *INDENT-ON* */ +	// Fade to black with the specified effect, if any. +	switch (effect) { +	case 1: +	case 2: +	case 3: +	case 4: +		transitionEffect(effect - 1); +		break; +	case 128: +		unkScreenEffect6(); +		break; +	case 129: +		// Just blit screen 0 to the display (i.e. display will be black) +		setDirtyRange(0, 0, vs->height); +		updateDirtyScreen(0); +		break; +	case 134: +		dissolveEffect(1, 1); +		break; +	case 135: +		unkScreenEffect5(1); +		break; +	default: +		warning("fadeOut: default case %d", effect); +	} +}  /* Transition effect. There are four different effects possible,   * indicated by the value of a: @@ -2220,7 +2363,6 @@ void Scumm::scrollEffect(int dir) {  	}  } -  void Scumm::unkScreenEffect6() {  	if (_gameId == GID_LOOM256)  		dissolveEffect(1, 1); @@ -2249,259 +2391,184 @@ void Scumm::setShake(int mode)  	_system->set_shake_pos(0);  } -void Gdi::clearUpperMask() -{ -	memset(_vm->getResourceAddress(rtBuffer, 9), 0, _imgBufOffs[1] - _imgBufOffs[0] -		); -} +#pragma mark - +#pragma mark ### Palette ### +#pragma mark - -void Scumm::clampCameraPos(ScummPoint *pt) +void Scumm::setPaletteFromPtr(byte *ptr)  { -	if (pt->x < _vars[VAR_CAMERA_MIN_X]) -		pt->x = _vars[VAR_CAMERA_MIN_X]; - -	if (pt->x > _vars[VAR_CAMERA_MAX_X]) -		pt->x = _vars[VAR_CAMERA_MAX_X]; +	int i; +	byte *dest, r, g, b; +	int numcolor; -	if (pt->y < _vars[VAR_CAMERA_MIN_Y]) -		pt->y = _vars[VAR_CAMERA_MIN_Y]; +	if (_features & GF_SMALL_HEADER) { +		if (_features & GF_OLD256) +			numcolor = 256; +		else +			numcolor = READ_LE_UINT16(ptr + 6) / 3; +		ptr += 8; +	} else { +		numcolor = getResourceDataSize(ptr) / 3; +	} -	if (pt->y > _vars[VAR_CAMERA_MAX_Y]) -		pt->y = _vars[VAR_CAMERA_MAX_Y]; -} +	checkRange(256, 0, numcolor, "Too many colors (%d) in Palette"); +	dest = _currentPalette; -void Scumm::moveCamera() -{ -	if (_features & GF_AFTER_V7) { -		ScummPoint old = camera._cur; -		Actor *a = NULL; +	for (i = 0; i < numcolor; i++) { +		r = *ptr++; +		g = *ptr++; +		b = *ptr++; -		if (camera._follows) { -			a = derefActorSafe(camera._follows, "moveCamera"); -			if (abs(camera._cur.x - a->x) > _vars[VAR_CAMERA_THRESHOLD_X] || -					abs(camera._cur.y - a->y) > _vars[VAR_CAMERA_THRESHOLD_Y]) { -				camera._movingToActor = true; -				if (_vars[VAR_CAMERA_THRESHOLD_X] == 0) -					camera._cur.x = a->x; -				if (_vars[VAR_CAMERA_THRESHOLD_Y] == 0) -					camera._cur.y = a->y; -				clampCameraPos(&camera._cur); -			} +		// This comparison might look wierd, but it's what the disassembly (DOTT) says! +		// FIXME: Fingolfin still thinks it looks weird: the value 252 = 4*63 clearly comes from +		// the days 6/6/6 palettes were used, OK. But it breaks MonkeyVGA, so I had to add a +		// check for that. And somebody before me added a check for V7 games, turning this +		// off there, too... I wonder if it hurts other games, too? What exactly is broken +		// if we remove this patch? +		if ((_gameId == GID_MONKEY_VGA) || (_features & GF_AFTER_V7) || (i <= 15 || r < 252 || g < 252 || b < 252)) { +			*dest++ = r; +			*dest++ = g; +			*dest++ = b;  		} else { -			camera._movingToActor = false; -		} - -		if (camera._movingToActor) { -			camera._dest.x = a->x; -			camera._dest.y = a->y; -		} - -		assert(camera._cur.x >= (_realWidth / 2) && camera._cur.y >= (_realHeight / 2)); - -		clampCameraPos(&camera._dest); - -		if (camera._cur.x < camera._dest.x) { -			camera._cur.x += _vars[VAR_CAMERA_SPEED_X]; -			if (camera._cur.x > camera._dest.x) -				camera._cur.x = camera._dest.x; -		} - -		if (camera._cur.x > camera._dest.x) { -			camera._cur.x -= _vars[VAR_CAMERA_SPEED_X]; -			if (camera._cur.x < camera._dest.x) -				camera._cur.x = camera._dest.x; -		} - -		if (camera._cur.y < camera._dest.y) { -			camera._cur.y += _vars[VAR_CAMERA_SPEED_Y]; -			if (camera._cur.y > camera._dest.y) -				camera._cur.y = camera._dest.y; -		} - -		if (camera._cur.y > camera._dest.y) { -			camera._cur.y -= _vars[VAR_CAMERA_SPEED_Y]; -			if (camera._cur.y < camera._dest.y) -				camera._cur.y = camera._dest.y; +			dest += 3;  		} +	} +	setDirtyColors(0, numcolor - 1); +} -		if (camera._cur.x == camera._dest.x && camera._cur.y == camera._dest.y) { - -			camera._movingToActor = false; -			camera._accel.x = camera._accel.y = 0; -			_vars[VAR_CAMERA_SPEED_X] = _vars[VAR_CAMERA_SPEED_Y] = 0; -		} else { +void Scumm::setPaletteFromRes() +{ +	byte *ptr; +	ptr = getResourceAddress(rtRoom, _roomResource) + _CLUT_offs; +	setPaletteFromPtr(ptr); +} -			camera._accel.x += _vars[VAR_CAMERA_ACCEL_X]; -			camera._accel.y += _vars[VAR_CAMERA_ACCEL_Y]; -			_vars[VAR_CAMERA_SPEED_X] += camera._accel.x / 100; -			_vars[VAR_CAMERA_SPEED_Y] += camera._accel.y / 100; +void Scumm::setDirtyColors(int min, int max) +{ +	if (_palDirtyMin > min) +		_palDirtyMin = min; +	if (_palDirtyMax < max) +		_palDirtyMax = max; +} -			if (_vars[VAR_CAMERA_SPEED_X] < 8) -				_vars[VAR_CAMERA_SPEED_X] = 8; +void Scumm::initCycl(byte *ptr) +{ +	int j; +	ColorCycle *cycl; -			if (_vars[VAR_CAMERA_SPEED_Y] < 8) -				_vars[VAR_CAMERA_SPEED_Y] = 8; +	memset(_colorCycle, 0, sizeof(_colorCycle)); +	while ((j = *ptr++) != 0) { +		if (j < 1 || j > 16) { +			error("Invalid color cycle index %d", j);  		} +		cycl = &_colorCycle[j - 1]; -		cameraMoved(); - -		if (camera._cur.x != old.x || camera._cur.y != old.y) { -			_vars[VAR_CAMERA_POS_X] = camera._cur.x; -			_vars[VAR_CAMERA_POS_Y] = camera._cur.y; +		ptr += 2; +		cycl->counter = 0; +		cycl->delay = 16384 / READ_BE_UINT16_UNALIGNED(ptr); +		ptr += 2; +		cycl->flags = READ_BE_UINT16_UNALIGNED(ptr); +		ptr += 2; +		cycl->start = *ptr++; +		cycl->end = *ptr++; +	} +} -			_vars[VAR_CAMERA_DEST_X] = camera._dest.x; +void Scumm::stopCycle(int i) +{ +	ColorCycle *cycl; -			_vars[VAR_CAMERA_DEST_Y] = camera._dest.y; +	checkRange(16, 0, i, "Stop Cycle %d Out Of Range"); +	if (i != 0) { +		_colorCycle[i - 1].delay = 0; +		return; +	} -			_vars[VAR_CAMERA_FOLLOWED_ACTOR] = camera._follows; +	for (i = 0, cycl = _colorCycle; i < 16; i++, cycl++) +		cycl->delay = 0; +} -			if (_vars[VAR_SCROLL_SCRIPT]) -				runScript(_vars[VAR_SCROLL_SCRIPT], 0, 0, 0); -		} -	} else { -		int pos = camera._cur.x; -		int actorx, t; -		Actor *a = NULL; +void Scumm::cyclePalette() +{ +	ColorCycle *cycl; +	int valueToAdd; +	int i, num; +	byte *start, *end; +	byte tmp[3]; -		camera._cur.x &= 0xFFF8; +	valueToAdd = _vars[VAR_TIMER]; +	if (valueToAdd < _vars[VAR_TIMER_NEXT]) +		valueToAdd = _vars[VAR_TIMER_NEXT]; -		if (camera._cur.x < _vars[VAR_CAMERA_MIN_X]) { -			if (_vars[VAR_CAMERA_FAST_X]) -				camera._cur.x = _vars[VAR_CAMERA_MIN_X]; -			else -				camera._cur.x += 8; -			cameraMoved(); -			return; -		} +	if (!_colorCycle)							// FIXME +		return; -		if (camera._cur.x > _vars[VAR_CAMERA_MAX_X]) { -			if (_vars[VAR_CAMERA_FAST_X]) -				camera._cur.x = _vars[VAR_CAMERA_MAX_X]; -			else -				camera._cur.x -= 8; -			cameraMoved(); -			return; -		} +	for (i = 0, cycl = _colorCycle; i < 16; i++, cycl++) { +		if (cycl->delay && (cycl->counter += valueToAdd) >= cycl->delay) { +			do { +				cycl->counter -= cycl->delay; +			} while (cycl->delay <= cycl->counter); -		if (camera._mode == CM_FOLLOW_ACTOR) { -			a = derefActorSafe(camera._follows, "moveCamera"); +			setDirtyColors(cycl->start, cycl->end); +			moveMemInPalRes(cycl->start, cycl->end, cycl->flags & 2); +			start = &_currentPalette[cycl->start * 3]; +			end = &_currentPalette[cycl->end * 3]; -			actorx = a->x; -			t = (actorx >> 3) - _screenStartStrip; +			num = cycl->end - cycl->start; -			if (t < camera._leftTrigger || t > camera._rightTrigger) { -				if (_vars[VAR_CAMERA_FAST_X]) { -					if (t > 35) -						camera._dest.x = actorx + 80; -					if (t < 5) -						camera._dest.x = actorx - 80; -				} else -					camera._movingToActor = true; +			if (!(cycl->flags & 2)) { +				memmove(tmp, end, 3); +				memmove(start + 3, start, num * 3); +				memmove(start, tmp, 3); +			} else { +				memmove(tmp, start, 3); +				memmove(start, start + 3, num * 3); +				memmove(end, tmp, 3);  			}  		} - -		if (camera._movingToActor) { -			a = derefActorSafe(camera._follows, "moveCamera(2)"); -			camera._dest.x = a->x; -		} - -		if (camera._dest.x < _vars[VAR_CAMERA_MIN_X]) -			camera._dest.x = _vars[VAR_CAMERA_MIN_X]; - -		if (camera._dest.x > _vars[VAR_CAMERA_MAX_X]) -			camera._dest.x = _vars[VAR_CAMERA_MAX_X]; - -		if (_vars[VAR_CAMERA_FAST_X]) { -			camera._cur.x = camera._dest.x; -		} else { -			if (camera._cur.x < camera._dest.x) -				camera._cur.x += 8; -			if (camera._cur.x > camera._dest.x) -				camera._cur.x -= 8; -		} - -		/* a is set a bit above */ -		if (camera._movingToActor && (camera._cur.x >> 3) == (a->x >> 3)) { -			camera._movingToActor = false; -		} - -		cameraMoved(); - -		if (pos != camera._cur.x && _vars[VAR_SCROLL_SCRIPT]) { -			_vars[VAR_CAMERA_POS_X] = camera._cur.x; -			runScript(_vars[VAR_SCROLL_SCRIPT], 0, 0, 0); -		}  	}  } -void Scumm::cameraMoved() +// Perform color cycling on the palManipulate data, too, otherwise +// color cycling will be disturbed by the palette fade. +void Scumm::moveMemInPalRes(int start, int end, byte direction)  { -	if (_features & GF_AFTER_V7) { - -		assert(camera._cur.x >= (_realWidth / 2) && camera._cur.y >= (_realHeight / 2)); - -	} else { - -		if (camera._cur.x < (_realWidth / 2)) { -			camera._cur.x = (_realWidth / 2); -		} else if (camera._cur.x > _scrWidth - (_realWidth / 2)) { -			camera._cur.x = _scrWidth - (_realWidth / 2); -		} -	} - -	_screenStartStrip = (camera._cur.x - (_realWidth / 2)) >> 3; -	_screenEndStrip = _screenStartStrip + gdi._numStrips - 1; -	virtscr[0].xstart = _screenStartStrip << 3; - +	byte *startptr, *endptr; +	byte *startptr2, *endptr2; +	int num; +	byte tmp[6]; -	_screenTop = camera._cur.y - (_realHeight / 2); -	if (_features & GF_AFTER_V7) { +	if (!_palManipCounter) +		return; -		_screenLeft = camera._cur.x - (_realWidth / 2); -	} else { +	startptr = _palManipPalette + start * 3; +	endptr = _palManipPalette + end * 3; +	startptr2 = _palManipIntermediatePal + start * 6; +	endptr2 = _palManipIntermediatePal + end * 6; +	num = end - start; -		_screenLeft = _screenStartStrip << 3; +	if (!endptr) { +		warning("moveMemInPalRes(%d,%d): Bad end pointer\n", start, end); +		return;  	} -} - -void Scumm::panCameraTo(int x, int y) -{ -	if (_features & GF_AFTER_V7) { - -		camera._follows = 0; -		camera._dest.x = x; -		camera._dest.y = y; +	if (!direction) { +		memmove(tmp, endptr, 3); +		memmove(startptr + 3, startptr, num * 3); +		memmove(startptr, tmp, 3); +		memmove(tmp, endptr2, 6); +		memmove(startptr2 + 6, startptr2, num * 6); +		memmove(startptr2, tmp, 6);  	} else { - -		camera._dest.x = x; -		camera._mode = CM_PANNING; -		camera._movingToActor = false; -	} -} - -void Scumm::actorFollowCamera(int act) -{ -	if (!(_features & GF_AFTER_V7)) { -		int old; - -		/* mi1 compatibilty */ -		if (act == 0) { -			camera._mode = CM_NORMAL; -			camera._follows = 0; -			camera._movingToActor = false; -			return; -		} - -		old = camera._follows; -		setCameraFollows(derefActorSafe(act, "actorFollowCamera")); -		if (camera._follows != old) -			runHook(0); - -		camera._movingToActor = false; +		memmove(tmp, startptr, 3); +		memmove(startptr, startptr + 3, num * 3); +		memmove(endptr, tmp, 3); +		memmove(tmp, startptr2, 6); +		memmove(startptr2, startptr2 + 6, num * 6); +		memmove(endptr2, tmp, 6);  	}  } @@ -2606,11 +2673,6 @@ void Scumm::setupShadowPalette(int slot, int redScale, int greenScale, int blueS  	}  } -static inline uint colorWeight(int red, int green, int blue) -{ -	return 3 * red * red + 6 * green * green + 2 * blue * blue; -} -  void Scumm::setupShadowPalette(int redScale, int greenScale, int blueScale, int startColor, int endColor)  {  	byte *basepal = getPalettePtr(); @@ -2857,35 +2919,6 @@ void Scumm::copyPalColor(int dst, int src)  	setDirtyColors(dst, dst);  } -void Gdi::resetBackground(int top, int bottom, int strip) -{ -	VirtScreen *vs = &_vm->virtscr[0]; -	int offs; - -	if (top < vs->tdirty[strip]) -		vs->tdirty[strip] = top; - -	if (bottom > vs->bdirty[strip]) -		vs->bdirty[strip] = bottom; - -	offs = (top * _numStrips + _vm->_screenStartStrip + strip); -	_mask_ptr = _vm->getResourceAddress(rtBuffer, 9) + offs; -	_bgbak_ptr = _vm->getResourceAddress(rtBuffer, 5) + (offs << 3); -	_backbuff_ptr = vs->screenPtr + (offs << 3); - -	_numLinesToProcess = bottom - top; -	if (_numLinesToProcess) { -		if ((_vm->_features & GF_AFTER_V6) || (_vm->_vars[_vm->VAR_CURRENT_LIGHTS] & LIGHTMODE_screen)) { -			if (_vm->hasCharsetMask(strip << 3, top, (strip + 1) << 3, bottom)) -				draw8ColWithMasking(_backbuff_ptr, _bgbak_ptr, _numLinesToProcess, _mask_ptr); -			else -				draw8Col(_backbuff_ptr, _bgbak_ptr, _numLinesToProcess); -		} else { -			clear8Col(_backbuff_ptr, _numLinesToProcess); -		} -	} -} -  void Scumm::setPalColor(int idx, int r, int g, int b)  {  	_currentPalette[idx * 3 + 0] = r; @@ -2894,42 +2927,6 @@ void Scumm::setPalColor(int idx, int r, int g, int b)  	setDirtyColors(idx, idx);  } -void Scumm::setCursorHotspot2(int x, int y) -{ -	_cursor.hotspotX = x; -	_cursor.hotspotY = y; -} - -byte Scumm::isMaskActiveAt(int l, int t, int r, int b, byte *mem) -{ -	int w, h, i; - -	l >>= 3; -	if (l < 0) -		l = 0; -	if (t < 0) -		t = 0; - -	r >>= 3; -	if (r > gdi._numStrips - 1) -		r = gdi._numStrips - 1; - -	mem += l + t * gdi._numStrips; - -	w = r - l; -	h = b - t + 1; - -	do { -		for (i = 0; i <= w; i++) -			if (mem[i]) { -				return true; -			} -		mem += gdi._numStrips; -	} while (--h); - -	return false; -} -  void Scumm::setPalette(int palindex)  {  	byte *pals; @@ -2975,6 +2972,10 @@ byte *Scumm::getPalettePtr()  	return cptr;  } +#pragma mark - +#pragma mark ### Cursor ### +#pragma mark - +  void Scumm::grabCursor(int x, int y, int w, int h)  {  	VirtScreen *vs = findVirtScreen(y); @@ -2988,36 +2989,6 @@ void Scumm::grabCursor(int x, int y, int w, int h)  } -void Scumm::decompressBomp(byte *dst, byte *src, int w, int h) -{ -	int len, num; -	byte code, color; - -	src += 8; - -	do { -		len = w; -		src += 2; -		while (len) { -			code = *src++; -			num = (code >> 1) + 1; -			if (num > len) -				num = len; -			len -= num; -			if (code & 1) { -				color = *src++; -				do -					*dst++ = color; -				while (--num); -			} else { -				do -					*dst++ = *src++; -				while (--num); -			} -		} -	} while (--h); -} -  void Scumm::grabCursor(byte *ptr, int width, int height)  {  	uint size; @@ -3061,10 +3032,24 @@ void Scumm::useIm01Cursor(byte *im, int w, int h)  	blit(vs->screenPtr + vs->xstart, getResourceAddress(rtBuffer, 5) + vs->xstart, w, h);  } +void Scumm::setCursor(int cursor) +{ +	if (cursor >= 0 && cursor <= 3) +		_currentCursor = cursor; +	else +		warning("setCursor(%d)", cursor); +} + +void Scumm::setCursorHotspot2(int x, int y) +{ +	_cursor.hotspotX = x; +	_cursor.hotspotY = y; +} +  void Scumm::updateCursor()  {  	_system->set_mouse_cursor(_grabbedCursor, _cursor.width, _cursor.height, -														_cursor.hotspotX, _cursor.hotspotY); +	                                          _cursor.hotspotX, _cursor.hotspotY);  }  void Scumm::animateCursor() @@ -3075,7 +3060,6 @@ void Scumm::animateCursor()  		}  		_cursor.animateIndex++;  	} -  }  void Scumm::useBompCursor(byte *im, int width, int height) @@ -3098,29 +3082,6 @@ void Scumm::useBompCursor(byte *im, int width, int height)  	updateCursor();  } -static const byte default_cursor_colors[4] = { -	15, 15, 7, 8 -}; - -static const uint16 default_cursor_images[4][16] = { -	/* cross-hair */ -	{ 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0000, 0x7e3f, -	  0x0000, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0000 }, -	/* hourglass */ -	{ 0x0000, 0x7ffe, 0x6006, 0x300c, 0x1818, 0x0c30, 0x0660, 0x03c0, -	  0x0660, 0x0c30, 0x1998, 0x33cc, 0x67e6, 0x7ffe, 0x0000, 0x0000 }, -	/* arrow */ -	{ 0x0000, 0x4000, 0x6000, 0x7000, 0x7800, 0x7c00, 0x7e00, 0x7f00, -	  0x7f80, 0x78c0, 0x7c00, 0x4600, 0x0600, 0x0300, 0x0300, 0x0180 }, -	/* hand */ -	{ 0x1e00, 0x1200, 0x1200, 0x1200, 0x1200, 0x13ff, 0x1249, 0x1249, -	  0xf249, 0x9001, 0x9001, 0x9001, 0x8001, 0x8001, 0x8001, 0xffff }, -}; - -static const byte default_cursor_hotspots[8] = { -	8, 7,   8, 7,   1, 1,   5, 0 -}; -  void Scumm::decompressDefaultCursor(int idx)  {  	int i, j; @@ -3175,6 +3136,10 @@ void Scumm::makeCursorColorTransparent(int a)  	updateCursor();  } +#pragma mark - +#pragma mark ### Bomp ### +#pragma mark - +  int32 Scumm::bompDecodeLineMode0(byte * src, byte * line_buffer, int32 size) {  	if (size <= 0)  		return size; @@ -3328,6 +3293,36 @@ void Scumm::bompScaleFuncX(byte * line_buffer, byte * scalling_x_ptr, byte skip,  	}  } +void Scumm::decompressBomp(byte *dst, byte *src, int w, int h) +{ +	int len, num; +	byte code, color; + +	src += 8; + +	do { +		len = w; +		src += 2; +		while (len) { +			code = *src++; +			num = (code >> 1) + 1; +			if (num > len) +				num = len; +			len -= num; +			if (code & 1) { +				color = *src++; +				do +					*dst++ = color; +				while (--num); +			} else { +				do +					*dst++ = *src++; +				while (--num); +			} +		} +	} while (--h); +} +  void Scumm::drawBomp(BompDrawData * bd, int decode_mode, int mask) {  	byte skip_y = 128;  	byte skip_y_new = 0; diff --git a/scumm/gfx.h b/scumm/gfx.h index 7985c884c7..cbc2948dd0 100644 --- a/scumm/gfx.h +++ b/scumm/gfx.h @@ -114,12 +114,10 @@ class Gdi {  public:  	Scumm *_vm; -public:  	int _numZBuffer;  	int _imgBufOffs[5];  	byte _disable_zbuffer;  	int32 _numStrips; -public:  	int16 _mask_top, _mask_bottom, _mask_right, _mask_left;  protected: @@ -174,6 +172,9 @@ protected:  	void decompressMaskImgOr(byte *dst, byte *src, int height);  	void decompressMaskImg(byte *dst, byte *src, int height); +	void drawStripToScreen(VirtScreen *vs, int x, int w, int t, int b); +	void updateDirtyScreen(VirtScreen *vs); +  public:  	void drawBitmap(byte *ptr, VirtScreen *vs, int x, int y, int h, int stripnr, int numstrip, byte flag);  	void clearUpperMask(); @@ -182,8 +183,6 @@ public:  	void enableZBuffer() { _disable_zbuffer--; }  	void resetBackground(int top, int bottom, int strip); -	void drawStripToScreen(VirtScreen *vs, int x, int w, int t, int b); -	void updateDirtyScreen(VirtScreen *vs);  	enum DrawBitmapFlags {  		dbAllowMaskOr = 1, diff --git a/scumm/scumm.h b/scumm/scumm.h index 3b5827a1f8..c158da78d0 100644 --- a/scumm/scumm.h +++ b/scumm/scumm.h @@ -794,10 +794,6 @@ public:  	void fadeIn(int effect);  	void fadeOut(int effect); -	void unkScreenEffect1(); -	void unkScreenEffect2(); -	void unkScreenEffect3(); -	void unkScreenEffect4();  	void unkScreenEffect5(int a);  	void unkScreenEffect6();  	void transitionEffect(int a); @@ -846,7 +842,14 @@ public:  	uint16 _palManipCounter;  	byte *_palManipPalette;  	byte *_palManipIntermediatePal; +	 +	/* For each screen strip, gfxUsageBits contains a bitmask. +	 * The lower 30 bits each correspond to one actor and signify if any part +	 * of that actor is currently contained in that strip. +	 * If the left most bit is set, the strip (background) is dirty needs to be redrawn. +	 */  	uint32 gfxUsageBits[410]; +	  	byte *_shadowPalette;  	int _shadowPaletteSize;  	byte _currentPalette[3 * 256]; | 
