From f01f9343c831cda618dabd2dcda7be77b2948ecc Mon Sep 17 00:00:00 2001 From: johndoe123 Date: Fri, 1 Jul 2011 10:25:55 +0000 Subject: NEVERHOOD: Start with AnimatedSprite and AnimResource --- engines/neverhood/graphics.h | 3 + engines/neverhood/neverhood.cpp | 9 +- engines/neverhood/resource.cpp | 153 +++++++++++++++++++++ engines/neverhood/resource.h | 38 ++++++ engines/neverhood/sprite.cpp | 287 ++++++++++++++++++++++++++++++++++++++-- engines/neverhood/sprite.h | 55 +++++++- 6 files changed, 533 insertions(+), 12 deletions(-) diff --git a/engines/neverhood/graphics.h b/engines/neverhood/graphics.h index 68ff84dc25..cb7474c78d 100644 --- a/engines/neverhood/graphics.h +++ b/engines/neverhood/graphics.h @@ -62,6 +62,9 @@ public: void drawSpriteResource(SpriteResource &spriteResource); int getPriority() const { return _priority; } void setPriority(int priority) { _priority = priority; } + NDrawRect& getDrawRect() { return _drawRect; } + NDrawRect& getSysRect() { return _sysRect; } + NRect& getClipRect() { return _clipRect; } protected: NeverhoodEngine *_vm; int _priority; diff --git a/engines/neverhood/neverhood.cpp b/engines/neverhood/neverhood.cpp index d4418cb8cd..2f27fca2df 100644 --- a/engines/neverhood/neverhood.cpp +++ b/engines/neverhood/neverhood.cpp @@ -112,7 +112,7 @@ Common::Error NeverhoodEngine::run() { _res->unuseResource(resourceHandle); #endif -#if 1 +#if 0 { // Create a new scope SpriteResource r(this); BaseSurface *surf = new BaseSurface(this, 0, 640, 480); @@ -123,6 +123,13 @@ Common::Error NeverhoodEngine::run() { } #endif +#if 1 + { // Create a new scope + AnimResource r(this); + r.load(0x000540B0); + } +#endif + delete _res; return Common::kNoError; diff --git a/engines/neverhood/resource.cpp b/engines/neverhood/resource.cpp index 4dcbd838fe..84eab7fe0e 100644 --- a/engines/neverhood/resource.cpp +++ b/engines/neverhood/resource.cpp @@ -25,6 +25,8 @@ namespace Neverhood { +// SpriteResource + SpriteResource::SpriteResource(NeverhoodEngine *vm) : _vm(vm), _resourceHandle(-1), _pixels(NULL) { } @@ -87,6 +89,8 @@ void SpriteResource::unload() { _rle = false; } +// PaletteResource + PaletteResource::PaletteResource(NeverhoodEngine *vm) : _vm(vm), _resourceHandle(-1), _palette(NULL) { } @@ -134,4 +138,153 @@ void PaletteResource::copyPalette(byte *destPalette) { } } +// AnimResource + +AnimResource::AnimResource(NeverhoodEngine *vm) + : _vm(vm), _width(0), _height(0), _currSpriteData(NULL) { + + clear(); + clear2(); +} + +AnimResource::~AnimResource() { + unloadInternal(); +} + +bool AnimResource::load(uint32 fileHash) { + + if (fileHash == _fileHash) + return true; + + unload(); + _resourceHandle = _vm->_res->useResource(fileHash); + if (_resourceHandle == -1) + return false; + + byte *resourceData, *animList, *frameList; + uint16 animInfoStartOfs, animListIndex, animListCount; + uint16 frameListStartOfs, frameCount; + uint32 spriteDataOfs, paletteDataOfs; + + if (_vm->_res->getResourceType(_resourceHandle) != 4) { + _vm->_res->unuseResource(_resourceHandle); + _resourceHandle = -1; + return false; + } + + resourceData = _vm->_res->loadResource(_resourceHandle); + if (!resourceData) { + _vm->_res->unuseResource(_resourceHandle); + _resourceHandle = -1; + return false; + } + + animListCount = READ_LE_UINT16(resourceData); + animInfoStartOfs = READ_LE_UINT16(resourceData + 2); + spriteDataOfs = READ_LE_UINT32(resourceData + 4); + paletteDataOfs = READ_LE_UINT32(resourceData + 8); + + animList = resourceData + 12; + for (animListIndex = 0; animListIndex < animListCount; animListIndex++) { + debug("hash: %08X", READ_LE_UINT32(animList)); + if (READ_LE_UINT32(animList) == fileHash) + break; + animList += 8; + } + + if (animListIndex >= animListCount) { + _vm->_res->unloadResource(_resourceHandle); + _vm->_res->unuseResource(_resourceHandle); + _resourceHandle = -1; + return false; + } + + _spriteData = resourceData + spriteDataOfs; + if (paletteDataOfs > 0) + _paletteData = resourceData + paletteDataOfs; + + frameCount = READ_LE_UINT16(animList + 4); + frameListStartOfs = READ_LE_UINT16(animList + 6); + + debug("frameCount = %d; frameListStartOfs = %04X; animInfoStartOfs = %04X", frameCount, frameListStartOfs, animInfoStartOfs); + + frameList = resourceData + animInfoStartOfs + frameListStartOfs; + + _frames.clear(); + _frames.reserve(frameCount); + + for (uint16 frameIndex = 0; frameIndex < frameCount; frameIndex++) { + AnimFrameInfo frameInfo; + frameInfo.frameHash = READ_LE_UINT32(frameList); + frameInfo.counter = READ_LE_UINT16(frameList + 4); + frameInfo.rect.x1 = READ_LE_UINT16(frameList + 6); + frameInfo.rect.y1 = READ_LE_UINT16(frameList + 8); + frameInfo.rect.x2 = READ_LE_UINT16(frameList + 10); + frameInfo.rect.y2 = READ_LE_UINT16(frameList + 12); + frameInfo.deltaX = READ_LE_UINT16(frameList + 14); + frameInfo.deltaY = READ_LE_UINT16(frameList + 16); + frameInfo.deltaRect.x = READ_LE_UINT16(frameList + 18); + frameInfo.deltaRect.y = READ_LE_UINT16(frameList + 20); + frameInfo.deltaRect.width = READ_LE_UINT16(frameList + 22); + frameInfo.deltaRect.height = READ_LE_UINT16(frameList + 24); + frameInfo.field_1A = READ_LE_UINT16(frameList + 26); + frameInfo.spriteDataOffs = READ_LE_UINT32(frameList + 28); + debug("frameHash = %08X; counter = %d; rect = (%d,%d,%d,%d); deltaX = %d; deltaY = %d; deltaRect = (%d,%d,%d,%d); field_1A = %04X; spriteDataOffs = %08X", + frameInfo.frameHash, frameInfo.counter, + frameInfo.rect.x1, frameInfo.rect.y1, frameInfo.rect.x2, frameInfo.rect.y2, + frameInfo.deltaX, frameInfo.deltaY, + frameInfo.deltaRect.x, frameInfo.deltaRect.y, frameInfo.deltaRect.width, frameInfo.deltaRect.height, + frameInfo.field_1A, frameInfo.spriteDataOffs); + frameList += 32; + _frames.push_back(frameInfo); + } + + _fileHash = fileHash; + + return true; + +} + +void AnimResource::unload() { + if (_resourceHandle != -1) { + _vm->_res->unloadResource(_resourceHandle); + _vm->_res->unuseResource(_resourceHandle); + clear(); + } +} + +void AnimResource::clear() { + _resourceHandle = -1; + // _count = 0; + // _infoStructs = NULL; + _currSpriteData = NULL; + _fileHash = 0; + _paletteData = NULL; + _spriteData = NULL; +} + +void AnimResource::clear2() { + clear(); + _replEnabled = true; + _replOldByte = 0; + _replNewByte = 0; +} + +bool AnimResource::loadInternal(uint32 fileHash) { + unloadInternal(); + return load(fileHash); +} + +void AnimResource::unloadInternal() { + unload(); + clear2(); +} + +int16 AnimResource::getFrameIndex(uint32 frameHash) { + for (uint i = 0; i < _frames.size(); i++) + if (_frames[i].frameHash == frameHash) + return (int16)i; + return -1; +} + } // End of namespace Neverhood diff --git a/engines/neverhood/resource.h b/engines/neverhood/resource.h index 5a30d1292d..8cab1eb565 100644 --- a/engines/neverhood/resource.h +++ b/engines/neverhood/resource.h @@ -61,6 +61,44 @@ protected: byte *_palette; }; +struct AnimFrameInfo { + uint32 frameHash; + int16 counter; + NRect rect; + int16 deltaX, deltaY; + NDrawRect deltaRect; + uint16 field_1A; + uint32 spriteDataOffs; +}; + +class AnimResource { +public: + AnimResource(NeverhoodEngine *vm); + ~AnimResource(); + bool load(uint32 fileHash); + void unload(); + void clear(); + void clear2(); + bool loadInternal(uint32 fileHash); + void unloadInternal(); + uint getFrameCount() const { return _frames.size(); } + const AnimFrameInfo& getFrameInfo(int16 index) const { return _frames[index]; } + int16 getFrameIndex(uint32 frameHash); +protected: + NeverhoodEngine *_vm; + int _resourceHandle; + int16 _width, _height; + byte *_currSpriteData; + uint32 _fileHash; + byte *_paletteData; + byte *_spriteData; + bool _replEnabled; + byte _replOldByte; + byte _replNewByte; + Common::Array _frames; +}; + + } // End of namespace Neverhood #endif /* NEVERHOOD_RESOURCE_H */ diff --git a/engines/neverhood/sprite.cpp b/engines/neverhood/sprite.cpp index 6ee0a6633c..0157673250 100644 --- a/engines/neverhood/sprite.cpp +++ b/engines/neverhood/sprite.cpp @@ -30,7 +30,6 @@ Sprite::Sprite(NeverhoodEngine *vm, int objectPriority) : Entity(vm, objectPriority), _x(0), _y(0), _spriteUpdateCb(NULL), _filterXCb(NULL), _filterYCb(NULL), _doDeltaX(false), _doDeltaY(false), _needRedraw(false), - _deltaX1(0), _deltaY1(0), _deltaX2(0), _deltaY2(0), _flags(0) { SetMessageHandler(&Sprite::handleMessage); @@ -43,18 +42,18 @@ Sprite::~Sprite() { void Sprite::processDelta() { if (_doDeltaX) { - _rect.x1 = _x - _deltaX1 - _deltaX2 + 1; - _rect.x2 = _x - _deltaX1; + _rect.x1 = _x - _deltaRect.x - _deltaRect.width + 1; + _rect.x2 = _x - _deltaRect.x; } else { - _rect.x1 = _x + _deltaX1; - _rect.x2 = _x + _deltaX1 + _deltaX2 - 1; + _rect.x1 = _x + _deltaRect.x; + _rect.x2 = _x + _deltaRect.x + _deltaRect.width - 1; } if (_doDeltaY) { - _rect.y1 = _y - _deltaY1 - _deltaY2 + 1; - _rect.y2 = _y - _deltaY1; + _rect.y1 = _y - _deltaRect.y - _deltaRect.height + 1; + _rect.y2 = _y - _deltaRect.y; } else { - _rect.y1 = _y + _deltaY1; - _rect.y2 = _y + _deltaY1 + _deltaY2 - 1; + _rect.y1 = _y + _deltaRect.y; + _rect.y2 = _y + _deltaRect.y + _deltaRect.height - 1; } } @@ -176,4 +175,274 @@ void StaticSprite::load(uint32 fileHash, bool dimensions, bool position) { } +// AnimatedSprite + +AnimatedSprite::AnimatedSprite(NeverhoodEngine *vm, int objectPriority) + : Sprite(vm, objectPriority), _animResource(vm) { + + init(); +} + +AnimatedSprite::AnimatedSprite(NeverhoodEngine *vm, uint32 fileHash, int surfacePriority, int16 x, int16 y) + : Sprite(vm, 1100), _animResource(vm) { + + init(); + SetUpdateHandler(&AnimatedSprite::update); + createSurface1(fileHash, surfacePriority); + _x = x; + _y = y; + setFileHash(fileHash, 0, -1); + +} + +void AnimatedSprite::init() { + _counter = 0; + _fileHash1 = 0; + _deltaX = 0; + _deltaY = 0; + _fileHash2 = 0; + // TODO _callbackList = 0; + _frameIndex3 = 0; + // TODO _callback3 = 0; + _frameIndex = 0; + _hashListIndex = -1; + // TODO _callback2 = 0; + _newHashListIndex = -1; + // TODO _callback1 = 0; + _fileHash4 = 0; + _flag = false; + _replOldByte = 0; + _replNewByte = 0; + // TODO _animResource.replEnabled = 0; + _playBackwards = 0; +} + +void AnimatedSprite::update() { + updateAnim(); + handleSpriteUpdate(); + updatePosition(); +} + +void AnimatedSprite::updateDeltaXY() { + if (_doDeltaX) { + _x -= _deltaX; + } else { + _x += _deltaX; + } + if (_doDeltaY) { + _y -= _deltaY; + } else { + _y += _deltaY; + } + _deltaX = 0; + _deltaY = 0; + processDelta(); +} + +void AnimatedSprite::updateAnim() { + + _flag = false; + + if (_fileHash1 == 0) { + if (_newHashListIndex != -1) { + _hashListIndex = _newHashListIndex == -2 ? _animResource.getFrameCount() - 1 : _newHashListIndex; + _newHashListIndex = -1; + } else if (_fileHash4 != 0) { + _hashListIndex = MAX(0, _animResource.getFrameIndex(_fileHash4)); + _fileHash4 = 0; + } + if (_fileHash1 == 0 && _frameIndex != _hashListIndex) { + if (_counter != 0) + _counter--; + if (_counter == 0 && _animResource.getFrameCount() != 0) { + + if (_fileHash2 != 0) { + if (_animResource.loadInternal(_fileHash2)) { + _fileHash3 = _fileHash2; + } else { + // TODO _animResource.loadInternal(calcHash("sqDefault")); + _fileHash3 = 0; + } + // loc_43831D + if (_replNewByte != _replOldByte) { + // TODO _animResource.setRepl(_replOldByte, _replNewByte); + } + _fileHash2 = 0; + if (_status != 0) { + _frameIndex = _fileHash6 != 0 ? MAX(0, _animResource.getFrameIndex(_fileHash6)) : 0; + _frameIndex2 = _fileHash5 != 0 ? MAX(0, _animResource.getFrameIndex(_fileHash5)) : _animResource.getFrameCount() - 1; + } else { + _frameIndex = _frameIndex3 != -1 ? _frameIndex3 : _animResource.getFrameCount() - 1; + _frameIndex2 = _frameIndex4 != -1 ? _frameIndex4 : _animResource.getFrameCount() - 1; + } + } else { + // TODO updateFrameIndex(); + } + if (_fileHash1 == 0) + updateFrameInfo(); + } + } + } + + if (_fileHash1 != 0) { + if (_status == 2) { + _hashListIndex = _frameIndex; + } else { + if (_status == 1) { + if (_animResource.loadInternal(_fileHash1)) { + _fileHash3 = _fileHash1; + } else { + // TODO _animResource.loadInternal(calcHash("sqDefault")); + _fileHash3 = 0; + } + if (_replNewByte != _replOldByte) { + // TODO _animResource.setRepl(_replOldByte, _replNewByte); + } + _fileHash1 = 0; + _frameIndex = _fileHash6 != 0 ? MAX(0, _animResource.getFrameIndex(_fileHash6)) : 0; + _frameIndex2 = _fileHash5 != 0 ? MAX(0, _animResource.getFrameIndex(_fileHash5)) : _animResource.getFrameCount() - 1; + } else { + if (_animResource.loadInternal(_fileHash1)) { + _fileHash3 = _fileHash1; + } else { + // TODO _animResource.loadInternal(calcHash("sqDefault")); + _fileHash3 = 0; + } + if (_replNewByte != _replOldByte) { + // TODO _animResource.setRepl(_replOldByte, _replNewByte); + } + _fileHash1 = 0; + _frameIndex = _frameIndex3 != -1 ? _frameIndex3 : _animResource.getFrameCount() - 1; + _frameIndex2 = _frameIndex4 != -1 ? _frameIndex4 : _animResource.getFrameCount() - 1; + } + updateFrameInfo(); + } + + if (_newHashListIndex != -1) { + _hashListIndex = _newHashListIndex == -2 ? _animResource.getFrameCount() - 1 : _newHashListIndex; + _newHashListIndex = -1; + } else if (_fileHash4 != 0) { + _hashListIndex = MAX(0, _animResource.getFrameIndex(_fileHash4)); + _fileHash4 = 0; + } + + } + +} + +void AnimatedSprite::updatePosition() { + + if (!_surface) + return; + + if (_doDeltaX) { + _surface->getDrawRect().x = filterX(_x - _rect1.x1 - _rect1.x2 + 1); + } else { + _surface->getDrawRect().x = filterX(_x + _rect1.x1); + } + + if (_doDeltaY) { + _surface->getDrawRect().y = filterY(_y - _rect1.y1 - _rect1.y2 + 1); + } else { + _surface->getDrawRect().y = filterY(_y + _rect1.y1); + } + + if (_needRedraw) { + // TODO _surface->drawAnimResource(_animResource, _frameIndex, _doDeltaX, _doDeltaY, _rect1.x2, _rect1.y2); + _needRedraw = false; + } + +} + +void AnimatedSprite::updateFrameIndex() { + if (!_playBackwards) { + if (_frameIndex < _frameIndex2) { + _frameIndex++; + } else { + // Inform self about end of current animation + // The caller can then e.g. set a new animation fileHash + sendMessage(0x3002, 0, this); + if (_fileHash1 == 0) + _frameIndex = 0; + } + } else { + if (_frameIndex > 0) { + _frameIndex--; + } else { + sendMessage(0x3002, 0, this); + if (_fileHash1 == 0) + _frameIndex = _frameIndex2; + } + } +} + +void AnimatedSprite::updateFrameInfo() { + + const AnimFrameInfo &frameInfo = _animResource.getFrameInfo(_frameIndex); + + _flag = true; + _rect1 = frameInfo.rect; + _deltaX = frameInfo.deltaX; + _deltaY = frameInfo.deltaY; + _deltaRect = frameInfo.deltaRect; + _counter = frameInfo.counter; + + processDelta(); + + _needRedraw = true; + + if (frameInfo.frameHash != 0) { + sendMessage(0x100D, frameInfo.frameHash, this); + } + +} + +void AnimatedSprite::createSurface1(uint32 fileHash, int surfacePriority) { + NDimensions dimensions; + // TODO dimensions = getAnimatedSpriteDimensions(fileHash); + dimensions.width = 640; + dimensions.height = 480; + _surface = new BaseSurface(_vm, surfacePriority, dimensions.width, dimensions.height); +} + +void AnimatedSprite::setFileHash(uint32 fileHash, int16 frameIndex3, int16 frameIndex4) { + _fileHash1 = fileHash; + _frameIndex3 = frameIndex3; + _frameIndex4 = frameIndex4; + _fileHash4 = 0; + _status = 0; + _playBackwards = false; + _newHashListIndex = -1; + _hashListIndex = -1; +} + +void AnimatedSprite::setFileHash1() { + _fileHash1 = 1; + _status = 2; +} + +void AnimatedSprite::setFileHash2(uint32 fileHash, uint32 fileHash6, uint32 fileHash5) { + _fileHash1 = fileHash; + _fileHash6 = fileHash6; + _fileHash5 = fileHash5; + _fileHash4 = 0; + _status = 1; + _playBackwards = false; + _newHashListIndex = -1; + _hashListIndex = -1; +} + +void AnimatedSprite::setFileHash3(uint32 fileHash2, uint32 fileHash6, uint32 fileHash5) { + _fileHash2 = fileHash2; + _fileHash6 = fileHash6; + _fileHash5 = fileHash5; + _fileHash4 = 0; + _status = 1; + _playBackwards = false; + _newHashListIndex = -1; + _hashListIndex = -1; +} + + + } // End of namespace Neverhood diff --git a/engines/neverhood/sprite.h b/engines/neverhood/sprite.h index c2ed720fb0..708228ca2f 100644 --- a/engines/neverhood/sprite.h +++ b/engines/neverhood/sprite.h @@ -56,8 +56,7 @@ protected: //0000002B field_2B db ? //0000002C field2C dd ? // unused NRect _rect1; - int16 _deltaX1, _deltaY1; - int16 _deltaX2, _deltaY2; + NDrawRect _deltaRect; NRect _rect; uint16 _flags; //0000004A field4A dw ? // seems to be unused except in ctor @@ -65,6 +64,10 @@ protected: //void update(); uint32 handleMessage(int messageNum, const MessageParam ¶m, Entity *sender); void createSurface(int surfacePriority, int16 width, int16 height); + void handleSpriteUpdate() { + if (_spriteUpdateCb) + (this->*_spriteUpdateCb)(); + } int16 filterX(int16 x) { return _filterXCb ? (this->*_filterXCb)(x) : x; } @@ -85,6 +88,54 @@ protected: void update(); }; +class AnimatedSprite : public Sprite { +public: + AnimatedSprite(NeverhoodEngine *vm, int objectPriority); + AnimatedSprite(NeverhoodEngine *vm, uint32 fileHash, int surfacePriority, int16 x, int16 y); +protected: + AnimResource _animResource; + uint32 _fileHash1; + uint32 _fileHash2; + uint32 _fileHash3; + int16 _frameIndex; + int16 _frameIndex3; + int16 _frameIndex2; + int16 _frameIndex4; + uint32 _fileHash6; + uint32 _fileHash5; + int16 _status; + int16 _counter; + int _hashListIndex; + int _newHashListIndex; + uint32 _fileHash4; + int16 _deltaX, _deltaY; + byte _replOldByte; + byte _replNewByte; + bool _playBackwards; + bool _flag; + /* TODO + callbackListIndex dw ? + callbackListCount dw ? + callbackList dd ? + callback3 dd ? + callback2 dd ? + callback1 dd ? + */ + void init(); + void update(); + void updateDeltaXY(); + void updateAnim(); + void updatePosition(); + void updateFrameIndex(); + void updateFrameInfo(); + void createSurface1(uint32 fileHash, int surfacePriority); + void setFileHash(uint32 fileHash, int16 frameIndex3, int16 frameIndex4); + void setFileHash1(); + void setFileHash2(uint32 fileHash, uint32 fileHash6, uint32 fileHash5); + void setFileHash3(uint32 fileHash2, uint32 fileHash6, uint32 fileHash5); + int16 getHashListIndex(uint32 fileHash) { return 0; } // TODO !!! +}; + } // End of namespace Neverhood #endif /* NEVERHOOD_SPRITE_H */ -- cgit v1.2.3