v1.1.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Groups Pages
color.h
1 /* -*- mode: C; c-basic-offset: 4; intent-tabs-mode: nil -*-
2  *
3  * This file is part of the public interface to the Sifteo SDK.
4  * Copyright <c> 2012 Sifteo, Inc. All rights reserved.
5  */
6 
7 #pragma once
8 #ifdef NOT_USERSPACE
9 # error This is a userspace-only header, not allowed by the current build.
10 #endif
11 
12 #include <sifteo/abi.h>
13 #include <sifteo/macros.h>
14 #include <sifteo/math.h>
15 
16 namespace Sifteo {
17 
31 struct RGB565 {
33  uint16_t value;
34 
39  static RGB565 from565(uint8_t r, uint8_t g, uint8_t b) {
40  RGB565 result = { (r << 11) | (g << 5) | b };
41  return result;
42  }
43 
48  static RGB565 fromRGB(uint8_t r, uint8_t g, uint8_t b) {
49  /*
50  * Round to the nearest 5/6 bit color. Note that simple
51  * bit truncation does NOT produce the best result!
52  */
53  return from565( ((unsigned)r * 31 + 128) / 255,
54  ((unsigned)g * 63 + 128) / 255,
55  ((unsigned)b * 31 + 128) / 255 );
56  }
57 
62  static RGB565 fromRGB(float r, float g, float b) {
63  return from565( r * 31.f + 0.5f,
64  g * 63.f + 0.5f,
65  b * 31.f + 0.5f );
66  }
67 
74  static RGB565 fromRGB(uint32_t rgb) {
75  return fromRGB((uint8_t)(rgb >> 16), (uint8_t)(rgb >> 8), (uint8_t)rgb);
76  }
77 
81  uint8_t red5() const {
82  return (value >> 11) & 0x1F;
83  }
84 
88  uint8_t green6() const {
89  return (value >> 5) & 0x3F;
90  }
91 
95  uint8_t blue5() const {
96  return value & 0x1F;
97  }
98 
102  uint8_t red() const {
103  /*
104  * A good approximation is `(r5 << 3) | (r5 >> 2)`, but this
105  * is still not quite as accurate as the implementation here.
106  */
107  return red5() * 255 / 31;
108  }
109 
113  uint8_t green() const {
114  return green6() * 255 / 63;
115  }
116 
120  uint8_t blue() const {
121  return blue5() * 255 / 31;
122  }
123 
130  uint32_t packedRGB() const {
131  return blue() | (green() << 8) | (red() << 16);
132  }
133 
141  RGB565 lerp(RGB565 other, uint8_t alpha) const {
142  unsigned A = alpha;
143  unsigned invA = 0xff - A;
144  return from565( (red5() * invA + other.red5() * A) / 0xff,
145  (green6() * invA + other.green6() * A) / 0xff,
146  (blue5() * invA + other.blue5() * A) / 0xff );
147  }
148 
150  bool operator== (const RGB565 &other) const { return value == other.value; }
151 
153  bool operator!= (const RGB565 &other) const { return value != other.value; }
154 };
155 
156 
168 struct ColormapSlot {
169  _SYSAttachedVideoBuffer *sys;
170  unsigned index;
171 
175  void set(RGB565 color) const {
176  _SYS_vbuf_poke(&sys->vbuf, _SYS_VA_COLORMAP / 2 + index, color.value);
177  }
178 
182  void set(uint8_t r, uint8_t g, uint8_t b) const {
183  set(RGB565::fromRGB(r, g, b));
184  }
185 
189  void set(float r, float g, float b) const {
190  set(RGB565::fromRGB(r, g, b));
191  }
192 
199  void set(uint32_t rgb) const {
200  set(RGB565::fromRGB(rgb));
201  }
202 
206  const ColormapSlot& operator= (RGB565 color) const {
207  set(color);
208  return *this;
209  }
210 
217  const ColormapSlot& operator= (uint32_t color) const {
218  set(color);
219  return *this;
220  }
221 
225  RGB565 get() const {
226  RGB565 result = { _SYS_vbuf_peek(&sys->vbuf, _SYS_VA_COLORMAP / 2 + index) };
227  return result;
228  }
229 };
230 
231 
245 struct Colormap {
246  _SYSAttachedVideoBuffer sys;
247 
249  static const unsigned NUM_COLORS = 16;
250 
259  ColormapSlot operator[](unsigned index) {
260  ASSERT(index < NUM_COLORS);
261  ColormapSlot result = { &sys, index };
262  return result;
263  }
264 
268  void erase() {
269  _SYS_vbuf_fill(&sys.vbuf, _SYS_VA_COLORMAP / 2, 0, NUM_COLORS);
270  }
271 
275  void fill(RGB565 color) {
276  _SYS_vbuf_fill(&sys.vbuf, _SYS_VA_COLORMAP / 2, color.value, NUM_COLORS);
277  }
278 
282  void setRange(const RGB565 *colors, unsigned firstColor, unsigned numColors) {
283  ASSERT(firstColor <= NUM_COLORS && numColors <= NUM_COLORS
284  && (firstColor + numColors) <= NUM_COLORS);
285  _SYS_vbuf_write(&sys.vbuf, _SYS_VA_COLORMAP / 2 + firstColor,
286  &colors[0].value, numColors);
287  }
288 
292  void set(const RGB565 *colors) {
293  setRange(colors, 0, NUM_COLORS);
294  }
295 
301  void setEGA() {
302  static const RGB565 colors[] = {
303  /* 0 */ { 0x0000 },
304  /* 1 */ { 0x0015 },
305  /* 2 */ { 0x0540 },
306  /* 3 */ { 0x0555 },
307  /* 4 */ { 0xa800 },
308  /* 5 */ { 0xa815 },
309  /* 6 */ { 0xaaa0 },
310  /* 7 */ { 0xad55 },
311  /* 8 */ { 0x52aa },
312  /* 9 */ { 0x52bf },
313  /* 10 */ { 0x57ea },
314  /* 11 */ { 0x57ff },
315  /* 12 */ { 0xfaaa },
316  /* 13 */ { 0xfabf },
317  /* 14 */ { 0xffea },
318  /* 15 */ { 0xffff },
319  };
320  set(colors);
321  }
322 
328  void setMono(RGB565 color0, RGB565 color1) {
329  (*this)[0].set(color0);
330  (*this)[1].set(color1);
331  }
332 
340  void setMono(uint32_t color0, uint32_t color1) {
341  (*this)[0].set(color0);
342  (*this)[1].set(color1);
343  }
344 
348  _SYSVideoBuffer &videoBuffer() {
349  return sys.vbuf;
350  }
351 
355  CubeID cube() const {
356  return sys.cube;
357  }
358 };
359 
364 }; // namespace Sifteo