aboutsummaryrefslogtreecommitdiff
path: root/engines/neverhood/sprite.h
blob: 1d17bf0e70b416b66d6d11e697715d7ebbe50664 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
/* 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 2
 * 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, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 */

#ifndef NEVERHOOD_SPRITE_H
#define NEVERHOOD_SPRITE_H

#include "neverhood/neverhood.h"
#include "neverhood/entity.h"
#include "neverhood/graphics.h"
#include "neverhood/resource.h"

namespace Neverhood {

#define SetSpriteUpdate(callback)											\
	do {																	\
		_spriteUpdateCb = static_cast <void (Sprite::*)(void)> (callback);	\
		debug(2, "SetSpriteUpdate(" #callback ")");							\
		_spriteUpdateCbName = #callback;									\
	} while (0)

#define SetFilterX(callback)												\
	do {																	\
		_filterXCb = static_cast <int16 (Sprite::*)(int16)> (callback);		\
		debug(2, "SetFilterX(" #callback ")");								\
	} while (0)

#define SetFilterY(callback)												\
	do {																	\
		_filterYCb = static_cast <int16 (Sprite::*)(int16)> (callback);		\
		debug(2, "SetFilterY(" #callback ")");								\
	} while (0)

const int16 kDefPosition = -32768;

class Sprite : public Entity {
public:
	Sprite(NeverhoodEngine *vm, int objectPriority);
	~Sprite();
	void init() {}
	BaseSurface *getSurface() { return _surface; }
	void updateBounds();
	void setDoDeltaX(int type);
	void setDoDeltaY(int type);
	bool isPointInside(int16 x, int16 y);
	bool checkCollision(NRect &rect);
	int16 getX() const { return _x; }
	int16 getY() const { return _y; }
	void setX(int16 value) { _x = value; }
	void setY(int16 value) { _y = value; }
	uint16 getFlags() const { return _flags; }
	bool isDoDeltaX() const { return _doDeltaX; }
	bool isDoDeltaY() const { return _doDeltaY; }
	NRect& getCollisionBounds() { return _collisionBounds; }
	uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
	void loadDataResource(uint32 fileHash);
	int16 defFilterY(int16 y);
	bool getVisible() const { return _surface->getVisible(); }
	void setVisible(bool value) { _surface->setVisible(value); }
	NDrawRect& getDrawRect() { return _surface->getDrawRect(); }
	// Some shortcuts to set the clipRect
	NRect& getClipRect() { return _surface->getClipRect(); }
	void setClipRect(int16 x1, int16 y1, int16 x2, int16 y2);
	void setClipRect(NRect& clipRect);
	void setClipRect(NDrawRect& drawRect);
protected:
	void (Sprite::*_spriteUpdateCb)();
	Common::String _spriteUpdateCbName; // For debugging purposes
	int16 (Sprite::*_filterXCb)(int16);
	int16 (Sprite::*_filterYCb)(int16);
	BaseSurface *_surface;
	int16 _x, _y;
	bool _doDeltaX, _doDeltaY;
	bool _needRefresh;
	NDrawRect _drawOffset;
	NRect _collisionBounds;
	NDrawRect _collisionBoundsOffset;
	uint16 _flags;
	DataResource _dataResource;
	void createSurface(int surfacePriority, int16 width, int16 height);
	void handleSpriteUpdate() {
		if (_spriteUpdateCb)
			(this->*_spriteUpdateCb)();
	}
	int16 filterX(int16 x) {
		return _filterXCb ? (this->*_filterXCb)(x) : x;
	}
	int16 filterY(int16 y) {
		return _filterYCb ? (this->*_filterYCb)(y) : y;
	}
};

enum {
	kSLFDefDrawOffset				= 1 << 0,
	kSLFCenteredDrawOffset			= 1 << 1,
	kSLFDefPosition					= 1 << 2,
	kSLFSetPosition					= 1 << 3,
	kSLFDefCollisionBoundsOffset	= 1 << 4
};

class StaticSprite : public Sprite {
public:
	StaticSprite(NeverhoodEngine *vm, int objectPriority);
	StaticSprite(NeverhoodEngine *vm, uint32 fileHash, int surfacePriority, int16 x = kDefPosition, int16 y = kDefPosition);
	void loadSprite(uint32 fileHash, uint flags = 0, int surfacePriority = 0, int16 x = kDefPosition, int16 y = kDefPosition);
	void updatePosition();
protected:
	SpriteResource _spriteResource;
};

#define AnimationCallback(callback) static_cast <void (AnimatedSprite::*)()> (callback)
#define GotoState(callback) gotoState(static_cast <void (AnimatedSprite::*)()> (callback))
#define NextState(callback)															\
	do {																			\
		_nextStateCb = static_cast <void (AnimatedSprite::*)(void)> (callback);		\
		debug(2, "NextState(" #callback ")"); _nextStateCbName = #callback;			\
	} while (0)
#define FinalizeState(callback) setFinalizeState(static_cast <void (AnimatedSprite::*)()> (callback));

const int STICK_LAST_FRAME = -2;

class AnimatedSprite : public Sprite {
public:
	AnimatedSprite(NeverhoodEngine *vm, int objectPriority);
	AnimatedSprite(NeverhoodEngine *vm, uint32 fileHash, int surfacePriority, int16 x, int16 y);
	void update();
	void updateDeltaXY();
	void setRepl(byte oldColor, byte newColor);
	void clearRepl();
	uint32 getCurrAnimFileHash() const { return _currAnimFileHash; }
	int16 getFrameIndex() const { return _currFrameIndex; }
	int16 getFrameIndex(uint32 frameHash) { return _animResource.getFrameIndex(frameHash); }
	void setNewHashListIndex(int value) { _newStickFrameIndex = value; }
	void startAnimation(uint32 fileHash, int16 plFirstFrameIndex, int16 plLastFrameIndex);
protected:
	typedef void (AnimatedSprite::*AnimationCb)();
	AnimResource _animResource;
	uint32 _currAnimFileHash, _newAnimFileHash, _nextAnimFileHash;
	int16 _currFrameIndex, _lastFrameIndex;
	int16 _plFirstFrameIndex, _plLastFrameIndex;
	uint32 _plFirstFrameHash, _plLastFrameHash;
	int16 _animStatus;
	int16 _currFrameTicks;
	int _currStickFrameIndex, _newStickFrameIndex;
	uint32 _newStickFrameHash;
	int16 _deltaX, _deltaY;
	byte _replOldColor, _replNewColor;
	bool _playBackwards, _frameChanged;
	AnimationCb _finalizeStateCb;
	AnimationCb _currStateCb;
	AnimationCb _nextStateCb;
	// For debugging purposes
	Common::String _finalizeStateCbName;
	Common::String _currStateCbName;
	Common::String _nextStateCbName;
	void init();
	void updateAnim();
	void updatePosition();
	void updateFrameIndex();
	void updateFrameInfo();
	void createSurface1(uint32 fileHash, int surfacePriority);
	void createShadowSurface1(BaseSurface *shadowSurface, uint32 fileHash, int surfacePriority);
	void createShadowSurface(BaseSurface *shadowSurface, int16 width, int16 height, int surfacePriority);
	void stopAnimation();
	void startAnimationByHash(uint32 fileHash, uint32 plFirstFrameHash, uint32 plLastFrameHash);
	void nextAnimationByHash(uint32 fileHash2, uint32 plFirstFrameHash, uint32 plLastFrameHash);
	void setFinalizeState(AnimationCb finalizeStateCb);
	void gotoState(AnimationCb currStateCb);
	void gotoNextState();
};

} // End of namespace Neverhood

#endif /* NEVERHOOD_SPRITE_H */