summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/util/palette.h
blob: 23d1141605313b330d29c7363e9d70e4b73804f8 (plain) (blame)
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
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/******************************************************************************

    palette.h

    Core palette routines.

***************************************************************************/

#pragma once

#ifndef __PALETTE_H__
#define __PALETTE_H__

#include "osdcore.h"
#include "coretmpl.h"


//**************************************************************************
//  TYPE DEFINITIONS
//**************************************************************************

// forward definitions
class palette_t;

// an rgb15_t is a single combined 15-bit R,G,B value
typedef UINT16 rgb15_t;


// ======================> rgb_t

// an rgb_t is a single combined R,G,B (and optionally alpha) value
class rgb_t
{
public:
	// construction/destruction
	rgb_t() { }
	rgb_t(UINT32 data) { m_data = data; }
	rgb_t(UINT8 r, UINT8 g, UINT8 b) { m_data = (255 << 24) | (r << 16) | (g << 8) | b; }
	rgb_t(UINT8 a, UINT8 r, UINT8 g, UINT8 b) { m_data = (a << 24) | (r << 16) | (g << 8) | b; }

	// getters
	UINT8 a() const { return m_data >> 24; }
	UINT8 r() const { return m_data >> 16; }
	UINT8 g() const { return m_data >> 8; }
	UINT8 b() const { return m_data >> 0; }
	rgb15_t as_rgb15() const { return ((r() >> 3) << 10) | ((g() >> 3) << 5) | ((b() >> 3) << 0); }
	UINT8 brightness() const { return (r() * 222 + g() * 707 + b() * 71) / 1000; }
	UINT32 const *ptr() const { return &m_data; }

	// setters
	rgb_t &set_a(UINT8 a) { m_data &= ~0xff000000; m_data |= a << 24; return *this; }
	rgb_t &set_r(UINT8 r) { m_data &= ~0x00ff0000; m_data |= r << 16; return *this; }
	rgb_t &set_g(UINT8 g) { m_data &= ~0x0000ff00; m_data |= g <<  8; return *this; }
	rgb_t &set_b(UINT8 b) { m_data &= ~0x000000ff; m_data |= b <<  0; return *this; }

	// implicit conversion operators
	operator UINT32() const { return m_data; }

	// operations
	rgb_t &scale8(UINT8 scale) { m_data = rgb_t(clamphi((a() * scale) >> 8), clamphi((r() * scale) >> 8), clamphi((g() * scale) >> 8), clamphi((b() * scale) >> 8)); return *this; }

	// assignment operators
	rgb_t &operator=(UINT32 rhs) { m_data = rhs; return *this; }
	rgb_t &operator+=(const rgb_t &rhs) { m_data = rgb_t(clamphi(a() + rhs.a()), clamphi(r() + rhs.r()), clamphi(g() + rhs.g()), clamphi(b() + rhs.b())); return *this; }
	rgb_t &operator-=(const rgb_t &rhs) { m_data = rgb_t(clamplo(a() - rhs.a()), clamplo(r() - rhs.r()), clamplo(g() - rhs.g()), clamplo(b() - rhs.b())); return *this; }

	// arithmetic operators
	const rgb_t operator+(const rgb_t &rhs) const { rgb_t result = *this; result += rhs; return result; }
	const rgb_t operator-(const rgb_t &rhs) const { rgb_t result = *this; result -= rhs; return result; }

	// static helpers
	static UINT8 clamp(INT32 value) { return (value < 0) ? 0 : (value > 255) ? 255 : value; }
	static UINT8 clamphi(INT32 value) { return (value > 255) ? 255 : value; }
	static UINT8 clamplo(INT32 value) { return (value < 0) ? 0 : value; }

	// constants
	static const rgb_t black;
	static const rgb_t white;

private:
	UINT32  m_data;
};


// ======================> palette_client

// a single palette client
class palette_client
{
public:
	// construction/destruction
	palette_client(palette_t &palette);
	~palette_client();

