joeylib2/src/core/palette.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;
}
}