summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/util/palette.h
blob: ff2c7bb80c995e40f1ab990bcf66a188d8a9d0f1 (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
276
277
278
279
280
281
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/******************************************************************************

    palette.h

    Core palette routines.

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

#ifndef MAME_UTIL_PALETTE_H
#define MAME_UTIL_PALETTE_H

#pragma once

#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_t rgb15_t;


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

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

	// getters
	constexpr uint8_t a() const { return m_data >> 24; }
	constexpr uint8_t r() const { return m_data >> 16; }
	constexpr uint8_t g() const { return m_data >> 8; }
	constexpr uint8_t b() const { return m_data >> 0; }
	constexpr rgb15_t as_rgb15() const { return ((r() >> 3) << 10) | ((g() >> 3) << 5) | ((b() >> 3) << 0); }
	constexpr uint8_t brightness() const { return (r() * 222 + g() * 707 + b() * 71) / 1000; }
	constexpr uint32_t const *ptr() const { return &m_data; }
	void expand_rgb(uint8_t &r, uint8_t &g, uint8_t &b) const { r = m_data >> 16; g = m_data >> 8; b = m_data >> 0; }
	void expand_rgb(int &r, int &g, int &b) const { r = (m_data >> 16) & 0xff; g = (m_data >> 8) & 0xff; b = (m_data >> 0) & 0xff; }

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

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

	// operations
	rgb_t &scale8(uint8_t 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_t rhs) { m_data = rhs; return *this; }
	rgb_t &operator+=(const rgb_t &rhs) { m_data = uint32_t(*this + rhs); return *this; }
	rgb_t &operator-=(const rgb_t &rhs) { m_data = uint32_t(*this - rhs); return *this; }

	// arithmetic operators
	constexpr rgb_t operator+(const rgb_t &rhs) const { return rgb_t(clamphi(a() + rhs.a()), clamphi(r() + rhs.r()), clamphi(g() + rhs.g()), clamphi(b() + rhs.b())); }
	constexpr rgb_t operator-(const rgb_t &rhs) const { return rgb_t(clamplo(a() - rhs.a()), clamplo(r() - rhs.r()), clamplo(g() - rhs.g()), clamplo(b() - rhs.b())); }

	// static helpers
	static constexpr uint8_t clamp(int32_t value) { return (value < 0) ? 0 : (value > 255) ? 255 : value; }
	static constexpr uint8_t clamphi(int32_t value) { return (value > 255) ? 255 : value; }
	static constexpr uint8_t clamplo(int32_t value) { return (value < 0) ? 0 : value; }

	// constant factories
	static constexpr rgb_t black() { return rgb_t(0, 0, 0); }
	static constexpr rgb_t white() { return rgb_t(255, 255, 255); }
	static constexpr rgb_t green() { return rgb_t(0, 255, 0); }
	static constexpr rgb_t amber() { return rgb_t(247, 170, 0); }
	static constexpr rgb_t transparent() { return rgb_t(0, 0, 0, 0); }

private:
	uint32_t  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_t *dirty_list(uint32_t &mindirty, uint32_t &maxdirty);

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

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

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

	private:
		// internal state
		std::vector<uint32_t> m_dirty;          // bitmap of dirty entries
		uint32_t          m_mindirty;             // minimum dirty entry
		uint32_t          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_t numcolors, uint32_t 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_t black_entry() const { return m_numcolors * m_numgroups + 0; }
	uint32_t 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_t index) const { return (index < m_numcolors) ? m_entry_color[index] : rgb_t::black(); }
	rgb_t entry_adjusted_color(uint32_t index) const { return (index < m_numcolors * m_numgroups) ? m_adjusted_color[index] : rgb_t::black(); }
	float entry_contrast(uint32_t index) const { return (index < m_numcolors) ? m_entry_contrast[index] : 1.0f; }

	// entry setters
	void entry_set_color(uint32_t index, rgb_t rgb);
	void entry_set_red_level(uint32_t index, uint8_t level);
	void entry_set_green_level(uint32_t index, uint8_t level);
	void entry_set_blue_level(uint32_t index, uint8_t level);
	void entry_set_contrast(uint32_t index, float contrast);

	// entry list getters
	const rgb_t *entry_list_raw() const { return &m_entry_color[0]; }
	const rgb_t *entry_list_adjusted() const { return &m_adjusted_color[0]; }
	const rgb_t *entry_list_adjusted_rgb15() const { return &m_adjusted_rgb15[0]; }

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

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

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

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

	// internal state
	uint32_t          m_refcount;                   // reference count on the palette
	uint32_t          m_numcolors;                  // number of colors in the palette
	uint32_t          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_t           m_gamma_map[256];             // gamma map

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

	std::vector<float> m_group_bright;          // brightness value for each group
	std::vector<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_t palexpand(uint8_t 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_t pal1bit(uint8_t bits) { return palexpand<1>(bits); }
inline uint8_t pal2bit(uint8_t bits) { return palexpand<2>(bits); }
inline uint8_t pal3bit(uint8_t bits) { return palexpand<3>(bits); }
inline uint8_t pal4bit(uint8_t bits) { return palexpand<4>(bits); }
inline uint8_t pal5bit(uint8_t bits) { return palexpand<5>(bits); }
inline uint8_t pal6bit(uint8_t bits) { return palexpand<6>(bits); }
inline uint8_t pal7bit(uint8_t 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_t data, uint8_t rshift, uint8_t gshift, uint8_t 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_t
//-------------------------------------------------

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

#endif // MAME_UTIL_PALETTE_H