	// getters
	palette_client *next() const { return m_next; }
	palette_t &palette() const { return m_palette; }
	const UINT32 *dirty_list(UINT32 &mindirty, UINT32 &maxdirty);

	// dirty marking
	void mark_dirty(UINT32 index) { m_live->mark_dirty(index); }

private:
	// internal object to track dirty states
	class dirty_state
	{
	public:
		// construction
		dirty_state();

		// operations
		const UINT32 *dirty_list(UINT32 &mindirty, UINT32 &maxdirty);
		void resize(UINT32 colors);
		void mark_dirty(UINT32 index);
		void reset();

	private:
		// internal state
		dynamic_array<UINT32> m_dirty;          // bitmap of dirty entries
		UINT32          m_mindirty;             // minimum dirty entry
		UINT32          m_maxdirty;             // minimum dirty entry
	};

	// internal state
	palette_t &     m_palette;                  // reference to the palette
	palette_client *m_next;                     // pointer to next client
	dirty_state *   m_live;                     // live dirty state
	dirty_state *   m_previous;                 // previous dirty state
	dirty_state     m_dirty[2];                 // two dirty states
};


// ======================> palette_t

// a palette object
class palette_t
{
	friend class palette_client;

public:
	// static constructor: used to ensure same new/delete is used
	static palette_t *alloc(UINT32 numcolors, UINT32 numgroups = 1);

	// reference counting
	void ref() { m_refcount++; }
	void deref();

	// getters
	int num_colors() const { return m_numcolors; }
	int num_groups() const { return m_numgroups; }
	int max_index() const { return m_numcolors * m_numgroups + 2; }
	UINT32 black_entry() const { return m_numcolors * m_numgroups + 0; }
	UINT32 white_entry() const { return m_numcolors * m_numgroups + 1; }

	// overall adjustments
	void set_brightness(float brightness);
	void set_contrast(float contrast);
	void set_gamma(float gamma);

	// entry getters
	rgb_t entry_color(UINT32 index) const { return (index < m_numcolors) ? m_entry_color[index] : rgb_t::black; }
	rgb_t entry_adjusted_color(UINT32 index) const { return (index < m_numcolors * m_numgroups) ? m_adjusted_color[index] : rgb_t::black; }
	float entry_contrast(UINT32 index) const { return (index < m_numcolors) ? m_entry_contrast[index] : 1.0f; }

	// entry setters
	void entry_set_color(UINT32 index, rgb_t rgb);
	void entry_set_contrast(UINT32 index, float contrast);

	// entry list getters
	const rgb_t *entry_list_raw() const { return m_entry_color; }
	const dynamic_array<rgb_t> *entry_list_adjusted_darray() const { return &m_adjusted_color; }
	const rgb_t *entry_list_adjusted() const { return m_adjusted_color; }
	const rgb_t *entry_list_adjusted_rgb15() const { return m_adjusted_rgb15; }

	// group adjustments
	void group_set_brightness(UINT32 group, float brightness);
	void group_set_contrast(UINT32 group, float contrast);

	// utilities
	void normalize_range(UINT32 start, UINT32 end, int lum_min = 0, int lum_max = 255);

private:
	// construction/destruction
	palette_t(UINT32 numcolors, UINT32 numgroups = 1);
	~palette_t();

	// internal helpers
	rgb_t adjust_palette_entry(rgb_t entry, float brightness, float contrast, const UINT8 *gamma_map);
	void update_adjusted_color(UINT32 group, UINT32 index);

	// internal state
	UINT32          m_refcount;                   // reference count on the palette
	UINT32          m_numcolors;                  // number of colors in the palette
	UINT32          m_numgroups;                  // number of groups in the palette

	float           m_brightness;                 // overall brightness value
	float           m_contrast;                   // overall contrast value
	float           m_gamma;                      // overall gamma value
	UINT8           m_gamma_map[256];             // gamma map

