2017-03-22 04:23:23 +05:30
|
|
|
|
|
|
|
|
|
colors.c / colors.h
|
|
|
|
|
|
|
|
|
|
To convert in-game player name colors to html display.
|
|
|
|
|
|
|
|
|
|
References used:
|
|
|
|
|
http://www.rapidtables.com/convert/color/hsl-to-rgb.htm
|
|
|
|
|
http://www.rapidtables.com/convert/color/rgb-to-hsl.htm
|
|
|
|
|
https://gitlab.com/xonotic/xonstat/blob/master/xonstat/util.py
|
|
|
|
|
|
|
|
|
|
Overview:
|
|
|
|
|
|
2017-09-15 02:13:40 +05:30
|
|
|
|
This component is slightly based on util.py of XonStats, but the only
|
|
|
|
|
functionality needed is coloring the player's names. Since C programming
|
|
|
|
|
language does not have standard libraries for color model conversions and
|
|
|
|
|
regex, some functionality had to be self written. The function of interest
|
|
|
|
|
is:
|
2017-03-22 04:23:23 +05:30
|
|
|
|
def html_colors(qstr='', limit=None):
|
|
|
|
|
|
|
|
|
|
This component uses purely C standard library.
|
|
|
|
|
|
2017-09-15 02:13:40 +05:30
|
|
|
|
Advanced string manipulations such as replace and concatenation are
|
|
|
|
|
avoided. Instead, strings are printed in parts across functions.
|
2017-03-22 04:23:23 +05:30
|
|
|
|
|
|
|
|
|
There is only one instance of dynamic memory allocation.
|
|
|
|
|
void print_plname(const char *)
|
|
|
|
|
It both allocates, near the start, and frees memory at the end.
|
|
|
|
|
|
|
|
|
|
darkplaces Player Names & Colors
|
2017-09-15 02:13:40 +05:30
|
|
|
|
Players can add color themes to their names. They're expressed either
|
|
|
|
|
decimal or hexidecimal.
|
2017-03-22 04:23:23 +05:30
|
|
|
|
|
|
|
|
|
The decimal format follows
|
2017-09-15 02:13:40 +05:30
|
|
|
|
A character '^' that is not displayed, followed by a single digit
|
|
|
|
|
between 0 and 9.
|
2017-03-22 04:23:23 +05:30
|
|
|
|
The hexidecimal format follows
|
2017-09-15 02:13:40 +05:30
|
|
|
|
A string '^x' that is not displayed, followed by 3 digits between
|
|
|
|
|
0 - 0xF.
|
2017-03-22 04:23:23 +05:30
|
|
|
|
|
|
|
|
|
Python Regex to C Translation
|
|
|
|
|
|
|
|
|
|
The snippets from the original python code:
|
|
|
|
|
|
|
|
|
|
_all_colors = re.compile(r'\^(\d|x[\dA-Fa-f]{3})')
|
|
|
|
|
_dec_colors = re.compile(r'\^(\d)')
|
|
|
|
|
_hex_colors = re.compile(r'\^x([\dA-Fa-f])([\dA-Fa-f])([\dA-Fa-f])')
|
|
|
|
|
|
|
|
|
|
_dec_spans = [
|
|
|
|
|
"<span style='color:rgb(128,128,128)'>",
|
|
|
|
|
"<span style='color:rgb(255,0,0)'>",
|
|
|
|
|
"<span style='color:rgb(51,255,0)'>",
|
|
|
|
|
"<span style='color:rgb(255,255,0)'>",
|
|
|
|
|
"<span style='color:rgb(51,102,255)'>",
|
|
|
|
|
"<span style='color:rgb(51,255,255)'>",
|
|
|
|
|
"<span style='color:rgb(255,51,102)'>",
|
|
|
|
|
"<span style='color:rgb(255,255,255)'>",
|
|
|
|
|
"<span style='color:rgb(153,153,153)'>",
|
|
|
|
|
"<span style='color:rgb(128,128,128)'>"
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
...
|
|
|
|
|
|
|
|
|
|
def html_colors(qstr='', limit=None):
|
|
|
|
|
...
|
2017-09-15 02:13:40 +05:30
|
|
|
|
html = _dec_colors.sub(lambda match: _dec_spans[int(match.group(1))],
|
|
|
|
|
qstr)
|
2017-03-22 04:23:23 +05:30
|
|
|
|
html = _hex_colors.sub(hex_repl, html)
|
|
|
|
|
...
|
|
|
|
|
|
|
|
|
|
html = _dec_colors.sub(lambda match: _dec_spans[int(match.group(1))], qstr)
|
2017-09-15 02:13:40 +05:30
|
|
|
|
The character following a '^' is treated as an index to the array
|
|
|
|
|
'_dec_spans'. The corresponding element in '_dec_spans' replaces the
|
|
|
|
|
character '^' and the following digit in the string 'qstr'.
|
2017-03-22 04:23:23 +05:30
|
|
|
|
|
|
|
|
|
html = _hex_colors.sub(hex_repl, html)
|
2017-09-15 02:13:40 +05:30
|
|
|
|
The output of function 'hex_repl' replaces matching strings in html-
|
|
|
|
|
'^x' followed by 3 hexadecimal digits. The function 'hex_repl' has more
|
|
|
|
|
to do with the algorithms of color model conversions than it has to do
|
|
|
|
|
with regex rules.
|
2017-03-22 04:23:23 +05:30
|
|
|
|
|
2017-09-15 02:13:40 +05:30
|
|
|
|
The control flow to output similar results to the regex substitutions is
|
|
|
|
|
in the function
|
2017-03-22 04:23:23 +05:30
|
|
|
|
static void b(char * const str);
|
2017-09-15 02:13:40 +05:30
|
|
|
|
Unlike the python counterparts, it segments the player name into tokens and
|
|
|
|
|
prints strings also other strings instead of the sequences not intended to
|
|
|
|
|
be displayed.
|
2017-03-22 04:23:23 +05:30
|
|
|
|
|
|
|
|
|
Function Walkthrough
|
|
|
|
|
Sorted by caller to callee.
|
|
|
|
|
|
|
|
|
|
void print_plname(const char *)
|
2017-09-15 02:13:40 +05:30
|
|
|
|
const char * parameter is the player's name. It is used as a basis for
|
|
|
|
|
the variable 'copy'. 'copy' will always be the shorter character string.
|
2017-03-22 04:23:23 +05:30
|
|
|
|
|
|
|
|
|
This is function is intended to be used by the client file.
|
|
|
|
|
|
2017-09-15 02:13:40 +05:30
|
|
|
|
This function unconditionally allocates memory (calloc) and frees it at
|
|
|
|
|
the end.
|
2017-03-22 04:23:23 +05:30
|
|
|
|
|
2017-09-15 02:13:40 +05:30
|
|
|
|
By itself, it only removes extraneous instances of the character '^'.
|
|
|
|
|
It then calls the function
|
2017-03-22 04:23:23 +05:30
|
|
|
|
static void b(char * const)
|
|
|
|
|
where actual output occurs.
|
|
|
|
|
|
|
|
|
|
static void b(char * const)
|
2017-09-15 02:13:40 +05:30
|
|
|
|
const char * parameter is the player's name. The data pointed at by the
|
|
|
|
|
pointer is altered by function 'strtok', but the pointer itself is
|
|
|
|
|
never changed. Abstractly, fragments of the player's name are treated
|
|
|
|
|
as a command to print specific strings.
|
|
|
|
|
|
|
|
|
|
This function iterates once through the player's name. 'strtok'
|
|
|
|
|
segments the player's name; sequences between and not including '^'s
|
|
|
|
|
are treated as substrings. The first character of the substring is
|
|
|
|
|
checked for a digit inclusively between 0 and 9 for a decimal color
|
|
|
|
|
code. Exclusively or, checked for an 'x' and a numerical sequence
|
|
|
|
|
afterwards for a hexidecimal color code. If the substring does not have
|
|
|
|
|
either, it is printed like an ordinary string.
|
|
|
|
|
|
|
|
|
|
This function may not be adequate when a player's name intentionally
|
|
|
|
|
contains '^'.
|
2017-03-22 04:23:23 +05:30
|
|
|
|
|
|
|
|
|
static void hexspan(const char *)
|
2017-09-15 02:13:40 +05:30
|
|
|
|
const char * parameter is ideally a sequence of 3 hexidecimal digits.
|
|
|
|
|
Actually it is the entire substring from the callee. The first 3
|
|
|
|
|
elements are of interest as 3 separate single digit numerical values
|
|
|
|
|
and are explicitly separated to prevent function 'strtol' from
|
|
|
|
|
interpreting them as multidigit numbers. These 3 elements are rgb
|
|
|
|
|
values from the game engine.
|
|
|
|
|
Xonotic represents RGB values as a sequence of three digits 0 - 0xF.
|
|
|
|
|
Before conversion is to be done, they must be multiplied by 0xF so the
|
|
|
|
|
full range of values for RGB, 0 - 255 can be represented.
|
2017-03-22 04:23:23 +05:30
|
|
|
|
|
|
|
|
|
This function prints the an html span tag.
|
|
|
|
|
|
2017-09-15 02:13:40 +05:30
|
|
|
|
This function will first convert rgb to hsl to check if the colors are
|
|
|
|
|
too dark for the web page, and if so brighten up the colors then
|
|
|
|
|
reconvert to rgb.
|
2017-03-22 04:23:23 +05:30
|
|
|
|
|
|
|
|
|
static void decspan(const int)
|
|
|
|
|
const int parameter is a digit, the range being [0, 9].
|
|
|
|
|
|
2017-09-15 02:13:40 +05:30
|
|
|
|
This function is straightforward. It will print an html tag
|
|
|
|
|
corresponding to the const int parameter.
|
2017-03-22 04:23:23 +05:30
|
|
|
|
|
|
|
|
|
void hsl2rgb(struct Rgb *, const struct Hls const *)
|
2017-09-15 02:13:40 +05:30
|
|
|
|
First parameter, 'struct Rgb *' is the result of the conversion. It
|
|
|
|
|
does not need to be initialized.
|
|
|
|
|
Second parameter, 'const struct Hls const *' is the values and color
|
|
|
|
|
model to convert from and because, it must be initialized.
|
2017-03-22 04:23:23 +05:30
|
|
|
|
|
|
|
|
|
The math referenced from:
|
|
|
|
|
http://www.rapidtables.com/convert/color/hsl-to-rgb.htm
|
2017-09-15 02:13:40 +05:30
|
|
|
|
The implemenation deviates at the last 3 lines of code where the
|
|
|
|
|
results are finalized and placed in the output. The webpage does not
|
|
|
|
|
mention that rounding up is necessary. However it is, otherwise the
|
|
|
|
|
nonzero rgb values for the following colors
|
2017-03-22 04:23:23 +05:30
|
|
|
|
Silver (0<>,0%,75%)
|
|
|
|
|
Gray (0<>,0%,50%)
|
|
|
|
|
Maroon (0<>,100%,25%)
|
|
|
|
|
Olive (60<36>,100%,25%)
|
|
|
|
|
Green (120<32>,100%,25%)
|
|
|
|
|
Purple (300<30>,100%,25%)
|
|
|
|
|
Teal (180<38>,100%,25%)
|
|
|
|
|
Navy (240<34>,100%,25%)
|
|
|
|
|
will be off by one.
|
|
|
|
|
|
|
|
|
|
void rgb2hsl(struct Hls *, const struct Rgb const *)
|
2017-09-15 02:13:40 +05:30
|
|
|
|
First parameter, 'struct Hls *' is the result of the conversion. It
|
|
|
|
|
does not need to be initialized.
|
|
|
|
|
Second parameter, 'const struct Rgb const *' is the values and color
|
|
|
|
|
model to convert from and because, it must be initialized.
|
2017-03-22 04:23:23 +05:30
|
|
|
|
|
|
|
|
|
The math referenced from:
|
|
|
|
|
http://www.rapidtables.com/convert/color/rgb-to-hsl.htm
|
2017-09-15 02:13:40 +05:30
|
|
|
|
The implementation deviates when calculating hue, when Cmax is R'.
|
|
|
|
|
Instead of modulo, there is a summation by 6 when G' is less than B'.
|