100 lines
2.9 KiB
C
100 lines
2.9 KiB
C
// Palette accessors.
|
|
//
|
|
// Library contract: color 0 of every palette is forced to black ($000).
|
|
// paletteSet silently masks that entry regardless of what the caller
|
|
// provides.
|
|
|
|
#include <stddef.h>
|
|
#include <string.h>
|
|
|
|
#include "joey/palette.h"
|
|
#include "surfaceInternal.h"
|
|
|
|
|
|
// Standard 16-color EGA palette in IIgs $0RGB format. Used as the
|
|
// per-surface default at allocation time (paletteInitDefault) so a
|
|
// program that draws without first calling paletteSet still gets
|
|
// recognizable colors instead of an all-black palette. EGA index 6
|
|
// is the canonical "brown" hack ($0A50, half-green) so CGA monitors
|
|
// rendered the third primary as brown rather than dark yellow.
|
|
static const uint16_t kDefaultPaletteEga[SURFACE_COLORS_PER_PALETTE] = {
|
|
0x0000, // 0: Black
|
|
0x000A, // 1: Blue
|
|
0x00A0, // 2: Green
|
|
0x00AA, // 3: Cyan
|
|
0x0A00, // 4: Red
|
|
0x0A0A, // 5: Magenta
|
|
0x0A50, // 6: Brown
|
|
0x0AAA, // 7: Light Gray
|
|
0x0555, // 8: Dark Gray
|
|
0x055F, // 9: Light Blue
|
|
0x05F5, // 10: Light Green
|
|
0x05FF, // 11: Light Cyan
|
|
0x0F55, // 12: Light Red
|
|
0x0F5F, // 13: Light Magenta
|
|
0x0FF5, // 14: Yellow
|
|
0x0FFF // 15: White
|
|
};
|
|
|
|
|
|
// ----- Internal API -----
|
|
|
|
void paletteInitDefault(SurfaceT *s) {
|
|
uint8_t i;
|
|
|
|
if (s == NULL) {
|
|
return;
|
|
}
|
|
for (i = 0; i < SURFACE_PALETTE_COUNT; i++) {
|
|
paletteSet(s, i, kDefaultPaletteEga);
|
|
}
|
|
}
|
|
|
|
|
|
// ----- Public API (alphabetical) -----
|
|
|
|
void paletteGet(const SurfaceT *s, uint8_t paletteIndex, uint16_t *out16) {
|
|
const uint16_t *row;
|
|
|
|
if (s == NULL || out16 == NULL) {
|
|
return;
|
|
}
|
|
if (paletteIndex >= SURFACE_PALETTE_COUNT) {
|
|
return;
|
|
}
|
|
/* Byte-pointer math + shift to skip the ~MUL4 helper -- see
|
|
* paletteSet for the reasoning. */
|
|
row = (const uint16_t *)((const uint8_t *)s->palette + ((uint16_t)paletteIndex << 5));
|
|
memcpy(out16, row, SURFACE_COLORS_PER_PALETTE * sizeof(uint16_t));
|
|
}
|
|
|
|
|
|
void paletteSet(SurfaceT *s, uint8_t paletteIndex, const uint16_t *colors16) {
|
|
uint8_t i;
|
|
uint16_t *row;
|
|
const uint16_t *src;
|
|
|
|
if (s == NULL || colors16 == NULL) {
|
|
return;
|
|
}
|
|
if (paletteIndex >= SURFACE_PALETTE_COUNT) {
|
|
return;
|
|
}
|
|
|
|
/* Compute the row pointer via byte-pointer math + a single shift
|
|
* (16 entries * 2 bytes = 32 = 1 << 5) so ORCA-C doesn't emit a
|
|
* ~MUL4 helper for the 2D-array indexing. Then walk both arrays
|
|
* with post-increment pointers so the inner loop avoids ~MUL4
|
|
* for every `row[i]` / `colors16[i]` index multiply too. */
|
|
row = (uint16_t *)((uint8_t *)s->palette + ((uint16_t)paletteIndex << 5));
|
|
src = colors16;
|
|
|
|
*row++ = 0x0000;
|
|
src++;
|
|
for (i = 1; i < SURFACE_COLORS_PER_PALETTE; i++) {
|
|
*row++ = (uint16_t)(*src++ & 0x0FFF);
|
|
}
|
|
if (s == stageGet()) {
|
|
gStagePaletteDirty = true;
|
|
}
|
|
}
|