	dynamic_array<rgb_t> m_entry_color;           // array of raw colors
	dynamic_array<float> m_entry_contrast;        // contrast value for each entry
	dynamic_array<rgb_t> m_adjusted_color;        // array of adjusted colors
	dynamic_array<rgb_t> m_adjusted_rgb15;        // array of adjusted colors as RGB15

	dynamic_array<float> m_group_bright;          // brightness value for each group
	dynamic_array<float> m_group_contrast;        // contrast value for each group

	palette_client *m_client_list;                // list of clients for this palette
};



//**************************************************************************
//  INLINE FUNCTIONS
//**************************************************************************

//-------------------------------------------------
//  palexpand - expand a palette value to 8 bits
//-------------------------------------------------

template<int _NumBits>
inline UINT8 palexpand(UINT8 bits)
{
	if (_NumBits == 1) { return (bits & 1) ? 0xff : 0x00; }
	if (_NumBits == 2) { bits &= 3; return (bits << 6) | (bits << 4) | (bits << 2) | bits; }
	if (_NumBits == 3) { bits &= 7; return (bits << 5) | (bits << 2) | (bits >> 1); }
	if (_NumBits == 4) { bits &= 0xf; return (bits << 4) | bits; }
	if (_NumBits == 5) { bits &= 0x1f; return (bits << 3) | (bits >> 2); }
	if (_NumBits == 6) { bits &= 0x3f; return (bits << 2) | (bits >> 4); }
	if (_NumBits == 7) { bits &= 0x7f; return (bits << 1) | (bits >> 6); }
	return bits;
}


//-------------------------------------------------
//  palxbit - convert an x-bit value to 8 bits
//-------------------------------------------------

inline UINT8 pal1bit(UINT8 bits) { return palexpand<1>(bits); }
inline UINT8 pal2bit(UINT8 bits) { return palexpand<2>(bits); }
inline UINT8 pal3bit(UINT8 bits) { return palexpand<3>(bits); }
inline UINT8 pal4bit(UINT8 bits) { return palexpand<4>(bits); }
inline UINT8 pal5bit(UINT8 bits) { return palexpand<5>(bits); }
inline UINT8 pal6bit(UINT8 bits) { return palexpand<6>(bits); }
inline UINT8 pal7bit(UINT8 bits) { return palexpand<7>(bits); }


//-------------------------------------------------
//  rgbexpand - expand a 32-bit raw data to 8-bit
//  RGB
//-------------------------------------------------

template<int _RBits, int _GBits, int _BBits>
inline rgb_t rgbexpand(UINT32 data, UINT8 rshift, UINT8 gshift, UINT8 bshift)
{
	return rgb_t(palexpand<_RBits>(data >> rshift), palexpand<_GBits>(data >> gshift), palexpand<_BBits>(data >> bshift));
}


//-------------------------------------------------
//  palxxx - create an x-x-x color by extracting
//  bits from a UINT32
//-------------------------------------------------

inline rgb_t pal332(UINT32 data, UINT8 rshift, UINT8 gshift, UINT8 bshift) { return rgbexpand<3,3,2>(data, rshift, gshift, bshift); }
inline rgb_t pal444(UINT32 data, UINT8 rshift, UINT8 gshift, UINT8 bshift) { return rgbexpand<4,4,4>(data, rshift, gshift, bshift); }
inline rgb_t pal555(UINT32 data, UINT8 rshift, UINT8 gshift, UINT8 bshift) { return rgbexpand<5,5,5>(data, rshift, gshift, bshift); }
inline rgb_t pal565(UINT32 data, UINT8 rshift, UINT8 gshift, UINT8 bshift) { return rgbexpand<5,6,5>(data, rshift, gshift, bshift); }
inline rgb_t pal888(UINT32 data, UINT8 rshift, UINT8 gshift, UINT8 bshift) { return rgbexpand<8,8,8>(data, rshift, gshift, bshift); }


#endif  // __PALETTE_H__