2016-09-22 19:11:56 +01:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <pc.h>
|
|
|
|
|
|
|
|
|
|
#include "palette.h"
|
|
|
|
|
|
|
|
|
|
#define MAX_IDX 256
|
|
|
|
|
#define MAP_SIZE 1024
|
|
|
|
|
#define MAP_MASK (MAP_SIZE - 1)
|
|
|
|
|
|
2016-09-24 09:35:32 +01:00
|
|
|
struct { unsigned color; int idx; } palette_map[MAP_SIZE];
|
2016-09-26 20:25:10 +01:00
|
|
|
unsigned palette_palette[MAX_IDX];
|
2016-09-24 09:35:32 +01:00
|
|
|
int palette_nextIdx;
|
|
|
|
|
int palette_inited;
|
2016-09-22 19:11:56 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
void palette_init(void) {
|
2016-09-24 09:35:32 +01:00
|
|
|
if (palette_inited) return;
|
2016-09-22 19:11:56 +01:00
|
|
|
palette_reset();
|
2016-09-24 09:35:32 +01:00
|
|
|
palette_inited = 1;
|
2016-09-22 19:11:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void palette_reset(void) {
|
|
|
|
|
/* Reset nextIdx -- start at idx 1 as 0 is used for transparency */
|
2016-09-24 09:35:32 +01:00
|
|
|
palette_nextIdx = 1;
|
|
|
|
|
/* Reset palette_map */
|
2016-09-22 19:11:56 +01:00
|
|
|
int i;
|
|
|
|
|
for (i = 0; i < MAP_SIZE; i++) {
|
2016-09-24 09:35:32 +01:00
|
|
|
palette_map[i].idx = -1;
|
2016-09-22 19:11:56 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static unsigned hash(const void *data, int size) {
|
|
|
|
|
unsigned hash = 5381;
|
|
|
|
|
const unsigned char *p = data;
|
|
|
|
|
while (size--) {
|
|
|
|
|
hash = ((hash << 5) + hash) ^ *p++;
|
|
|
|
|
}
|
|
|
|
|
return hash;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-09-26 20:14:17 +01:00
|
|
|
int palette_colorToIdx(int r, int g, int b) {
|
2016-09-22 19:11:56 +01:00
|
|
|
palette_init();
|
|
|
|
|
|
|
|
|
|
/* Make 18bit rgb color (6bits per-channel) from 8bit channels */
|
2016-09-22 19:59:59 +01:00
|
|
|
unsigned color = ((b & 0xfc) << 10) | ((g & 0xfc) << 4) | ((r & 0xfc) >> 2);
|
2016-09-22 19:11:56 +01:00
|
|
|
|
|
|
|
|
/* Hash color */
|
|
|
|
|
unsigned h = hash(&color, sizeof(color));
|
|
|
|
|
|
|
|
|
|
/* Find color in hashmap */
|
|
|
|
|
int i = h & MAP_MASK;
|
2016-09-24 09:35:32 +01:00
|
|
|
while (palette_map[i].idx != -1) {
|
|
|
|
|
if (palette_map[i].color == color) {
|
|
|
|
|
return palette_map[i].idx;
|
2016-09-22 19:11:56 +01:00
|
|
|
}
|
|
|
|
|
i = (i + 1) & MAP_MASK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Color wasn't found in hashmap -- Add to system palette and map */
|
2016-09-24 09:35:32 +01:00
|
|
|
if (palette_nextIdx >= MAX_IDX) {
|
2016-09-22 19:11:56 +01:00
|
|
|
return -1; /* Return -1 for error if we've exceeded the palette capacity */
|
|
|
|
|
}
|
2016-09-24 09:35:32 +01:00
|
|
|
int idx = palette_nextIdx++;
|
2016-09-22 19:11:56 +01:00
|
|
|
|
2016-09-26 20:25:10 +01:00
|
|
|
/* Update internal palette table */
|
|
|
|
|
palette_palette[idx] = color;
|
|
|
|
|
|
2016-09-22 19:11:56 +01:00
|
|
|
/* Update system palette */
|
|
|
|
|
outp(0x03c8, idx);
|
|
|
|
|
outp(0x03c9, (color ) & 0x3f); /* r */
|
|
|
|
|
outp(0x03c9, (color >> 6) & 0x3f); /* g */
|
|
|
|
|
outp(0x03c9, (color >> 12) & 0x3f); /* b */
|
|
|
|
|
|
|
|
|
|
/* Add to hashmap and return idx */
|
2016-09-24 09:35:32 +01:00
|
|
|
palette_map[i].color = color;
|
|
|
|
|
palette_map[i].idx = idx;
|
2016-09-22 19:11:56 +01:00
|
|
|
return idx;
|
|
|
|
|
}
|
2016-09-26 20:25:10 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
int palette_idxToColor(int idx, int *rgb) {
|
|
|
|
|
/* Bounds check, return -1 on error */
|
|
|
|
|
if (idx <= 0 || idx >= MAX_IDX) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Convert 18bit (6bit-per-channel) internal color to 8bit-per-channel and
|
|
|
|
|
* store in array */
|
|
|
|
|
unsigned color = palette_palette[idx];
|
|
|
|
|
rgb[0] = (color & 0x0003f) << 2; /* r */
|
|
|
|
|
rgb[1] = (color & 0x00fc0) >> 4; /* g */
|
|
|
|
|
rgb[2] = (color & 0x3f000) >> 10; /* b */
|
|
|
|
|
|
|
|
|
|
/* Return 0 for ok */
|
|
|
|
|
return 0;
|
|
|
|
|
}
|