2017-03-18 12:53:13 +05:30
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <math.h>
|
2017-03-19 08:53:17 +05:30
|
|
|
#include <ctype.h>
|
2017-03-18 13:52:24 +05:30
|
|
|
#include "colors.h"
|
2017-03-18 12:53:13 +05:30
|
|
|
#define MIN_CONTRAST 0.5
|
|
|
|
|
2017-03-18 13:52:24 +05:30
|
|
|
void hsl2rgb(struct Rgb *dest, const struct Hls const *src) {
|
|
|
|
if ((src -> h < 0 || 360 < src -> h) ||
|
|
|
|
(src -> s < 0 && 1 < src -> s) ||
|
|
|
|
(src -> l < 0 && 1 < src -> l)) {
|
2017-03-18 12:53:13 +05:30
|
|
|
return;
|
|
|
|
}
|
|
|
|
float r, g, b;
|
2017-03-20 10:52:12 +05:30
|
|
|
float hue = (src -> h)/60.0f;
|
|
|
|
const float chroma = (1 - fabs((2 * (src -> l)) - 1)) * (src -> s);
|
|
|
|
float x = chroma * (1 - fabs(fmod(hue, 2) - 1));
|
2017-03-18 13:19:05 +05:30
|
|
|
float m = (src -> l) - (chroma/2);
|
2017-03-20 10:52:12 +05:30
|
|
|
if (0 <= hue && hue < 1) {
|
2017-03-18 12:53:13 +05:30
|
|
|
r = chroma;
|
|
|
|
g = x;
|
|
|
|
b = 0;
|
2017-03-20 10:52:12 +05:30
|
|
|
} else if (1 <= hue && hue < 2) {
|
2017-03-18 12:53:13 +05:30
|
|
|
r = x;
|
|
|
|
g = chroma;
|
|
|
|
b = 0;
|
2017-03-20 10:52:12 +05:30
|
|
|
} else if (2 <= hue && hue < 3) {
|
2017-03-18 12:53:13 +05:30
|
|
|
r = 0;
|
|
|
|
g = chroma;
|
|
|
|
b = x;
|
2017-03-20 10:52:12 +05:30
|
|
|
} else if (3 <= hue && hue < 4) {
|
2017-03-18 12:53:13 +05:30
|
|
|
r = 0;
|
|
|
|
g = x;
|
|
|
|
b = chroma;
|
2017-03-20 10:52:12 +05:30
|
|
|
} else if (4 <= hue && hue < 5) {
|
2017-03-18 12:53:13 +05:30
|
|
|
r = x;
|
|
|
|
g = 0;
|
|
|
|
b = chroma;
|
2017-03-20 10:52:12 +05:30
|
|
|
} else if (5 <= hue && hue < 6) {
|
2017-03-18 12:53:13 +05:30
|
|
|
r = chroma;
|
|
|
|
g = 0;
|
|
|
|
b = x;
|
|
|
|
} else {
|
|
|
|
r = 0;
|
|
|
|
g = 0;
|
|
|
|
b = 0;
|
|
|
|
}
|
2017-03-18 13:19:05 +05:30
|
|
|
dest -> r = ceil((r + m) * 255);
|
|
|
|
dest -> g = ceil((g + m) * 255);
|
|
|
|
dest -> b = ceil((b + m) * 255);
|
2017-03-18 12:53:13 +05:30
|
|
|
}
|
|
|
|
|
2017-03-18 13:52:24 +05:30
|
|
|
void rgb2hsl(struct Hls *dest, const struct Rgb const *src) {
|
2017-03-18 12:53:13 +05:30
|
|
|
if (src == NULL || dest == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
2017-03-20 10:52:12 +05:30
|
|
|
float r = (src -> r) / 255.0f;
|
|
|
|
float g = (src -> g) / 255.0f;
|
|
|
|
float b = (src -> b) / 255.0f;
|
2017-03-18 12:53:13 +05:30
|
|
|
float min = fmin(fmin(r, g), b);
|
|
|
|
float max = fmax(fmax(r, g), b);
|
2017-03-20 10:52:12 +05:30
|
|
|
float chroma = max - min;
|
2017-03-18 12:53:13 +05:30
|
|
|
dest -> l = (max + min)/2; //bi-hexcone model.
|
2017-03-20 10:52:12 +05:30
|
|
|
if (chroma == 0) { // neutral color.
|
2017-03-18 12:53:13 +05:30
|
|
|
dest -> h = 0; // undefined.
|
|
|
|
dest -> s = 0.0f;
|
|
|
|
} else {
|
|
|
|
dest -> s = (dest -> l > 0.5) ? (chroma/(2 - max - min)) : (chroma/(max + min));
|
|
|
|
//piecewise function..
|
|
|
|
float hue;
|
|
|
|
if (max == r) {
|
2017-03-20 12:13:08 +05:30
|
|
|
hue = ((g - b)/chroma) + (g < b ? 6 : 0); // % 6 will break magenta (255, 0, 255)
|
2017-03-18 12:53:13 +05:30
|
|
|
} else if (max == g) {
|
|
|
|
hue = ((b - r)/chroma) + 2.0f;
|
|
|
|
} else {
|
|
|
|
hue = ((r - g)/chroma) + 4.0f;
|
|
|
|
}
|
|
|
|
dest -> h = (int)(hue * 60);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-10-19 09:51:02 +05:30
|
|
|
static const char* decspan(const int d) {
|
2017-03-18 12:53:13 +05:30
|
|
|
switch(d) {
|
|
|
|
case 0:
|
2024-10-19 09:51:02 +05:30
|
|
|
return "<span style='color:rgb(128,128,128)'>";
|
2017-03-18 12:53:13 +05:30
|
|
|
case 1:
|
2024-10-19 09:51:02 +05:30
|
|
|
return "<span style='color:rgb(255,0,0)'>";
|
2017-03-18 12:53:13 +05:30
|
|
|
case 2:
|
2024-10-19 09:51:02 +05:30
|
|
|
return "<span style='color:rgb(51,255,0)'>";
|
2017-03-18 12:53:13 +05:30
|
|
|
case 3:
|
2024-10-19 09:51:02 +05:30
|
|
|
return "<span style='color:rgb(255,255,0)'>";
|
2017-03-18 12:53:13 +05:30
|
|
|
case 4:
|
2024-10-19 09:51:02 +05:30
|
|
|
return "<span style='color:rgb(51,102,255)'>";
|
2017-03-18 12:53:13 +05:30
|
|
|
case 5:
|
2024-10-19 09:51:02 +05:30
|
|
|
return "<span style='color:rgb(51,255,255)'>";
|
2017-03-18 12:53:13 +05:30
|
|
|
case 6:
|
2024-10-19 09:51:02 +05:30
|
|
|
return "<span style='color:rgb(255,51,102)'>";
|
2017-03-18 12:53:13 +05:30
|
|
|
case 7:
|
2024-10-19 09:51:02 +05:30
|
|
|
return "<span style='color:rgb(255,255,255)'>";
|
2017-03-18 12:53:13 +05:30
|
|
|
case 8:
|
2024-10-19 09:51:02 +05:30
|
|
|
return "<span style='color:rgb(153,153,153)'>";
|
2017-03-18 12:53:13 +05:30
|
|
|
case 9:
|
2024-10-19 09:51:02 +05:30
|
|
|
return "<span style='color:rgb(128,128,128)'>";
|
2017-03-18 12:53:13 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-10-19 09:51:02 +05:30
|
|
|
static void hexspan(char *buf, int bufsize, const char *str) {
|
|
|
|
// length of ...
|
|
|
|
// "<span style=\"color:rgb(%d,%d,%d)\">"
|
|
|
|
// where each %d ranges from 0 to 255
|
|
|
|
// char buf[40];
|
2017-03-18 12:53:13 +05:30
|
|
|
const char h1[2] = {str[0], '\0'};
|
|
|
|
const char h2[2] = {str[1], '\0'};
|
|
|
|
const char h3[2] = {str[2], '\0'};
|
|
|
|
struct Rgb nrgb;
|
2017-03-20 10:52:12 +05:30
|
|
|
// max value for a color code in darkplaces = 0xF
|
|
|
|
// 0xF * 0xF = 255, max value for rgb
|
|
|
|
nrgb.r = strtol(h1, NULL, 16) * 0xF;
|
|
|
|
nrgb.g = strtol(h2, NULL, 16) * 0xF;
|
|
|
|
nrgb.b = strtol(h3, NULL, 16) * 0xF;
|
2017-03-18 12:53:13 +05:30
|
|
|
struct Hls nhls;
|
2017-03-18 13:52:24 +05:30
|
|
|
rgb2hsl(&nhls, &nrgb);
|
2017-03-18 12:53:13 +05:30
|
|
|
if (nhls.l < MIN_CONTRAST) {
|
|
|
|
nhls.l = MIN_CONTRAST;
|
2017-03-18 13:52:24 +05:30
|
|
|
hsl2rgb(&nrgb, &nhls);
|
2017-03-18 12:53:13 +05:30
|
|
|
}
|
2024-10-19 09:51:02 +05:30
|
|
|
int wrote = snprintf(
|
|
|
|
buf, bufsize,
|
|
|
|
"<span style=\"color:rgb(%d,%d,%d)\">",
|
|
|
|
nrgb.r, nrgb.g, nrgb.b);
|
|
|
|
// output = buf;
|
2017-03-18 12:53:13 +05:30
|
|
|
}
|
|
|
|
|
2024-10-19 09:51:02 +05:30
|
|
|
#define TAG_LEN 40
|
|
|
|
static void colorize_noalloc(char * const str) {
|
2017-03-18 12:53:13 +05:30
|
|
|
char *token = strtok(str, "^");
|
|
|
|
char c;
|
|
|
|
while (token) {
|
|
|
|
c = token[0];
|
2017-03-19 08:53:17 +05:30
|
|
|
if (isdigit(c)) {
|
2024-10-19 09:51:02 +05:30
|
|
|
printf( decspan(c - '0') );
|
2017-03-19 08:53:17 +05:30
|
|
|
if (strlen(token) > 1) {
|
|
|
|
printf("%s", token + 1);
|
|
|
|
}
|
2017-03-20 10:52:12 +05:30
|
|
|
printf("</span>");
|
2017-03-19 14:16:32 +05:30
|
|
|
} else if ((c == 'x' && strlen(token) > 3) &&
|
|
|
|
(isxdigit(token[1]) &&
|
|
|
|
isxdigit(token[2]) &&
|
|
|
|
isxdigit(token[3]))) {
|
2024-10-19 09:51:02 +05:30
|
|
|
char tag[TAG_LEN];
|
|
|
|
hexspan(tag, TAG_LEN, token + 1);
|
|
|
|
printf( tag ); //exclude x
|
2017-03-19 14:16:32 +05:30
|
|
|
if (strlen(token) > 4){
|
|
|
|
printf("%s", token + 4);
|
2017-03-19 08:53:17 +05:30
|
|
|
}
|
2017-03-19 14:16:32 +05:30
|
|
|
printf("</span>");
|
2017-03-18 12:53:13 +05:30
|
|
|
} else {
|
|
|
|
printf("%s", token);
|
|
|
|
}
|
|
|
|
token = strtok(NULL, "^");
|
|
|
|
}
|
2024-10-19 09:51:02 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
static void sanitize(char *user_name) {
|
|
|
|
if (user_name == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
char *pos = user_name;
|
|
|
|
while (pos = strstr(pos, "^^")) {
|
|
|
|
strcpy(pos, (pos + 1));
|
|
|
|
}
|
2017-03-18 12:53:13 +05:30
|
|
|
}
|
|
|
|
|
2017-03-18 13:52:24 +05:30
|
|
|
void print_plname(const char* str) {
|
2017-03-18 12:53:13 +05:30
|
|
|
//find instance of ^^
|
|
|
|
//replace with ^
|
|
|
|
//concatenate with rest of the string
|
|
|
|
char *copy;
|
|
|
|
copy = calloc(strlen(str) + 1, sizeof(char));
|
|
|
|
strcpy(copy, str);
|
2024-10-19 09:51:02 +05:30
|
|
|
sanitize(copy);
|
|
|
|
colorize_noalloc(copy);
|
|
|
|
fflush(stdout);
|
2017-03-18 12:53:13 +05:30
|
|
|
free(copy);
|
|
|
|
}
|
|
|
|
|
2024-10-19 09:51:02 +05:30
|
|
|
static char* append_to_str(char *dest, const char *src) {
|
|
|
|
if (dest == NULL || src == NULL) {
|
|
|
|
fprintf(stderr, "append_to_str(): warning - received null ptr" );
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
size_t new_len = strlen(dest) + strlen(src) + 1;
|
|
|
|
char *new_str = realloc(dest, new_len);
|
|
|
|
if (new_str != NULL) {
|
|
|
|
strcat(new_str, src);
|
|
|
|
}
|
|
|
|
return new_str;
|
|
|
|
}
|
|
|
|
|
|
|
|
// the most colorful names are the longest
|
|
|
|
// names with 8 colors can go to 400 chars
|
|
|
|
char* colorize_name(char *buf, /*int bufsize,*/ char * const str) {
|
|
|
|
char *token = strtok(str, "^");
|
|
|
|
char c;
|
|
|
|
// unsigned int i = 0;
|
|
|
|
while (token) {
|
|
|
|
c = token[0];
|
|
|
|
if (isdigit(c)) {
|
|
|
|
// printf("%i : %s\n", i, buf);;
|
|
|
|
buf = append_to_str(buf, decspan(c - '0') );
|
|
|
|
if (strlen(token) > 1) {
|
|
|
|
buf = append_to_str(buf, token + 1);
|
|
|
|
}
|
|
|
|
buf = append_to_str(buf, "</span>");
|
|
|
|
} else if ((c == 'x' && strlen(token) > 3) &&
|
|
|
|
(isxdigit(token[1]) &&
|
|
|
|
isxdigit(token[2]) &&
|
|
|
|
isxdigit(token[3]))) {
|
|
|
|
char tag[TAG_LEN];
|
|
|
|
hexspan(tag, TAG_LEN, token + 1); //exclude x
|
|
|
|
buf = append_to_str(buf, tag );
|
|
|
|
if (strlen(token) > 4){
|
|
|
|
buf = append_to_str(buf, token + 4);
|
|
|
|
}
|
|
|
|
buf = append_to_str(buf, "</span>");
|
|
|
|
} else {
|
|
|
|
buf = append_to_str(buf, token);
|
|
|
|
}
|
|
|
|
token = strtok(NULL, "^");
|
|
|
|
// i++;
|
|
|
|
}
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* test:
|
|
|
|
|
|
|
|
./colors ^9[^1S^9]^x469Kom^0ier^7
|
|
|
|
./colors ^9[^1S^9]^^x469Kom^0ier^7
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef COLORS4PYTHON
|
|
|
|
int main(int argc, const char **argv) {
|
|
|
|
if (argc < 1) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
char *colored = (char*)calloc(strlen(argv[1]) + 1, sizeof(char));
|
|
|
|
char *player_name = (char*)calloc(strlen(argv[1]) + 1, sizeof(char));
|
|
|
|
strcpy(player_name, argv[1]);
|
|
|
|
sanitize(player_name);
|
|
|
|
|
|
|
|
colored = colorize_name(colored, /*sizeof(colored),*/ player_name);
|
|
|
|
fprintf(stdout, "%s\n", colored);
|
|
|
|
|
|
|
|
// clean up
|
|
|
|
fflush(stdout);
|
|
|
|
free(colored);
|
|
|
|
free(player_name);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|