/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "lastexpress/lastexpress.h" #include "lastexpress/game/nis.h" #include "lastexpress/data/archive.h" namespace LastExpress { NISManager::NISManager(LastExpressEngine *engine) { _engine = engine; _background1 = new NisSprite(); _background2 = new NisSprite(); _waneSprite = new NisSprite(); _waxSprite = new NisSprite(); } NISManager::~NISManager() { SAFE_DELETE(_background1); SAFE_DELETE(_background2); SAFE_DELETE(_waneSprite); SAFE_DELETE(_waxSprite); SAFE_DELETE_ARR(_events); } void NISManager::clearBounds() { _nisRect.left = 640; _nisRect.top = 480; _nisRect.right = 0; _nisRect.bottom = 0; } void NISManager::addBounds(Extent extent) { if (_nisRect.left > (int16)extent.left) _nisRect.left = (int16)extent.left; if (_nisRect.right < (int16)extent.right) _nisRect.right = (int16)extent.right; if (_nisRect.top > (int16)extent.top) _nisRect.top = (int16)extent.top; if (_nisRect.bottom < (int16)extent.bottom) _nisRect.bottom = (int16)extent.bottom; } void NISManager::convertNSPR16(byte *spriteData, NisSprite *outSprite) { uint32 compDataOffset = READ_LE_UINT32(spriteData); uint32 eraseMaskOffset = READ_LE_UINT32(spriteData + 4); uint32 colorPaletteOffset = READ_LE_UINT32(spriteData + 8); outSprite->rect.left = READ_LE_INT32(spriteData + 12); outSprite->rect.top = READ_LE_INT32(spriteData + 16); outSprite->rect.right = READ_LE_INT32(spriteData + 20); outSprite->rect.bottom = READ_LE_INT32(spriteData + 24); outSprite->rect.width = READ_LE_INT32(spriteData + 28); outSprite->rect.height = READ_LE_INT32(spriteData + 32); outSprite->colorPalette = (uint16 *)&spriteData[colorPaletteOffset]; WRITE_LE_UINT16(&outSprite->colorPalette[0], 0); WRITE_LE_UINT16(&outSprite->colorPalette[1], 0); for (int i = 0; i < 128; ++i) outSprite->colorPalette[i] = READ_LE_UINT16(&outSprite->colorPalette[i]); _engine->getGraphicsManager()->modifyPalette((uint16 *)outSprite->colorPalette, 128); for (int i = 0; i < 128; i++) outSprite->gammaPalette[i] = READ_UINT16(spriteData + 2 * i + 36); outSprite->compBits = spriteData[2 * 128 + 36]; outSprite->compData = &spriteData[compDataOffset]; if (eraseMaskOffset) outSprite->eraseMask = &spriteData[eraseMaskOffset]; } void NISManager::getStream(byte *data, int32 size) { if (size > _remainingStreamBytes) { Slot *slot; for (slot = _engine->getSoundManager()->_soundCache; slot; slot = slot->getNext()) { if (!slot->hasTag(kSoundTagNIS)) break; } if (slot && _currentNISSound) _currentNISSound->addStatusFlag(kSoundFlagPauseRequested); for (int i = 0; i < 20; ++i) { if ((_flags & kNisFlagDataChunksAvailable) != 0) loadChunk(32); } getStream(data, size); if (_currentNISSound) _currentNISSound->removeStatusFlag(kSoundFlagPauseRequested | kSoundFlagPaused); } else if (size + _streamCurrentPosition <= _streamBufferSize) { memcpy(data, (byte *)_backgroundSurface + _streamCurrentPosition, size); _streamCurrentPosition += size; _remainingStreamBytes -= size; if (_streamCurrentPosition >= _streamBufferSize) _streamCurrentPosition = 0; } else { int32 prevSize = _streamBufferSize - _streamCurrentPosition; getStream(data, _streamBufferSize - _streamCurrentPosition); getStream(&data[prevSize], size - prevSize); } } void NISManager::loadSnd(int32 size) { byte *currentBufferPtr = _currentNISSound->getCurrentBufferPtr(); byte *dataEnd = _currentNISSound->getDataEnd(); int32 availableSize = dataEnd - currentBufferPtr; if (size < dataEnd - currentBufferPtr) { getStream(_currentNISSound->getCurrentBufferPtr(), size); _currentNISSound->advanceCurrentBufferPtrBy(size); _currentNISSound->advanceLoadedBytesBy(size); } else { getStream(_currentNISSound->getCurrentBufferPtr(), dataEnd - currentBufferPtr); _currentNISSound->advanceCurrentBufferPtrBy(availableSize); _currentNISSound->setCurrentBufferPtr(_currentNISSound->getDataStart()); loadSnd(size - availableSize); } if (_currentNISSound->getCurrentDataPtr() < _currentNISSound->getDataStart() + 88064) memcpy(_currentNISSound->getDataEnd(), _currentNISSound->getDataStart(), NIS_SOUND_CHUNK_SIZE); } int NISManager::loadChunk(int32 size) { int32 sizeToLoad = _totalStreamPages - ((_remainingStreamBytes + 2047) / MEM_PAGE_SIZE); if (!_archive || (_archive->status & 2) == 0) return 0; if (sizeToLoad > _totalStreamPages) sizeToLoad = 0; if (sizeToLoad > size) sizeToLoad = size; if (!sizeToLoad) return 0; uint16 sizeArch = _archive->size; uint16 currentPos = _archive->currentPos; if (sizeArch <= currentPos) return 0; if (sizeToLoad > 16) sizeToLoad = 16; if (currentPos + sizeToLoad > sizeArch) { _flags ^= kNisFlagDataChunksAvailable; sizeToLoad = sizeArch - currentPos; } if (sizeToLoad + _currentStreamPage >= _totalStreamPages) sizeToLoad = _totalStreamPages - _currentStreamPage; _engine->getArchiveManager()->readHPF(_archive, ((byte *)_backgroundSurface + (_currentStreamPage * MEM_PAGE_SIZE)), sizeToLoad); _currentStreamPage += sizeToLoad; _remainingStreamBytes += sizeToLoad * MEM_PAGE_SIZE; if (_currentStreamPage >= _totalStreamPages) _currentStreamPage -= _totalStreamPages; return sizeToLoad; } bool NISManager::initNIS(const char *filename, int32 flags) { int32 chunkSizeRead = 0; int32 eventSize = 0; Slot *slot; _currentNISSound = nullptr; _backgroundType = 0; _selectBackgroundType = 0; _backgroundFlag = false; _cumulativeEventSize = 0; _flags = flags | kNisFlagDataChunksAvailable; _decompressToBackBuffer = true; _firstNISBackgroundDraw = true; clearBounds(); _currentStreamPage = 0; _streamCurrentPosition = 0; _remainingStreamBytes = 0; _streamBufferSize = 1530 * MEM_PAGE_SIZE; _originalBackgroundSurface = _engine->getGraphicsManager()->_frontBuffer; _totalBackgroundPages = 1530; _totalStreamPages = 1530; _backgroundSurface = _engine->getGraphicsManager()->_frontBuffer; _archive = _engine->getArchiveManager()->openHPF(filename); if (!_archive) { warning("NIS %s not ready", filename); return false; } _engine->getMemoryManager()->lockSeqMem((_totalBackgroundPages - 300) * MEM_PAGE_SIZE); getStream((byte *)&_eventsCount, 4); _eventsCount = READ_LE_INT32(&_eventsCount); _eventsByteStream = (byte *)(_backgroundSurface + 2); _background1Offset = READ_LE_INT32((int32 *)_backgroundSurface + 2); _background1Offset += 16; _background1Offset &= 0xFFFFFFF0; _streamBufferSize -= _background1Offset; _background1ByteStream = (byte *)((byte *)_backgroundSurface + _streamBufferSize); _waneSpriteOffset = READ_LE_INT32((int32 *)_backgroundSurface + 4); _waneSpriteOffset += 16; _waneSpriteOffset &= 0xFFFFFFF0; _streamBufferSize -= _waneSpriteOffset; _waneSpriteByteStream = (byte *)((byte *)_backgroundSurface + _streamBufferSize); _streamBufferSize -= 8 * _eventsCount; _eventsByteStream = (byte *)((byte *)_backgroundSurface + _streamBufferSize); _totalStreamPages = (_streamBufferSize / MEM_PAGE_SIZE); _streamBufferSize = (_streamBufferSize / MEM_PAGE_SIZE) * MEM_PAGE_SIZE; chunkSizeRead = loadChunk(32); getStream(_eventsByteStream, 8 * _eventsCount); SAFE_DELETE_ARR(_events); _events = new NisEvents[_eventsCount]; for (int i = 0; i < _eventsCount; i++) { _events[i].eventType = READ_LE_INT16(_eventsByteStream + i * 8); _events[i].eventTime = READ_LE_INT16(_eventsByteStream + i * 8 + 2); _events[i].eventSize = READ_LE_INT32(_eventsByteStream + i * 8 + 4); } while ((_flags & kNisFlagDataChunksAvailable) != 0) { if (!_events[4].eventSize) break; chunkSizeRead = loadChunk(32) * MEM_PAGE_SIZE; if (!chunkSizeRead) break; eventSize = _events[4].eventSize; _events[4].eventSize = chunkSizeRead >= eventSize ? 0 : eventSize - chunkSizeRead; } if ((flags & kNisFlagSoundFade) != 0) _engine->getSoundManager()->NISFadeOut(); getNISSlot(); for (slot = _engine->getSoundManager()->_soundCache; slot; slot = slot->getNext()) { if (slot->hasTag(kSoundTagNIS)) break; } _currentNISSound = slot; if (!slot) { if ((flags & kNisFlagSoundFade) != 0) _engine->getSoundManager()->NISFadeIn(); endNIS(); return false; } Common::String noExtName = filename; noExtName.replace('.', '\0'); _currentNISSound->setSub(noExtName.c_str()); Common::String lnkName = Common::String(noExtName.c_str()) + ".LNK"; HPF *lnkResource = _engine->getArchiveManager()->openHPF(lnkName.c_str()); if (lnkResource) { _engine->getArchiveManager()->closeHPF(lnkResource); _chainedSoundSlot = new Slot(_engine->getSoundManager(), lnkName.c_str(), kSoundTypeLink | kVolumeFull, 105); } else { _chainedSoundSlot = nullptr; } if (_chainedSoundSlot) { _currentNISSound->setChainedSound(_chainedSoundSlot); _currentNISSound->addStatusFlag(kSoundFlagHasLinkAfter); if (!scumm_stricmp(lnkName.c_str(), "1917.LNK")) { _chainedSoundSlot->setAssociatedCharacter(kCharacterKronos); _chainedSoundSlot->removeStatusFlag(kSoundTypeLink | kSoundFlagFixedVolume); _chainedSoundSlot->addStatusFlag(kSoundTypeConcert); _chainedSoundSlot->assignDirectTag(kSoundTagConcert); _chainedSoundSlot->assignDirectVolume(16); } } return true; } void NISManager::endNIS() { if (_archive) { _engine->getArchiveManager()->closeHPF(_archive); _archive = nullptr; } } void NISManager::abortNIS() { if ((_flags & kNisFlagPlaying) != 0) _flags |= kNisFlagAbortRequested; } void NISManager::nisMouse(Event *event) { if ((event->flags & kMouseFlagRightDown) != 0) abortNIS(); } void NISManager::nisTimer(Event *event) { _engine->setEventTickInternal(false); } void NISManager::drawSprite(NisSprite *sprite) { Extent rect; rect.left = sprite->rect.left; rect.right = sprite->rect.right; rect.top = sprite->rect.top; rect.bottom = sprite->rect.bottom; rect.width = sprite->rect.width; rect.height = sprite->rect.height; addBounds(rect); // Use a temp sprite and just fill out the bare minimum needed for decompression... Sprite tempSprite; tempSprite.compData = sprite->compData; tempSprite.colorPalette = sprite->colorPalette; tempSprite.rect = rect; switch (sprite->compBits) { case 3: if (_decompressToBackBuffer) { _engine->getGraphicsManager()->bitBltSprite8(&tempSprite, _engine->getGraphicsManager()->_backBuffer); } else if (_engine->getGraphicsManager()->acquireSurface()) { _engine->getGraphicsManager()->bitBltSprite8(&tempSprite, (PixMap *)_engine->getGraphicsManager()->_screenSurface.getPixels()); _engine->getGraphicsManager()->unlockSurface(); } break; case 4: if (_decompressToBackBuffer) { _engine->getGraphicsManager()->bitBltSprite16(&tempSprite, _engine->getGraphicsManager()->_backBuffer); } else if (_engine->getGraphicsManager()->acquireSurface()) { _engine->getGraphicsManager()->bitBltSprite16(&tempSprite, (PixMap *)_engine->getGraphicsManager()->_screenSurface.getPixels()); _engine->getGraphicsManager()->unlockSurface(); } break; case 5: if (_decompressToBackBuffer) { _engine->getGraphicsManager()->bitBltSprite32(&tempSprite, _engine->getGraphicsManager()->_backBuffer); } else if (_engine->getGraphicsManager()->acquireSurface()) { _engine->getGraphicsManager()->bitBltSprite32(&tempSprite, (PixMap *)_engine->getGraphicsManager()->_screenSurface.getPixels()); _engine->getGraphicsManager()->unlockSurface(); } break; case 7: if (_decompressToBackBuffer) { _engine->getGraphicsManager()->bitBltSprite128(&tempSprite, _engine->getGraphicsManager()->_backBuffer); } else if (_engine->getGraphicsManager()->acquireSurface()) { _engine->getGraphicsManager()->bitBltSprite128(&tempSprite, (PixMap *)_engine->getGraphicsManager()->_screenSurface.getPixels()); _engine->getGraphicsManager()->unlockSurface(); } break; case 255: if (_decompressToBackBuffer) { _engine->getGraphicsManager()->bitBltSprite255(&tempSprite, _engine->getGraphicsManager()->_backBuffer); } else if (_engine->getGraphicsManager()->acquireSurface()) { _engine->getGraphicsManager()->bitBltSprite255(&tempSprite, (PixMap *)_engine->getGraphicsManager()->_screenSurface.getPixels()); _engine->getGraphicsManager()->unlockSurface(); } break; default: return; } } void NISManager::waxSprite(NisSprite *sprite) { Extent rect; rect.left = sprite->rect.left; rect.right = sprite->rect.right; rect.top = sprite->rect.top; rect.bottom = sprite->rect.bottom; rect.width = sprite->rect.width; rect.height = sprite->rect.height; addBounds(rect); // Use a temp sprite and just fill out the bare minimum needed for decompression... Sprite tempSprite; tempSprite.compData = sprite->compData; tempSprite.colorPalette = sprite->colorPalette; tempSprite.rect = rect; switch (sprite->compBits) { case 3: if (_engine->getGraphicsManager()->acquireSurface()) { _engine->getGraphicsManager()->bitBltWax8(&tempSprite, (PixMap *)_engine->getGraphicsManager()->_screenSurface.getPixels()); _engine->getGraphicsManager()->unlockSurface(); } break; case 4: if (_engine->getGraphicsManager()->acquireSurface()) { _engine->getGraphicsManager()->bitBltWax16(&tempSprite, (PixMap *)_engine->getGraphicsManager()->_screenSurface.getPixels()); _engine->getGraphicsManager()->unlockSurface(); } break; case 5: if (_engine->getGraphicsManager()->acquireSurface()) { _engine->getGraphicsManager()->bitBltWax32(&tempSprite, (PixMap *)_engine->getGraphicsManager()->_screenSurface.getPixels()); _engine->getGraphicsManager()->unlockSurface(); } break; case 7: if (_engine->getGraphicsManager()->acquireSurface()) { _engine->getGraphicsManager()->bitBltWax128(&tempSprite, (PixMap *)_engine->getGraphicsManager()->_screenSurface.getPixels()); _engine->getGraphicsManager()->unlockSurface(); } break; default: return; } } void NISManager::waneSprite(NisSprite *sprite) { Extent rect; rect.left = sprite->rect.left; rect.right = sprite->rect.right; rect.top = sprite->rect.top; rect.bottom = sprite->rect.bottom; rect.width = sprite->rect.width; rect.height = sprite->rect.height; addBounds(rect); // Use a temp sprite and just fill out the bare minimum needed for decompression... Sprite tempSprite; tempSprite.compData = sprite->compData; tempSprite.colorPalette = sprite->colorPalette; tempSprite.rect = rect; switch (sprite->compBits) { case 3: if (_engine->getGraphicsManager()->acquireSurface()) { _engine->getGraphicsManager()->bitBltWane8(&tempSprite, (PixMap *)_engine->getGraphicsManager()->_screenSurface.getPixels()); _engine->getGraphicsManager()->unlockSurface(); } break; case 4: if (_engine->getGraphicsManager()->acquireSurface()) { _engine->getGraphicsManager()->bitBltWane16(&tempSprite, (PixMap *)_engine->getGraphicsManager()->_screenSurface.getPixels()); _engine->getGraphicsManager()->unlockSurface(); } break; case 5: if (_engine->getGraphicsManager()->acquireSurface()) { _engine->getGraphicsManager()->bitBltWane32(&tempSprite, (PixMap *)_engine->getGraphicsManager()->_screenSurface.getPixels()); _engine->getGraphicsManager()->unlockSurface(); } break; case 7: if (_engine->getGraphicsManager()->acquireSurface()) { _engine->getGraphicsManager()->bitBltWane128(&tempSprite, (PixMap *)_engine->getGraphicsManager()->_screenSurface.getPixels()); _engine->getGraphicsManager()->unlockSurface(); } break; default: return; } } void NISManager::showNISStatus(int32 status) { if (status != -1) _nisStatus = status; } bool NISManager::doNIS(const char *name, int32 flags) { if (_engine->isGoldEdition()) return true; Slot *slot; if (_engine->mouseHasRightClicked()) return false; if (!initNIS(name, flags)) return false; for (slot = _engine->getSoundManager()->_soundCache; slot; slot = slot->getNext()) { if (slot->hasTag(kSoundTagNIS)) break; } if (slot) { _currentNISSound = slot; slot->addStatusFlag(kSoundFlagKeepAfterFinish); } for (int i = 0; i < 30; i++) { loadChunk(32); } _savedMouseEventHandle = _engine->getMessageManager()->getEventHandle(1); _savedTimerEventHandle = _engine->getMessageManager()->getEventHandle(3); _engine->getMessageManager()->setEventHandle(kEventChannelMouse, &LastExpressEngine::nisMouseWrapper); _engine->getMessageManager()->setEventHandle(kEventChannelTimer, &LastExpressEngine::nisTimerWrapper); _engine->getSoundManager()->setSoundDriverTicks(0); _numOfOverlays = 0; for (slot = _engine->getSoundManager()->_soundCache; slot; slot = slot->getNext()) { if (slot->hasTag(kSoundTagNIS)) break; } _currentNISSound = slot; if (slot) { _flags |= (kNisFlagPlaying | kNisFlagHasSound); slot->addStatusFlag(kSoundFlagKeepAfterFinish); } else { _flags = 0; } _engine->getSoundManager()->setSoundDriverTicks(0); if (_engine->mouseHasRightClicked()) { abortNIS(); _flags &= ~kNisFlagPlaying; } for (int i = 0; i < _eventsCount; i++) { if ((_flags & kNisFlagPlaying) == 0) break; if (_events[i].eventTime && _events[i].eventTime + 60 < _engine->getSoundManager()->getSoundDriverTicks()) { _engine->getSoundManager()->addSoundDriverFlags(kSoundDriverNISHasRequestedDelay); _currentNISSound->addStatusFlag(kSoundFlagPauseRequested); loadChunk(32); loadChunk(32); } bool useDriverTicks = false; if ((_currentNISSound->getStatusFlags() & (kSoundFlagCloseRequested | kSoundFlagClosed)) != 0 || _currentNISSound->getTime() <= 1) { useDriverTicks = true; } else { _engine->getSoundManager()->setSoundDriverTicks(_currentNISSound->getTime()); } if ((_flags & kNisFlagPlaying) != 0) { do { if (useDriverTicks) { if (_events[i].eventTime <= _engine->getSoundManager()->getSoundDriverTicks()) break; } else { if (_events[i].eventTime <= _currentNISSound->getTime()) break; } if ((_flags & kNisFlagDataChunksAvailable) != 0) loadChunk(32); showNISStatus(-1); if ((_currentNISSound->getStatusFlags() & kSoundFlagPaused) != 0) { _currentNISSound->removeStatusFlag(kSoundFlagPauseRequested | kSoundFlagPaused); _engine->getSoundManager()->removeSoundDriverFlags(kSoundDriverNISHasRequestedDelay); } _engine->getSoundManager()->soundThread(); _engine->getSubtitleManager()->subThread(); if (!_engine->getMessageManager()->process()) { // Only wait and handle events if we've processed all messages, unlike the original which had a separate thread for input... _engine->waitForTimer(5); } for (slot = _engine->getSoundManager()->_soundCache; slot; slot = slot->getNext()) { if (slot->hasTag(kSoundTagNIS)) break; } _currentNISSound = slot; if (!_backgroundFlag && (_flags & kNisFlagAbortRequested) != 0) _flags &= ~kNisFlagPlaying; } while ((_flags & kNisFlagPlaying) != 0); if ((_flags & kNisFlagPlaying) != 0) { if (_events[i].eventTime) { showNISStatus(_engine->getSoundManager()->getSoundDriverTicks() - _events[i].eventTime); } else { showNISStatus(-1); } processNIS(&_events[i]); while ((_flags & kNisFlagPlaying) != 0) { if (!_engine->getMessageManager()->process()) break; _engine->handleEvents(); _engine->getSubtitleManager()->subThread(); _engine->getSoundManager()->soundThread(); if (!_backgroundFlag && (_flags & kNisFlagAbortRequested) != 0) _flags &= ~kNisFlagPlaying; } } } } if (_currentNISSound && !_currentNISSound->getTime()) _currentNISSound->addStatusFlag(kSoundFlagCloseRequested); _engine->getMessageManager()->setEventHandle(kEventChannelMouse, _savedMouseEventHandle); _engine->getMessageManager()->setEventHandle(kEventChannelTimer, _savedTimerEventHandle); if (_currentNISSound && (_flags & kNisFlagAbortRequested) != 0) _currentNISSound->addStatusFlag(kSoundFlagCloseRequested); if (_currentNISSound) { if (_currentNISSound->getSubtitle()) { _currentNISSound->getSubtitle()->kill(); _engine->getSubtitleManager()->subThread(); } _currentNISSound->removeStatusFlag(kSoundFlagKeepAfterFinish); } if (_chainedSoundSlot && (_chainedSoundSlot->getStatusFlags() & (kSoundFlagPlayRequested | kSoundFlagPlaying)) == 0) { do { _engine->getSoundManager()->soundThread(); _engine->handleEvents(); } while ((_chainedSoundSlot->getStatusFlags() & (kSoundFlagPlayRequested | kSoundFlagPlaying)) == 0); } endNIS(); _engine->getMemoryManager()->freeSeqMem(); _flags = 0; if ((flags & kNisFlagSoundFade) != 0) _engine->getSoundManager()->NISFadeIn(); return true; } void NISManager::processNIS(NisEvents *event) { int32 x = _engine->getGraphicsManager()->_renderBox1.x; int32 width = _engine->getGraphicsManager()->_renderBox1.width; debug(2, "NISManager::processNIS(): event at time %d type %d size %d", event->eventTime, event->eventType, event->eventSize); switch (event->eventType) { case kNISEventBackground1: // 10 getStream(_background1ByteStream, event->eventSize); convertNSPR16(_background1ByteStream, _background1); if (_backgroundType == 1) _backgroundType = 0; return; case kNISEventSelectBackground1: // 11 _selectBackgroundType = 1; return; case kNISEventBackground2: // 12 _background2ByteStream = (_background1ByteStream + ((_background1Offset - event->eventSize) & 0xFFFFFFF0)); getStream(_background2ByteStream, event->eventSize); convertNSPR16(_background2ByteStream, _background2); if (_backgroundType == 2) _backgroundType = 0; return; case kNISEventSelectBackground2: // 13 _selectBackgroundType = 2; return; case kNISEventOverlay: // 20 if (!_decompressToBackBuffer) { addBounds(_spriteExtent); } _waxWaneToggleFlag = !_waxWaneToggleFlag; if (_waxWaneToggleFlag) { _waxSpriteByteStream = (_waneSpriteByteStream + ((_waneSpriteOffset - event->eventSize) & 0xFFFFFFF0)); getStream(_waxSpriteByteStream, event->eventSize); convertNSPR16(_waxSpriteByteStream, _waxSprite); } else { getStream(_waneSpriteByteStream, event->eventSize); convertNSPR16(_waneSpriteByteStream, _waneSprite); } _numOfOverlays++; return; case kNISEventUpdate: // 21 _backgroundFlag = 0; if (_decompressToBackBuffer) _engine->getGraphicsManager()->clear(_engine->getGraphicsManager()->_backBuffer, 0, 0, 640, 480); if (_selectBackgroundType != _backgroundType) { drawBK(_selectBackgroundType); } else if (_engine->getGraphicsManager()->acquireSurface()) { if (_backgroundType == 1) { _engine->getGraphicsManager()->copy( _engine->getGraphicsManager()->_backBuffer, (PixMap *)_engine->getGraphicsManager()->_screenSurface.getPixels(), _background1->rect.left, _background1->rect.top, _background1->rect.right - _background1->rect.left + 1, _background1->rect.bottom - _background1->rect.top + 1 ); } else if (_backgroundType == 2) { _engine->getGraphicsManager()->copy( _engine->getGraphicsManager()->_backBuffer, (PixMap *)_engine->getGraphicsManager()->_screenSurface.getPixels(), _background2->rect.left, _background2->rect.top, _background2->rect.right - _background2->rect.left + 1, _background2->rect.bottom - _background2->rect.top + 1 ); } _engine->getGraphicsManager()->unlockSurface(); } if (!_decompressToBackBuffer) { addBounds(_spriteExtent); } if (_waxWaneToggleFlag) { if (_waxSprite->rect.left != 640) drawSprite(_waxSprite); _spriteExtent.left = _waxSprite->rect.left; _spriteExtent.right = _waxSprite->rect.right; _spriteExtent.top = _waxSprite->rect.top; _spriteExtent.bottom = _waxSprite->rect.bottom; _spriteExtent.width = _waxSprite->rect.width; _spriteExtent.height = _waxSprite->rect.height; } else { if (_waneSprite->rect.left != 640) drawSprite(_waneSprite); _spriteExtent.left = _waneSprite->rect.left; _spriteExtent.right = _waneSprite->rect.right; _spriteExtent.top = _waneSprite->rect.top; _spriteExtent.bottom = _waneSprite->rect.bottom; _spriteExtent.width = _waneSprite->rect.width; _spriteExtent.height = _waneSprite->rect.height; } if (_firstNISBackgroundDraw) { _engine->getGraphicsManager()->burstBox(80, 0, 480, 480); } else { _engine->getGraphicsManager()->burstBox( _nisRect.left, _nisRect.top, _nisRect.right - _nisRect.left + 1, _nisRect.bottom - _nisRect.top + 1 ); } _engine->getSoundManager()->soundThread(); _firstNISBackgroundDraw = 0; if (_decompressToBackBuffer) { for (int i = 0; i < 3; i++) { _engine->getSoundManager()->soundThread(); _engine->getGraphicsManager()->dissolve((2 * x) + (2 * (i & 1)), width, 480, _engine->getGraphicsManager()->_backBuffer); _engine->getGraphicsManager()->burstBox(x, 0, width, 480); _engine->getSoundManager()->soundThread(); _engine->handleEvents(); } if (_engine->getGraphicsManager()->acquireSurface()) { _engine->getGraphicsManager()->copy(_engine->getGraphicsManager()->_backBuffer, (PixMap *)_engine->getGraphicsManager()->_screenSurface.getPixels(), x, 0, width, 480); _engine->getGraphicsManager()->unlockSurface(); } _engine->getGraphicsManager()->burstBox(x, 0, width, 480); _engine->getSoundManager()->soundThread(); if (_backgroundType == 1) { drawSprite(_background1); } else { drawSprite(_background2); } _decompressToBackBuffer = 0; _currentNISSound->play(); _engine->getSoundManager()->setSoundDriverTicks(0); } clearBounds(); return; case kNISEventUpdateTransition: // 22 _backgroundFlag = 1; if (_selectBackgroundType != _backgroundType) { drawBK(_selectBackgroundType); } else { if (_engine->getGraphicsManager()->acquireSurface()) { if (_backgroundType == 1) { _engine->getGraphicsManager()->copy( _engine->getGraphicsManager()->_backBuffer, (PixMap *)_engine->getGraphicsManager()->_screenSurface.getPixels(), _background1->rect.left, _background1->rect.top, _background1->rect.right - _background1->rect.left + 1, _background1->rect.bottom - _background1->rect.top + 1 ); } else if (_backgroundType == 2) { _engine->getGraphicsManager()->copy( _engine->getGraphicsManager()->_backBuffer, (PixMap *)_engine->getGraphicsManager()->_screenSurface.getPixels(), _background2->rect.left, _background2->rect.top, _background2->rect.right - _background2->rect.left + 1, _background2->rect.bottom - _background2->rect.top + 1 ); } _engine->getGraphicsManager()->unlockSurface(); } } waxSprite(_waxSprite); waneSprite(_waneSprite); _engine->getGraphicsManager()->burstBox( _nisRect.left, _nisRect.top, _nisRect.right - _nisRect.left + 1, _nisRect.bottom - _nisRect.top + 1 ); _engine->getSoundManager()->soundThread(); clearBounds(); return; case kNISEventSound1: // 30 case kNISEventSound2: // 31 _currentNISSound->setFade(event->eventSize); return; case kNISEventAudioData: // 32 _cumulativeEventSize += event->eventSize; while (_currentNISSound->getSize() + NIS_SOUND_CHUNK_SIZE * _currentNISSound->getTime() + 745 <= (event->eventSize + _currentNISSound->getNumLoadedBytes())) _engine->getSoundManager()->soundThread(); loadSnd(event->eventSize); if ((_flags & kNisFlagSoundInitialized) == 0) { _flags |= kNisFlagSoundInitialized; _currentNISSound->setBlockCount(READ_LE_UINT16((uint16 *)_currentNISSound->getDataStart() + 2) - 1); _currentNISSound->setSize(0x16000); } return; default: return; } } void NISManager::drawBK(int type) { Extent rect; rect.left = 80; rect.right = 559; rect.bottom = 479; rect.top = 0; rect.width = 0; rect.height = 0; if (!_decompressToBackBuffer && _engine->getGraphicsManager()->acquireSurface()) { _engine->getGraphicsManager()->clear(_engine->getGraphicsManager()->_screenSurface, 80, 0, 480, 480); _engine->getGraphicsManager()->unlockSurface(); } if (type == 1) { drawSprite(_background1); } else { drawSprite(_background2); } _firstNISBackgroundDraw = true; if (!_decompressToBackBuffer && _engine->getGraphicsManager()->acquireSurface()) { _engine->getGraphicsManager()->copy((PixMap *)_engine->getGraphicsManager()->_screenSurface.getPixels(), _engine->getGraphicsManager()->_backBuffer, 0, 0, 640, 480); _engine->getGraphicsManager()->unlockSurface(); } addBounds(rect); _backgroundType = type; } void NISManager::getNISSlot() { // This slot will automatically be included in the queue Slot *slot = new Slot(_engine->getSoundManager(), kSoundTypeNIS | kSoundFlagCyclicBuffer | kVolumeFull, 90); slot->setCurrentBufferPtr(slot->getSoundBuffer()); slot->setDataStart(slot->getSoundBuffer()); slot->setDataEnd(slot->getSoundBuffer() + (44 * MEM_PAGE_SIZE)); slot->setCurrentDataPtr(slot->getDataStart() + 6); slot->setSize(44 * MEM_PAGE_SIZE); } Slot *NISManager::getChainedSound() { return _chainedSoundSlot; } void NISManager::setChainedSound(Slot *slot) { _chainedSoundSlot = slot; } int32 NISManager::getNISFlag() { return _flags; } } // End of namespace LastExpress