summaryrefslogtreecommitdiff
path: root/src/blitter/blitter.hpp
blob: 4920da426b208860be37548619e3e2e37572d5ab (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
/* $Id$ */

/** @file blitter.hpp */

#ifndef BLITTER_HPP
#define BLITTER_HPP

#include "../spriteloader/spriteloader.hpp"
#include "../spritecache.h"
#include <string>
#include <map>

enum BlitterMode {
	BM_NORMAL,
	BM_COLOUR_REMAP,
	BM_TRANSPARENT,
};

/**
 * How all blitters should look like. Extend this class to make your own.
 */
class Blitter {
public:
	struct BlitterParams {
		const void *sprite;      ///< Pointer to the sprite how ever the encoder stored it
		const byte *remap;       ///< XXX -- Temporary storage for remap array

		int skip_left, skip_top; ///< How much pixels of the source to skip on the left and top (based on zoom of dst)
		int width, height;       ///< The width and height in pixels that needs to be drawn to dst
		int sprite_width;        ///< Real width of the sprite
		int sprite_height;       ///< Real height of the sprite
		int left, top;           ///< The offset in the 'dst' in pixels to start drawing

		void *dst;               ///< Destination buffer
		int pitch;               ///< The pitch of the destination buffer
	};

	/**
	 * Get the screen depth this blitter works for.
	 *  This is either: 8, 16, 24 or 32.
	 */
	virtual uint8 GetScreenDepth() = 0;

	/**
	 * Draw an image to the screen, given an amount of params defined above.
	 */
	virtual void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) = 0;

	/**
	 * Convert a sprite from the loader to our own format.
	 */
	virtual Sprite *Encode(SpriteLoader::Sprite *sprite) = 0;

	virtual ~Blitter() { }
};

/**
 * The base factory, keeping track of all blitters.
 */
class BlitterFactoryBase {
private:
	char *name;
	typedef std::map<std::string, BlitterFactoryBase *> Blitters;

	static Blitters &GetBlitters()
	{
		static Blitters &s_blitters = *new Blitters();
		return s_blitters;
	}

	static Blitter **GetActiveBlitter()
	{
		static Blitter *s_blitter = NULL;
		return &s_blitter;
	}

protected:
	/**
	 * Register a blitter internally, based on his name.
	 * @param name the name of the blitter.
	 * @note an assert() will be trigger if 2 blitters with the same name try to register.
	 */
	void RegisterBlitter(const char *name)
	{
		/* Don't register nameless Blitters */
		if (name == NULL) return;

		this->name = strdup(name);
		std::pair<Blitters::iterator, bool> P = GetBlitters().insert(Blitters::value_type(name, this));
		assert(P.second);
	}

public:
	BlitterFactoryBase() :
		name(NULL)
	{}

	virtual ~BlitterFactoryBase() { if (this->name != NULL) GetBlitters().erase(this->name); free(this->name); }

	/**
	 * Find the requested blitter and return his class.
	 * @param name the blitter to select.
	 * @post Sets the blitter so GetCurrentBlitter() returns it too.
	 */
	static Blitter *SelectBlitter(const char *name)
	{
		if (GetBlitters().size() == 0) return NULL;

		Blitters::iterator it = GetBlitters().begin();
		for (; it != GetBlitters().end(); it++) {
			BlitterFactoryBase *b = (*it).second;
			if (strcasecmp(name, b->name) == 0) {
				Blitter *newb = b->CreateInstance();
				*GetActiveBlitter() = newb;
				return newb;
			}
		}
		return NULL;
	}

	/**
	 * Get the current active blitter (always set by calling SelectBlitter).
	 */
	static Blitter *GetCurrentBlitter()
	{
		return *GetActiveBlitter();
	}


	static char *GetBlittersInfo(char *p, const char *last)
	{
		p += snprintf(p, last - p, "List of blitters:\n");
		Blitters::iterator it = GetBlitters().begin();
		for (; it != GetBlitters().end(); it++) {
			BlitterFactoryBase *b = (*it).second;
			p += snprintf(p, last - p, "%18s: %s\n", b->name, b->GetDescription());
		}
		p += snprintf(p, last - p, "\n");

		return p;
	}

	/**
	 * Get a nice description of the blitter-class.
	 */
	virtual const char *GetDescription() = 0;

	/**
	 * Create an instance of this Blitter-class.
	 */
	virtual Blitter *CreateInstance() = 0;
};

/**
 * A template factory, so ->GetName() works correctly. This because else some compiler will complain.
 */
template <class T>
class BlitterFactory: public BlitterFactoryBase {
public:
	BlitterFactory() { this->RegisterBlitter(((T *)this)->GetName()); }

	/**
	 * Get the long, human readable, name for the Blitter-class.
	 */
	const char *GetName();
};

#endif /* BLITTER_HPP */