1/* $NetBSD: testpat.c,v 1.6 2021/11/13 20:59:13 nat Exp $ */ 2 3/*- 4 * Copyright (c) 2016 Nathanial Sloss <nathanialsloss@yahoo.com.au> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28#include <sys/cdefs.h> 29__RCSID("$NetBSD: testpat.c,v 1.6 2021/11/13 20:59:13 nat Exp $"); 30 31#include <sys/types.h> 32#include <sys/time.h> 33 34#include <curses.h> 35#include <err.h> 36#include <errno.h> 37#include <math.h> 38#include <stdio.h> 39#include <stdlib.h> 40#include <string.h> 41#include <time.h> 42 43static int colour_list[6] = { 44 COLOR_YELLOW, 45 COLOR_CYAN, 46 COLOR_GREEN, 47 COLOR_MAGENTA, 48 COLOR_RED, 49 COLOR_BLUE, 50}; 51static int numcolours = (int)__arraycount(colour_list); 52 53int main(int argc, char *argv[]) { 54 int i, col, colour, line, x_limit, y_limit, colourOK, spacing; 55 int xpos, ypos, spacing_residual, spacing_start, spacing_end; 56 int grid_x, grid_y, **circle_pos; 57 size_t ncpos; 58 float grid_unit; 59 const char *title = "NetBSD"; 60 float coord_x, circle_int; 61 float a_axis, b_axis; 62 63 if (!initscr()) { 64 errx(EXIT_FAILURE, "Unknown terminal type"); 65 } 66 67 curs_set(0); 68 69 if (argc > 2) { 70 endwin(); 71 fprintf(stderr, "Usage: %s <title>", getprogname()); 72 return EXIT_FAILURE; 73 } 74 75 if (argc == 2) { 76 title = argv[1]; 77 if (strlen(title) >= (size_t)COLS) { 78 endwin(); 79 errx(EXIT_FAILURE, 80 "Title string is longer than display cols"); 81 } 82 } 83 84 colourOK = has_colors(); 85 86 if (COLS < 13 || LINES < 13) { 87 endwin(); 88 errx(EXIT_FAILURE, "Terminal size must be at least 72x25."); 89 } 90 91 if (colourOK) { 92 start_color(); 93 94 init_pair(0, COLOR_WHITE, COLOR_BLACK); 95 init_pair(1, COLOR_WHITE, COLOR_RED); 96 init_pair(2, COLOR_WHITE, COLOR_GREEN); 97 init_pair(3, COLOR_WHITE, COLOR_YELLOW); 98 init_pair(4, COLOR_WHITE, COLOR_BLUE); 99 init_pair(5, COLOR_WHITE, COLOR_MAGENTA); 100 init_pair(6, COLOR_WHITE, COLOR_CYAN); 101 init_pair(7, COLOR_BLACK, COLOR_WHITE); 102 103 attrset(COLOR_PAIR(0)); 104 } 105 106 x_limit = (COLS - 1) / 2; 107 x_limit = x_limit * 2; 108 y_limit = (LINES - 2) / 2; 109 y_limit = y_limit * 2; 110 spacing = 2 * y_limit / numcolours; 111 spacing_residual = ((2 * y_limit) % numcolours) / 2; 112 a_axis = y_limit / 2; 113 b_axis = y_limit; 114 grid_unit = b_axis / 13; 115 grid_y = grid_unit; 116 grid_x = grid_unit * 2; 117 118 119 ncpos = y_limit * sizeof(*circle_pos) 120 + y_limit * 2 * sizeof(**circle_pos); 121 circle_pos = malloc(ncpos); 122 if (circle_pos == NULL) { 123 endwin(); 124 errx(EXIT_FAILURE, "Can't allocate circle positions"); 125 } 126 for (i = 0; i < y_limit; i++) { 127 circle_pos[i] = (void *)&circle_pos[y_limit + i * 2]; 128 circle_pos[i][0] = circle_pos[i][1] = -1; 129 } 130 131 for (i = 0; i < y_limit; i++) { 132 /* Draw an ellipse (looks more circular.) */ 133 circle_int = (i - a_axis) / a_axis; 134 circle_int = 1 - powf(circle_int, 2); 135 circle_int = circle_int * powf(b_axis, 2); 136#if 0 137 /* Draw a circle, commented out as elipse looks better.*/ 138 circle_int = powf(a_axis, 2) - powf(i - a_axis, 2); 139#endif 140 coord_x = sqrtf(circle_int); 141 circle_pos[i][0] = (-coord_x + ((float)x_limit / 2)); 142 circle_pos[i][1] = (coord_x + ((float)x_limit / 2)); 143 } 144 145 clear(); 146 147 attron(A_ALTCHARSET); 148 move(0, 0); 149 150 /* Draw a grid. */ 151 for (line = 1; line < y_limit; line += grid_y) { 152 for (col = 1; col < x_limit; col = col + grid_x) { 153 xpos = col; 154 while ((xpos < col + grid_x - 1) && (xpos < 155 x_limit)) { 156 mvaddch(line + grid_y - 1, xpos, 113 | 157 A_ALTCHARSET); 158 xpos++; 159 } 160 if (xpos < x_limit) 161 mvaddch(line + grid_y - 1, xpos, 110 | 162 A_ALTCHARSET); 163 } 164 ypos = line; 165 while (ypos < line + grid_y - 1) { 166 for (col = grid_x - 1; col < x_limit; col += grid_x) { 167 mvaddch(ypos, col + 1, 120 | A_ALTCHARSET); 168 } 169 ypos++; 170 } 171 } 172 173 for (line = 1; line < y_limit; line += grid_y) { 174 mvaddch(line + grid_y - 1, 0, 116 | A_ALTCHARSET); 175 mvaddch(line + grid_y - 1, x_limit, 117 | A_ALTCHARSET); 176 177 ypos = line; 178 while (ypos < line + grid_y - 1) { 179 mvaddch(ypos, 0, 120 | A_ALTCHARSET); 180 mvaddch(ypos, x_limit, 120 | A_ALTCHARSET); 181 ypos++; 182 } 183 } 184 185 for (col = 1; col < x_limit; col += grid_x) { 186 mvaddch(0, col + grid_x - 1, 119 | A_ALTCHARSET); 187 mvaddch(y_limit, col + grid_x - 1, 118 | A_ALTCHARSET); 188 189 xpos = col; 190 while ((xpos < col + grid_x - 1) && (xpos < x_limit)) { 191 mvaddch(0, xpos, 113 | A_ALTCHARSET); 192 mvaddch(y_limit, xpos, 113 | A_ALTCHARSET); 193 xpos++; 194 } 195 } 196 197 mvaddch(0, 0, 108 | A_ALTCHARSET); 198 mvaddch(0, x_limit, 107 | A_ALTCHARSET); 199 mvaddch(y_limit, 0, 109 | A_ALTCHARSET); 200 mvaddch(y_limit, x_limit, 106 | A_ALTCHARSET); 201 202 /* Draw a white circle. */ 203 for (i = 1; i < y_limit; i++) { 204 for (col = circle_pos[i][0]; col <= circle_pos[i][1]; col++) { 205 mvaddch(i, col, 32 | A_REVERSE); 206 } 207 } 208 209 /* Add title segment. */ 210 for (i = roundf(1 * grid_unit); i < roundf(2 * grid_unit); i++) { 211 if (colourOK) 212 attrset(COLOR_PAIR(COLOR_BLACK)); 213 else 214 attrset(A_NORMAL); 215 216 for (col = roundf((4 * grid_unit * 2) + 217 circle_pos[y_limit / 2][0]); col <= roundf((9 * grid_unit 218 * 2) + circle_pos[y_limit / 2][0]); col++) 219 mvaddch(i, col, ' '); 220 } 221 222 i = roundf(1.4 * grid_unit); 223 224 if (!colourOK) 225 attrset(A_NORMAL); 226 227 col = y_limit - (strlen(title) / 2) + circle_pos[y_limit / 2][0]; 228 mvprintw(i, col, "%s", title); 229 230 /* Add black segments at top. */ 231 for (line = roundf(2 * grid_unit); line < 4 * grid_unit; line++) { 232 if (colourOK) 233 attrset(COLOR_PAIR(COLOR_BLACK)); 234 else 235 attrset(A_NORMAL); 236 237 for (col = 0; col <= roundf((3.5 * grid_unit * 2)); col++) { 238 xpos = col + circle_pos[y_limit / 2][0]; 239 if (xpos >= circle_pos[line][0] && 240 xpos <= circle_pos[line][1]) 241 mvaddch(line, xpos, ' '); 242 } 243 244 for (col = roundf((9.5 * grid_unit * 2)); col < 245 roundf((13 * grid_unit * 2)); col++) { 246 xpos = col + circle_pos[y_limit / 2][0]; 247 if (xpos >= circle_pos[line][0] && 248 xpos <= circle_pos[line][1]) 249 mvaddch(line, xpos, ' '); 250 } 251 } 252 253 /* Add black and white squares close to top. */ 254 int gap = (circle_pos[(int)(5 * grid_unit)][1] - 255 circle_pos[(int)(5 * grid_unit)][0]) / 13; 256 257 for (i = roundf(3 * grid_unit); i < roundf(4 * grid_unit); i++) { 258 for (xpos = 0; xpos <= x_limit; xpos += 2 * gap) { 259 if (colourOK) 260 attrset(COLOR_PAIR(COLOR_BLACK)); 261 else 262 attrset(A_NORMAL); 263 264 for (col = xpos; col < xpos + gap; col++) { 265 if (col >= circle_pos[i][0] && 266 col <= circle_pos[i][1]) 267 mvaddch(i, col, ' '); 268 } 269 270 if (colourOK) 271 attrset(COLOR_PAIR(COLOR_WHITE)); 272 else 273 attrset(A_REVERSE); 274 275 for (col = xpos + gap ; col < xpos + (2 * gap); 276 col++) { 277 if (col >= circle_pos[i][0] && 278 col <= circle_pos[i][1]) 279 mvaddch(i, col, ' '); 280 } 281 } 282 } 283 284 /* Add colour bars. */ 285 for (i = 0; i < numcolours; i++) { 286 colour = colour_list[i]; 287 if (colourOK) 288 attrset(COLOR_PAIR(colour)); 289 else if (i & 1) 290 attrset(A_NORMAL); 291 else 292 attrset(A_REVERSE); 293 294 if (i == 0) 295 spacing_start = 0; 296 else 297 spacing_start = (spacing * i) + spacing_residual; 298 299 if (i == numcolours - 1) 300 spacing_end = circle_pos[y_limit / 2][1]; 301 else 302 spacing_end = (spacing * (i + 1)) + spacing_residual; 303 304 for (line = roundf(4 * grid_unit); line < (y_limit / 2); 305 line++) { 306 for (col = spacing_start; col < spacing_end; col++) { 307 xpos = col + circle_pos[y_limit / 2][0]; 308 if (xpos >= circle_pos[line][0] && 309 xpos <= circle_pos[line][1]) 310 mvprintw(line, xpos, " "); 311 } 312 } 313 } 314 315 /* Add black segment under centre line. */ 316 for (line = y_limit / 2; line < (9.5 * grid_unit); line++) { 317 if (colourOK) 318 attrset(COLOR_PAIR(COLOR_BLACK)); 319 else 320 attrset(A_NORMAL); 321 322 for (col = circle_pos[line][0]; col <= circle_pos[line][1]; 323 col++) 324 mvaddch(line, col, ' '); 325 326 for (col = roundf((1.5 * grid_unit * 2)); col < 327 roundf((4.3 * grid_unit * 2)); col++) { 328 xpos = col + circle_pos[y_limit / 2][0]; 329 if (xpos >= circle_pos[line][0] && 330 xpos < circle_pos[line][1]) 331 mvaddch(line, xpos, 120 | A_ALTCHARSET); 332 } 333 334 for (col = roundf((4.3 * grid_unit * 2)); col < 335 roundf((7.6 * grid_unit * 2)); col++) { 336 xpos = col + circle_pos[y_limit / 2][0]; 337 if (xpos >= circle_pos[line][0] && 338 xpos < circle_pos[line][1]) 339 mvaddch(line, xpos, '|'); 340 } 341 342 for (col = roundf((7.6 * grid_unit * 2)); col < 343 roundf((11.5 * grid_unit * 2)); col++) { 344 xpos = col + circle_pos[y_limit / 2][0]; 345 if (xpos >= circle_pos[line][0] && 346 xpos < circle_pos[line][1]) 347 mvaddch(line, xpos, 97 | A_ALTCHARSET); 348 } 349 } 350 351 /* Add black segment close to bottom. */ 352 for (line = roundf(9.5 * grid_unit); line <= (10.5 * grid_unit); 353 line++) { 354 if (colourOK) 355 attrset(COLOR_PAIR(COLOR_BLACK)); 356 else 357 attrset(A_NORMAL); 358 359 for (col = roundf((0 * grid_unit * 2)); col < 360 roundf((4 * grid_unit * 2)); col++) { 361 xpos = col + circle_pos[y_limit / 2][0]; 362 if (xpos >= circle_pos[line][0] && 363 xpos < circle_pos[line][1]) 364 mvaddch(line, xpos, ' '); 365 } 366 367 for (col = roundf((4 * grid_unit * 2)); col < 368 roundf((6.5 * grid_unit * 2)); col++) { 369 xpos = col + circle_pos[y_limit / 2][0]; 370 if (xpos >= circle_pos[line][0] && 371 xpos < circle_pos[line][1]) 372 mvaddch(line, xpos, 97 | A_ALTCHARSET); 373 } 374 375 if (colourOK) 376 attrset(COLOR_PAIR(COLOR_WHITE)); 377 else 378 attrset(A_REVERSE); 379 380 for (col = roundf((6.5 * grid_unit * 2)); col < 381 roundf((9 * grid_unit * 2)); col++) { 382 xpos = col + circle_pos[y_limit / 2][0]; 383 if (xpos >= circle_pos[line][0] && 384 xpos < circle_pos[line][1]) 385 mvaddch(line, xpos, 97 | A_ALTCHARSET); 386 } 387 388 for (col = roundf((9 * grid_unit * 2)); col < 389 roundf((13 * grid_unit * 2)); col++) { 390 xpos = col + circle_pos[y_limit / 2][0]; 391 if (xpos >= circle_pos[line][0] && 392 xpos < circle_pos[line][1]) 393 mvaddch(line, xpos, ' '); 394 } 395 } 396 397 /* Add name segment close to bottom. */ 398 for (line = roundf(10.5 * grid_unit); line < (12 * grid_unit); 399 line++) { 400 if (colourOK) 401 attrset(COLOR_PAIR(COLOR_BLACK)); 402 else 403 attrset(A_NORMAL); 404 405 for (col = roundf(3.5 * grid_unit * 2); col <= roundf(9.5 * 406 grid_unit * 2); col++) { 407 xpos = col + circle_pos[y_limit / 2][0]; 408 if (xpos >= circle_pos[line][0] && 409 xpos < circle_pos[line][1]) 410 mvaddch(line, xpos, ' '); 411 } 412 413 if (colourOK) 414 attrset(COLOR_PAIR(COLOR_WHITE)); 415 else 416 attrset(A_REVERSE); 417 418 for (col = roundf(0 * grid_unit * 2); col <= roundf(3.5 * 419 grid_unit * 2); col++) { 420 xpos = col + circle_pos[y_limit / 2][0]; 421 if (xpos >= circle_pos[line][0] && 422 xpos < circle_pos[line][1]) 423 mvaddch(line, xpos, ' '); 424 } 425 426 for (col = roundf(9.5 * grid_unit * 2); col <= roundf(13 * 427 grid_unit * 2); col++) { 428 xpos = col + circle_pos[y_limit / 2][0]; 429 if (xpos >= circle_pos[line][0] && 430 xpos < circle_pos[line][1]) 431 mvaddch(line, xpos, ' '); 432 } 433 } 434 435 /* Add yellow segment at bottom. */ 436 for (line = 12 * grid_unit; line < y_limit; line++) { 437 if (colourOK) 438 attrset(COLOR_PAIR(COLOR_YELLOW)); 439 else 440 attrset(A_REVERSE); 441 442 443 for (col = circle_pos[line][0]; col <= circle_pos[line][1]; 444 col++) 445 mvaddch(line, col, ' '); 446 447 if (colourOK) 448 attrset(COLOR_PAIR(COLOR_RED)); 449 else 450 attrset(A_NORMAL); 451 452 for (col = roundf((6 * grid_unit * 2)); col < 453 roundf((7 * grid_unit * 2)); col++) { 454 xpos = col + circle_pos[y_limit / 2][0]; 455 if (xpos >= circle_pos[line][0] && 456 xpos < circle_pos[line][1]) 457 mvaddch(line, xpos, ' '); 458 } 459 } 460 461 if (colourOK) 462 attrset(COLOR_PAIR(COLOR_BLACK)); 463 else 464 attrset(A_NORMAL); 465 466 for (line = 6 * grid_unit; line <= (7 * grid_unit) + 1; line++) { 467 if (colourOK) 468 attrset(COLOR_PAIR(COLOR_BLACK)); 469 else 470 attrset(A_NORMAL); 471 472 col = x_limit / 2; 473 if (line != a_axis) { 474 mvaddch(line, col - 1, ' '); 475 mvaddch(line, col, 120 | A_ALTCHARSET); 476 mvaddch(line, col + 1, ' '); 477 } 478 } 479 480 line = y_limit / 2; 481 for (col = 1; col < x_limit; col = col + grid_x) { 482 xpos = col; 483 while (xpos < col + grid_x - 1) { 484 if (xpos >= circle_pos[line][0] 485 && xpos < circle_pos[line][1]) 486 mvaddch(line, xpos, 113 | A_ALTCHARSET); 487 xpos++; 488 } 489 if (xpos >= circle_pos[line][0] && xpos < circle_pos[line][1]) 490 mvaddch(line, xpos, 110 | A_ALTCHARSET); 491 } 492 493 line = y_limit / 2; 494 col = x_limit / 2; 495 mvaddch(line, col, 110 | A_ALTCHARSET); 496 mvaddch(line, col - 1, 113 | A_ALTCHARSET); 497 mvaddch(line, col + 1, 113 | A_ALTCHARSET); 498 499 refresh(); 500 501 getch(); 502 503 endwin(); 504 505 return EXIT_SUCCESS; 506} 507 508