1 /*- 2 * Copyright (c) 2015 Dag-Erling Smørgrav 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 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. 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 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * To CJA, in appreciation of Nighthawk brunches past and future. 27 */ 28 29 #include <sys/param.h> 30 #include <sys/systm.h> 31 #include <sys/kernel.h> 32 #include <sys/module.h> 33 #include <sys/syslog.h> 34 #include <sys/consio.h> 35 #include <sys/fbio.h> 36 37 #include <dev/fb/fbreg.h> 38 #include <dev/fb/splashreg.h> 39 #include <dev/syscons/syscons.h> 40 41 #define SAVER_NAME "plasma_saver" 42 43 #include "fp16.h" 44 45 /* 46 * Preferred video modes 47 */ 48 static int modes[] = { 49 M_VGA_CG640, 50 M_VGA_CG320, 51 -1 52 }; 53 54 /* 55 * Display parameters 56 */ 57 static unsigned char *vid; 58 static unsigned int banksize, scrmode, scrw, scrh; 59 static unsigned int blanked; 60 61 /* 62 * List of foci 63 */ 64 #define FOCI 3 65 static struct { 66 int x, y; /* coordinates */ 67 int vx, vy; /* velocity */ 68 } plasma_foci[FOCI]; 69 70 /* 71 * Palette 72 */ 73 static struct { 74 unsigned char r, g, b; 75 } plasma_pal[256]; 76 77 /* 78 * Draw a new frame 79 */ 80 static void 81 plasma_update(video_adapter_t *adp) 82 { 83 unsigned int x, y; /* coordinates */ 84 signed int dx, dy; /* horizontal / vertical distance */ 85 fp16_t sqd, d; /* square of distance and distance */ 86 fp16_t m; /* magnitude */ 87 unsigned int org, off; /* origin and offset */ 88 unsigned int i; /* loop index */ 89 90 /* switch to bank 0 */ 91 vidd_set_win_org(adp, 0); 92 /* for each scan line */ 93 for (y = org = off = 0; y < scrh; ++y) { 94 /* for each pixel on scan line */ 95 for (x = 0; x < scrw; ++x, ++off) { 96 /* for each focus */ 97 for (i = m = 0; i < FOCI; ++i) { 98 dx = x - plasma_foci[i].x; 99 dy = y - plasma_foci[i].y; 100 sqd = ItoFP16(dx * dx + dy * dy); 101 d = fp16_sqrt(sqd); 102 /* divide by 4 to stretch out the pattern */ 103 m = fp16_sub(m, fp16_cos(d / 4)); 104 } 105 /* 106 * m is now in the range +/- FOCI, but we need a 107 * value between 0 and 255. We scale to +/- 127 108 * and add 127, which moves it into the range [0, 109 * 254]. 110 */ 111 m = fp16_mul(m, ItoFP16(127)); 112 m = fp16_div(m, ItoFP16(FOCI)); 113 m = fp16_add(m, ItoFP16(127)); 114 /* switch banks if necessary */ 115 if (off > banksize) { 116 off -= banksize; 117 org += banksize; 118 vidd_set_win_org(adp, org); 119 } 120 /* plot */ 121 vid[off] = FP16toI(m); 122 } 123 } 124 /* now move the foci */ 125 for (i = 0; i < FOCI; ++i) { 126 plasma_foci[i].x += plasma_foci[i].vx; 127 if (plasma_foci[i].x < 0) { 128 /* bounce against left wall */ 129 plasma_foci[i].vx = -plasma_foci[i].vx; 130 plasma_foci[i].x = -plasma_foci[i].x; 131 } else if (plasma_foci[i].x >= scrw) { 132 /* bounce against right wall */ 133 plasma_foci[i].vx = -plasma_foci[i].vx; 134 plasma_foci[i].x = scrw - (plasma_foci[i].x - scrw); 135 } 136 plasma_foci[i].y += plasma_foci[i].vy; 137 if (plasma_foci[i].y < 0) { 138 /* bounce against ceiling */ 139 plasma_foci[i].vy = -plasma_foci[i].vy; 140 plasma_foci[i].y = -plasma_foci[i].y; 141 } else if (plasma_foci[i].y >= scrh) { 142 /* bounce against floor */ 143 plasma_foci[i].vy = -plasma_foci[i].vy; 144 plasma_foci[i].y = scrh - (plasma_foci[i].y - scrh); 145 } 146 } 147 } 148 149 /* 150 * Start or stop the screensaver 151 */ 152 static int 153 plasma_saver(video_adapter_t *adp, int blank) 154 { 155 int pl; 156 157 if (blank) { 158 /* switch to graphics mode */ 159 if (blanked <= 0) { 160 pl = splhigh(); 161 vidd_set_mode(adp, scrmode); 162 vidd_load_palette(adp, (unsigned char *)plasma_pal); 163 vidd_set_border(adp, 0); 164 blanked++; 165 vid = (unsigned char *)adp->va_window; 166 banksize = adp->va_window_size; 167 splx(pl); 168 vidd_clear(adp); 169 } 170 /* update display */ 171 plasma_update(adp); 172 } else { 173 blanked = 0; 174 } 175 return (0); 176 } 177 178 /* 179 * Initialize on module load 180 */ 181 static int 182 plasma_init(video_adapter_t *adp) 183 { 184 video_info_t info; 185 int i; 186 187 /* select video mode */ 188 for (i = 0; modes[i] >= 0; ++i) 189 if (vidd_get_info(adp, modes[i], &info) == 0) 190 break; 191 if (modes[i] < 0) { 192 log(LOG_NOTICE, "%s: no supported video modes\n", SAVER_NAME); 193 return (ENODEV); 194 } 195 scrmode = modes[i]; 196 scrw = info.vi_width; 197 scrh = info.vi_height; 198 199 /* initialize the palette */ 200 for (i = 0; i < 256; ++i) 201 plasma_pal[i].r = plasma_pal[i].g = plasma_pal[i].b = i; 202 203 /* randomize the foci */ 204 for (i = 0; i < FOCI; i++) { 205 plasma_foci[i].x = random() % scrw; 206 plasma_foci[i].y = random() % scrh; 207 plasma_foci[i].vx = random() % 5 - 2; 208 plasma_foci[i].vy = random() % 5 - 2; 209 } 210 211 return (0); 212 } 213 214 /* 215 * Clean up before module unload 216 */ 217 static int 218 plasma_term(video_adapter_t *adp) 219 { 220 221 return (0); 222 } 223 224 /* 225 * Boilerplate 226 */ 227 static scrn_saver_t plasma_module = { 228 SAVER_NAME, 229 plasma_init, 230 plasma_term, 231 plasma_saver, 232 NULL 233 }; 234 235 SAVER_MODULE(plasma_saver, plasma_module); 236