doc-colors.txt 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. colors.c / colors.h
  2. To convert in-game player name colors to html display.
  3. References used:
  4. http://www.rapidtables.com/convert/color/hsl-to-rgb.htm
  5. http://www.rapidtables.com/convert/color/rgb-to-hsl.htm
  6. https://gitlab.com/xonotic/xonstat/blob/master/xonstat/util.py
  7. Overview:
  8. This component is slightly based on util.py of XonStats, but the only
  9. functionality needed is coloring the player's names. Since C programming
  10. language does not have standard libraries for color model conversions and
  11. regex, some functionality had to be self written. The function of interest
  12. is:
  13. def html_colors(qstr='', limit=None):
  14. This component uses purely C standard library.
  15. Advanced string manipulations such as replace and concatenation are
  16. avoided. Instead, strings are printed in parts across functions.
  17. There is only one instance of dynamic memory allocation.
  18. void print_plname(const char *)
  19. It both allocates, near the start, and frees memory at the end.
  20. darkplaces Player Names & Colors
  21. Players can add color themes to their names. They're expressed either
  22. decimal or hexidecimal.
  23. The decimal format follows
  24. A character '^' that is not displayed, followed by a single digit
  25. between 0 and 9.
  26. The hexidecimal format follows
  27. A string '^x' that is not displayed, followed by 3 digits between
  28. 0 - 0xF.
  29. Python Regex to C Translation
  30. The snippets from the original python code:
  31. _all_colors = re.compile(r'\^(\d|x[\dA-Fa-f]{3})')
  32. _dec_colors = re.compile(r'\^(\d)')
  33. _hex_colors = re.compile(r'\^x([\dA-Fa-f])([\dA-Fa-f])([\dA-Fa-f])')
  34. _dec_spans = [
  35. "<span style='color:rgb(128,128,128)'>",
  36. "<span style='color:rgb(255,0,0)'>",
  37. "<span style='color:rgb(51,255,0)'>",
  38. "<span style='color:rgb(255,255,0)'>",
  39. "<span style='color:rgb(51,102,255)'>",
  40. "<span style='color:rgb(51,255,255)'>",
  41. "<span style='color:rgb(255,51,102)'>",
  42. "<span style='color:rgb(255,255,255)'>",
  43. "<span style='color:rgb(153,153,153)'>",
  44. "<span style='color:rgb(128,128,128)'>"
  45. ]
  46. ...
  47. def html_colors(qstr='', limit=None):
  48. ...
  49. html = _dec_colors.sub(lambda match: _dec_spans[int(match.group(1))],
  50. qstr)
  51. html = _hex_colors.sub(hex_repl, html)
  52. ...
  53. html = _dec_colors.sub(lambda match: _dec_spans[int(match.group(1))], qstr)
  54. The character following a '^' is treated as an index to the array
  55. '_dec_spans'. The corresponding element in '_dec_spans' replaces the
  56. character '^' and the following digit in the string 'qstr'.
  57. html = _hex_colors.sub(hex_repl, html)
  58. The output of function 'hex_repl' replaces matching strings in html-
  59. '^x' followed by 3 hexadecimal digits. The function 'hex_repl' has more
  60. to do with the algorithms of color model conversions than it has to do
  61. with regex rules.
  62. The control flow to output similar results to the regex substitutions is
  63. in the function
  64. static void b(char * const str);
  65. Unlike the python counterparts, it segments the player name into tokens and
  66. prints strings also other strings instead of the sequences not intended to
  67. be displayed.
  68. Function Walkthrough
  69. Sorted by caller to callee.
  70. void print_plname(const char *)
  71. const char * parameter is the player's name. It is used as a basis for
  72. the variable 'copy'. 'copy' will always be the shorter character string.
  73. This is function is intended to be used by the client file.
  74. This function unconditionally allocates memory (calloc) and frees it at
  75. the end.
  76. By itself, it only removes extraneous instances of the character '^'.
  77. It then calls the function
  78. static void b(char * const)
  79. where actual output occurs.
  80. static void b(char * const)
  81. const char * parameter is the player's name. The data pointed at by the
  82. pointer is altered by function 'strtok', but the pointer itself is
  83. never changed. Abstractly, fragments of the player's name are treated
  84. as a command to print specific strings.
  85. This function iterates once through the player's name. 'strtok'
  86. segments the player's name; sequences between and not including '^'s
  87. are treated as substrings. The first character of the substring is
  88. checked for a digit inclusively between 0 and 9 for a decimal color
  89. code. Exclusively or, checked for an 'x' and a numerical sequence
  90. afterwards for a hexidecimal color code. If the substring does not have
  91. either, it is printed like an ordinary string.
  92. This function may not be adequate when a player's name intentionally
  93. contains '^'.
  94. static void hexspan(const char *)
  95. const char * parameter is ideally a sequence of 3 hexidecimal digits.
  96. Actually it is the entire substring from the callee. The first 3
  97. elements are of interest as 3 separate single digit numerical values
  98. and are explicitly separated to prevent function 'strtol' from
  99. interpreting them as multidigit numbers. These 3 elements are rgb
  100. values from the game engine.
  101. Xonotic represents RGB values as a sequence of three digits 0 - 0xF.
  102. Before conversion is to be done, they must be multiplied by 0xF so the
  103. full range of values for RGB, 0 - 255 can be represented.
  104. This function prints the an html span tag.
  105. This function will first convert rgb to hsl to check if the colors are
  106. too dark for the web page, and if so brighten up the colors then
  107. reconvert to rgb.
  108. static void decspan(const int)
  109. const int parameter is a digit, the range being [0, 9].
  110. This function is straightforward. It will print an html tag
  111. corresponding to the const int parameter.
  112. void hsl2rgb(struct Rgb *, const struct Hls const *)
  113. First parameter, 'struct Rgb *' is the result of the conversion. It
  114. does not need to be initialized.
  115. Second parameter, 'const struct Hls const *' is the values and color
  116. model to convert from and because, it must be initialized.
  117. The math referenced from:
  118. http://www.rapidtables.com/convert/color/hsl-to-rgb.htm
  119. The implemenation deviates at the last 3 lines of code where the
  120. results are finalized and placed in the output. The webpage does not
  121. mention that rounding up is necessary. However it is, otherwise the
  122. nonzero rgb values for the following colors
  123. Silver (0°,0%,75%)
  124. Gray (0°,0%,50%)
  125. Maroon (0°,100%,25%)
  126. Olive (60°,100%,25%)
  127. Green (120°,100%,25%)
  128. Purple (300°,100%,25%)
  129. Teal (180°,100%,25%)
  130. Navy (240°,100%,25%)
  131. will be off by one.
  132. void rgb2hsl(struct Hls *, const struct Rgb const *)
  133. First parameter, 'struct Hls *' is the result of the conversion. It
  134. does not need to be initialized.
  135. Second parameter, 'const struct Rgb const *' is the values and color
  136. model to convert from and because, it must be initialized.
  137. The math referenced from:
  138. http://www.rapidtables.com/convert/color/rgb-to-hsl.htm
  139. The implementation deviates when calculating hue, when Cmax is R'.
  140. Instead of modulo, there is a summation by 6 when G' is less than B'.