PageRenderTime 43ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/engines/access/animation.cpp

http://github.com/scummvm/scummvm
C++ | 352 lines | 252 code | 68 blank | 32 comment | 58 complexity | 53569a9337701b0435000e124419eee0 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.1, GPL-2.0
  1. /* ScummVM - Graphic Adventure Engine
  2. *
  3. * ScummVM is the legal property of its developers, whose names
  4. * are too numerous to list here. Please refer to the COPYRIGHT
  5. * file distributed with this source distribution.
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * as published by the Free Software Foundation; either version 2
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  20. *
  21. */
  22. #include "common/endian.h"
  23. #include "common/memstream.h"
  24. #include "access/access.h"
  25. #include "access/animation.h"
  26. namespace Access {
  27. AnimationResource::AnimationResource(AccessEngine *vm, Resource *res) {
  28. int count = res->_stream->readUint16LE();
  29. Common::Array<int> offsets;
  30. for (int i = 0; i < count; ++i)
  31. offsets.push_back(res->_stream->readUint32LE());
  32. _animations.reserve(count);
  33. for (int i = 0; i < count; ++i) {
  34. res->_stream->seek(offsets[i]);
  35. Animation *anim = new Animation(vm, res->_stream);
  36. _animations.push_back(anim);
  37. }
  38. }
  39. AnimationResource::~AnimationResource() {
  40. for (int i = 0; i < (int)_animations.size(); ++i)
  41. delete _animations[i];
  42. }
  43. /*------------------------------------------------------------------------*/
  44. Animation::Animation(AccessEngine *vm, Common::SeekableReadStream *stream) : Manager(vm) {
  45. uint32 startOfs = stream->pos();
  46. _type = stream->readByte();
  47. // WORKAROUND: In Amazon floppy English, there's an animation associated with
  48. // the librarian that isn't used, and has junk data. Luckily, it's animation
  49. // type is also invalid, so if the _type isn't in range, exit immediately
  50. if (_type < 0 || _type > 7) {
  51. _scaling = -1;
  52. _frameNumber = -1;
  53. _initialTicks = _countdownTicks = 0;
  54. _loopCount = _currentLoopCount = 0;
  55. return;
  56. }
  57. _scaling = stream->readSByte();
  58. stream->readByte(); // unk
  59. _frameNumber = stream->readByte();
  60. _initialTicks = stream->readUint16LE();
  61. stream->readUint16LE(); // unk
  62. stream->readUint16LE(); // unk
  63. _loopCount = stream->readSint16LE();
  64. _countdownTicks = stream->readUint16LE();
  65. _currentLoopCount = stream->readSint16LE();
  66. stream->readUint16LE(); // unk
  67. Common::Array<uint16> frameOffsets;
  68. uint16 ofs;
  69. while ((ofs = stream->readUint16LE()) != 0)
  70. frameOffsets.push_back(ofs);
  71. for (int i = 0; i < (int)frameOffsets.size(); i++) {
  72. stream->seek(startOfs + frameOffsets[i]);
  73. AnimationFrame *frame = new AnimationFrame(stream, startOfs);
  74. _frames.push_back(frame);
  75. }
  76. }
  77. Animation::~Animation() {
  78. for (uint i = 0; i < _frames.size(); ++i)
  79. delete _frames[i];
  80. }
  81. typedef void(Animation::*AnimationMethodPtr)();
  82. void Animation::animate() {
  83. static const AnimationMethodPtr METHODS[8] = {
  84. &Animation::anim0, &Animation::anim1, &Animation::anim2, &Animation::anim3,
  85. &Animation::anim4, &Animation::animNone, &Animation::animNone, &Animation::anim7
  86. };
  87. (this->*METHODS[_type])();
  88. }
  89. void Animation::anim0() {
  90. if (_currentLoopCount != -1) {
  91. if (_countdownTicks != 0) {
  92. setFrame1(calcFrame());
  93. } else {
  94. _countdownTicks = _initialTicks;
  95. ++_frameNumber;
  96. AnimationFrame *frame = calcFrame();
  97. if (frame == nullptr) {
  98. _frameNumber = 0;
  99. _currentLoopCount = -1;
  100. frame = calcFrame();
  101. }
  102. setFrame(frame);
  103. }
  104. }
  105. }
  106. void Animation::anim1() {
  107. if (_currentLoopCount == -1 || _countdownTicks != 0) {
  108. setFrame1(calcFrame());
  109. } else {
  110. _countdownTicks = _initialTicks;
  111. ++_frameNumber;
  112. AnimationFrame *frame = calcFrame();
  113. if (frame == nullptr) {
  114. --_frameNumber;
  115. _currentLoopCount = -1;
  116. frame = calcFrame();
  117. }
  118. setFrame(frame);
  119. }
  120. }
  121. void Animation::anim2() {
  122. if (_countdownTicks != 0) {
  123. setFrame1(calcFrame());
  124. } else {
  125. _countdownTicks = _initialTicks;
  126. ++_frameNumber;
  127. AnimationFrame *frame = calcFrame();
  128. if (frame == nullptr) {
  129. _frameNumber = 0;
  130. frame = calcFrame();
  131. }
  132. setFrame(frame);
  133. }
  134. }
  135. void Animation::anim3() {
  136. if (_currentLoopCount != -1) {
  137. if (_countdownTicks != 0) {
  138. setFrame1(calcFrame());
  139. } else {
  140. _countdownTicks = _initialTicks;
  141. ++_frameNumber;
  142. AnimationFrame *frame = calcFrame();
  143. if (frame == nullptr) {
  144. --_currentLoopCount;
  145. _frameNumber = 0;
  146. frame = calcFrame();
  147. }
  148. setFrame(frame);
  149. }
  150. }
  151. }
  152. void Animation::anim4() {
  153. if (_currentLoopCount == -1 || _countdownTicks != 0) {
  154. setFrame1(calcFrame());
  155. } else {
  156. _countdownTicks = _initialTicks;
  157. ++_frameNumber;
  158. AnimationFrame *frame = calcFrame();
  159. if (frame == nullptr) {
  160. if (--_currentLoopCount == -1) {
  161. setFrame1(calcFrame());
  162. return;
  163. } else {
  164. _frameNumber = 0;
  165. frame = calcFrame();
  166. }
  167. }
  168. setFrame(frame);
  169. }
  170. }
  171. void Animation::animNone() {
  172. // Empty implementation
  173. }
  174. void Animation::anim7() {
  175. setFrame(calcFrame1());
  176. }
  177. AnimationFrame *Animation::calcFrame() {
  178. return (_frameNumber < (int)_frames.size()) ? _frames[_frameNumber] : nullptr;
  179. }
  180. AnimationFrame *Animation::calcFrame1() {
  181. return _frames[0];
  182. }
  183. void Animation::setFrame(AnimationFrame *frame) {
  184. assert(frame);
  185. _countdownTicks += frame->_frameDelay;
  186. setFrame1(frame);
  187. }
  188. void Animation::setFrame1(AnimationFrame *frame) {
  189. _vm->_animation->_base.x = frame->_baseX;
  190. _vm->_animation->_base.y = frame->_baseY;
  191. // Loop to add image draw requests for the parts of the frame
  192. for (uint i = 0; i < frame->_parts.size(); ++i) {
  193. AnimationFramePart *part = frame->_parts[i];
  194. ImageEntry ie;
  195. // Set the flags
  196. ie._flags = part->_flags & ~IMGFLAG_UNSCALED;
  197. if (_vm->_animation->_frameScale == -1)
  198. ie._flags |= IMGFLAG_UNSCALED;
  199. // Set the other fields
  200. ie._spritesPtr = _vm->_objectsTable[part->_spritesIndex];
  201. ie._frameNumber = part->_frameIndex;
  202. ie._position = part->_position + _vm->_animation->_base;
  203. ie._offsetY = part->_offsetY - ie._position.y;
  204. _vm->_images.addToList(ie);
  205. }
  206. }
  207. /*------------------------------------------------------------------------*/
  208. AnimationFrame::AnimationFrame(Common::SeekableReadStream *stream, int startOffset) {
  209. uint16 nextOffset;
  210. stream->readByte(); // unk
  211. _baseX = stream->readUint16LE();
  212. _baseY = stream->readUint16LE();
  213. _frameDelay = stream->readUint16LE();
  214. nextOffset = stream->readUint16LE();
  215. while (nextOffset != 0) {
  216. stream->seek(startOffset + nextOffset);
  217. AnimationFramePart *framePart = new AnimationFramePart(stream);
  218. _parts.push_back(framePart);
  219. nextOffset = stream->readUint16LE();
  220. }
  221. }
  222. AnimationFrame::~AnimationFrame() {
  223. for (int i = 0; i < (int)_parts.size(); ++i)
  224. delete _parts[i];
  225. }
  226. /*------------------------------------------------------------------------*/
  227. AnimationFramePart::AnimationFramePart(Common::SeekableReadStream *stream) {
  228. _flags = stream->readByte();
  229. _spritesIndex = stream->readByte();
  230. _frameIndex = stream->readByte();
  231. _position.x = stream->readUint16LE();
  232. _position.y = stream->readUint16LE();
  233. _offsetY = stream->readUint16LE();
  234. }
  235. /*------------------------------------------------------------------------*/
  236. AnimationManager::AnimationManager(AccessEngine *vm) : Manager(vm) {
  237. _animation = nullptr;
  238. _animStart = nullptr;
  239. _frameScale = 0;
  240. }
  241. AnimationManager::~AnimationManager() {
  242. delete _animation;
  243. }
  244. void AnimationManager::freeAnimationData() {
  245. delete _animation;
  246. _animation = nullptr;
  247. _animStart = nullptr;
  248. }
  249. void AnimationManager::clearTimers() {
  250. _animationTimers.clear();
  251. }
  252. void AnimationManager::loadAnimations(Resource *res) {
  253. _animationTimers.clear();
  254. delete _animation;
  255. _animation = new AnimationResource(_vm, res);
  256. }
  257. Animation *AnimationManager::setAnimation(int animId) {
  258. Animation *anim = findAnimation(animId);
  259. if (!anim)
  260. return nullptr;
  261. anim->_countdownTicks = anim->_initialTicks;
  262. anim->_frameNumber = 0;
  263. anim->_currentLoopCount = (anim->_type != 3 && anim->_type != 4) ? 0 : anim->_loopCount;
  264. return anim;
  265. }
  266. void AnimationManager::setAnimTimer(Animation *anim) {
  267. _animationTimers.push_back(anim);
  268. }
  269. Animation *AnimationManager::findAnimation(int animId) {
  270. _animStart = (_animation == nullptr) ? nullptr : _animation->getAnimation(animId);
  271. return _animStart;
  272. }
  273. void AnimationManager::animate(int animId) {
  274. Animation *anim = findAnimation(animId);
  275. _frameScale = anim->_scaling;
  276. anim->animate();
  277. }
  278. void AnimationManager::updateTimers() {
  279. for (uint idx = 0; idx < _animationTimers.size(); ++idx) {
  280. if (_animationTimers[idx]->_countdownTicks > 0)
  281. _animationTimers[idx]->_countdownTicks--;
  282. }
  283. }
  284. } // End of namespace Access