// 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 #include #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; } }