123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- 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:
- 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:
- def html_colors(qstr='', limit=None):
- This component uses purely C standard library.
- Advanced string manipulations such as replace and concatenation are
- avoided. Instead, strings are printed in parts across functions.
- 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
- Players can add color themes to their names. They're expressed either
- decimal or hexidecimal.
- The decimal format follows
- A character '^' that is not displayed, followed by a single digit
- between 0 and 9.
- The hexidecimal format follows
- A string '^x' that is not displayed, followed by 3 digits between
- 0 - 0xF.
- 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):
- ...
- html = _dec_colors.sub(lambda match: _dec_spans[int(match.group(1))],
- qstr)
- html = _hex_colors.sub(hex_repl, html)
- ...
- html = _dec_colors.sub(lambda match: _dec_spans[int(match.group(1))], qstr)
- 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'.
- html = _hex_colors.sub(hex_repl, html)
- 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.
- The control flow to output similar results to the regex substitutions is
- in the function
- static void b(char * const str);
- 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.
- Function Walkthrough
- Sorted by caller to callee.
- void print_plname(const char *)
- 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.
- This is function is intended to be used by the client file.
- This function unconditionally allocates memory (calloc) and frees it at
- the end.
- By itself, it only removes extraneous instances of the character '^'.
- It then calls the function
- static void b(char * const)
- where actual output occurs.
- static void b(char * const)
- 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 '^'.
- static void hexspan(const char *)
- 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.
- This function prints the an html span tag.
- 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.
- static void decspan(const int)
- const int parameter is a digit, the range being [0, 9].
- This function is straightforward. It will print an html tag
- corresponding to the const int parameter.
- void hsl2rgb(struct Rgb *, const struct Hls const *)
- 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.
- The math referenced from:
- http://www.rapidtables.com/convert/color/hsl-to-rgb.htm
- 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
- Silver (0°,0%,75%)
- Gray (0°,0%,50%)
- Maroon (0°,100%,25%)
- Olive (60°,100%,25%)
- Green (120°,100%,25%)
- Purple (300°,100%,25%)
- Teal (180°,100%,25%)
- Navy (240°,100%,25%)
- will be off by one.
- void rgb2hsl(struct Hls *, const struct Rgb const *)
- 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.
- The math referenced from:
- http://www.rapidtables.com/convert/color/rgb-to-hsl.htm
- 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'.
|