关键词搜索

源码搜索 ×
×

漫话Redis源码之四十九

发布2022-01-02浏览494次

详情内容

这里主要是Canvas相关的代码,一看就是跟颜色、位置相关,非核心代码,无需过度解读和分析。

在阅读源码时,一定要有粗有细,不能眉毛胡子一把抓。

  1. /*
  2. * Copyright (c) 2019, Salvatore Sanfilippo <antirez at gmail dot com>
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. *
  8. * * Redistributions of source code must retain the above copyright notice,
  9. * this list of conditions and the following disclaimer.
  10. * * Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * * Neither the name of Redis nor the names of its contributors may be used
  14. * to endorse or promote products derived from this software without
  15. * specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  18. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  21. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  22. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  23. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  24. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  25. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  26. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  27. * POSSIBILITY OF SUCH DAMAGE.
  28. *
  29. * ----------------------------------------------------------------------------
  30. *
  31. * This file implements the LOLWUT command. The command should do something
  32. * fun and interesting, and should be replaced by a new implementation at
  33. * each new version of Redis.
  34. *
  35. * Thanks to Michele Hiki Falcone for the original image that ispired
  36. * the image, part of his game, Plaguemon.
  37. *
  38. * Thanks to the Shhh computer art collective for the help in tuning the
  39. * output to have a better artistic effect.
  40. */
  41. #include "server.h"
  42. #include "lolwut.h"
  43. /* Render the canvas using the four gray levels of the standard color
  44. * terminal: they match very well to the grayscale display of the gameboy. */
  45. static sds renderCanvas(lwCanvas *canvas) {
  46. sds text = sdsempty();
  47. for (int y = 0; y < canvas->height; y++) {
  48. for (int x = 0; x < canvas->width; x++) {
  49. int color = lwGetPixel(canvas,x,y);
  50. char *ce; /* Color escape sequence. */
  51. /* Note that we set both the foreground and background color.
  52. * This way we are able to get a more consistent result among
  53. * different terminals implementations. */
  54. switch(color) {
  55. case 0: ce = "0;30;40m"; break; /* Black */
  56. case 1: ce = "0;90;100m"; break; /* Gray 1 */
  57. case 2: ce = "0;37;47m"; break; /* Gray 2 */
  58. case 3: ce = "0;97;107m"; break; /* White */
  59. default: ce = "0;30;40m"; break; /* Just for safety. */
  60. }
  61. text = sdscatprintf(text,"\033[%s \033[0m",ce);
  62. }
  63. if (y != canvas->height-1) text = sdscatlen(text,"\n",1);
  64. }
  65. return text;
  66. }
  67. /* Draw a skyscraper on the canvas, according to the parameters in the
  68. * 'skyscraper' structure. Window colors are random and are always one
  69. * of the two grays. */
  70. struct skyscraper {
  71. int xoff; /* X offset. */
  72. int width; /* Pixels width. */
  73. int height; /* Pixels height. */
  74. int windows; /* Draw windows if true. */
  75. int color; /* Color of the skyscraper. */
  76. };
  77. void generateSkyscraper(lwCanvas *canvas, struct skyscraper *si) {
  78. int starty = canvas->height-1;
  79. int endy = starty - si->height + 1;
  80. for (int y = starty; y >= endy; y--) {
  81. for (int x = si->xoff; x < si->xoff+si->width; x++) {
  82. /* The roof is four pixels less wide. */
  83. if (y == endy && (x <= si->xoff+1 || x >= si->xoff+si->width-2))
  84. continue;
  85. int color = si->color;
  86. /* Alter the color if this is a place where we want to
  87. * draw a window. We check that we are in the inner part of the
  88. * skyscraper, so that windows are far from the borders. */
  89. if (si->windows &&
  90. x > si->xoff+1 &&
  91. x < si->xoff+si->width-2 &&
  92. y > endy+1 &&
  93. y < starty-1)
  94. {
  95. /* Calculate the x,y position relative to the start of
  96. * the window area. */
  97. int relx = x - (si->xoff+1);
  98. int rely = y - (endy+1);
  99. /* Note that we want the windows to be two pixels wide
  100. * but just one pixel tall, because terminal "pixels"
  101. * (characters) are not square. */
  102. if (relx/2 % 2 && rely % 2) {
  103. do {
  104. color = 1 + rand() % 2;
  105. } while (color == si->color);
  106. /* Except we want adjacent pixels creating the same
  107. * window to be the same color. */
  108. if (relx % 2) color = lwGetPixel(canvas,x-1,y);
  109. }
  110. }
  111. lwDrawPixel(canvas,x,y,color);
  112. }
  113. }
  114. }
  115. /* Generate a skyline inspired by the parallax backgrounds of 8 bit games. */
  116. void generateSkyline(lwCanvas *canvas) {
  117. struct skyscraper si;
  118. /* First draw the background skyscraper without windows, using the
  119. * two different grays. We use two passes to make sure that the lighter
  120. * ones are always in the background. */
  121. for (int color = 2; color >= 1; color--) {
  122. si.color = color;
  123. for (int offset = -10; offset < canvas->width;) {
  124. offset += rand() % 8;
  125. si.xoff = offset;
  126. si.width = 10 + rand()%9;
  127. if (color == 2)
  128. si.height = canvas->height/2 + rand()%canvas->height/2;
  129. else
  130. si.height = canvas->height/2 + rand()%canvas->height/3;
  131. si.windows = 0;
  132. generateSkyscraper(canvas, &si);
  133. if (color == 2)
  134. offset += si.width/2;
  135. else
  136. offset += si.width+1;
  137. }
  138. }
  139. /* Now draw the foreground skyscraper with the windows. */
  140. si.color = 0;
  141. for (int offset = -10; offset < canvas->width;) {
  142. offset += rand() % 8;
  143. si.xoff = offset;
  144. si.width = 5 + rand()%14;
  145. if (si.width % 4) si.width += (si.width % 3);
  146. si.height = canvas->height/3 + rand()%canvas->height/2;
  147. si.windows = 1;
  148. generateSkyscraper(canvas, &si);
  149. offset += si.width+5;
  150. }
  151. }
  152. /* The LOLWUT 6 command:
  153. *
  154. * LOLWUT [columns] [rows]
  155. *
  156. * By default the command uses 80 columns, 40 squares per row
  157. * per column.
  158. */
  159. void lolwut6Command(client *c) {
  160. long cols = 80;
  161. long rows = 20;
  162. /* Parse the optional arguments if any. */
  163. if (c->argc > 1 &&
  164. getLongFromObjectOrReply(c,c->argv[1],&cols,NULL) != C_OK)
  165. return;
  166. if (c->argc > 2 &&
  167. getLongFromObjectOrReply(c,c->argv[2],&rows,NULL) != C_OK)
  168. return;
  169. /* Limits. We want LOLWUT to be always reasonably fast and cheap to execute
  170. * so we have maximum number of columns, rows, and output resulution. */
  171. if (cols < 1) cols = 1;
  172. if (cols > 1000) cols = 1000;
  173. if (rows < 1) rows = 1;
  174. if (rows > 1000) rows = 1000;
  175. /* Generate the city skyline and reply. */
  176. lwCanvas *canvas = lwCreateCanvas(cols,rows,3);
  177. generateSkyline(canvas);
  178. sds rendered = renderCanvas(canvas);
  179. rendered = sdscat(rendered,
  180. "\nDedicated to the 8 bit game developers of past and present.\n"
  181. "Original 8 bit image from Plaguemon by hikikomori. Redis ver. ");
  182. rendered = sdscat(rendered,REDIS_VERSION);
  183. rendered = sdscatlen(rendered,"\n",1);
  184. addReplyVerbatim(c,rendered,sdslen(rendered),"txt");
  185. sdsfree(rendered);
  186. lwFreeCanvas(canvas);
  187. }

相关技术文章

点击QQ咨询
开通会员
返回顶部
×
微信扫码支付
微信扫码支付
确定支付下载
请使用微信描二维码支付
×

提示信息

×

选择支付方式

  • 微信支付
  • 支付宝付款
确定支付下载