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 * $FreeBSD$ 27 * 28 * To CJA, in appreciation of Nighthawk brunches past and future. 29 */ 30 31 #include <sys/param.h> 32 #include <sys/systm.h> 33 #include <sys/kernel.h> 34 #include <sys/module.h> 35 #include <sys/syslog.h> 36 #include <sys/consio.h> 37 #include <sys/fbio.h> 38 39 #include <dev/fb/fbreg.h> 40 #include <dev/fb/splashreg.h> 41 #include <dev/syscons/syscons.h> 42 43 #define SAVER_NAME "plasma_saver" 44 45 #include "fp16.h" 46 47 /* 48 * Preferred video modes 49 */ 50 static int modes[] = { 51 M_VGA_CG640, 52 M_VGA_CG320, 53 -1 54 }; 55 56 /* 57 * Display parameters 58 */ 59 static unsigned char *vid; 60 static unsigned int banksize, scrmode, scrw, scrh; 61 static unsigned int blanked; 62 63 /* 64 * List of foci 65 */ 66 #define FOCI 3 67 static struct { 68 int x, y; /* coordinates */ 69 int vx, vy; /* velocity */ 70 } plasma_foci[FOCI]; 71 72 /* 73 * Palette 74 */ 75 static struct { 76 unsigned char r, g, b; 77 } plasma_pal[256]; 78 79 /* 80 * Draw a new frame 81 */ 82 static void 83 plasma_update(video_adapter_t *adp) 84 { 85 unsigned int x, y; /* coordinates */ 86 signed int dx, dy; /* horizontal / vertical distance */ 87 fp16_t sqd, d; /* square of distance and distance */ 88 fp16_t m; /* magnitude */ 89 unsigned int org, off; /* origin and offset */ 90 unsigned int i; /* loop index */ 91 92 /* switch to bank 0 */ 93 vidd_set_win_org(adp, 0); 94 /* for each scan line */ 95 for (y = org = off = 0; y < scrh; ++y) { 96 /* for each pixel on scan line */ 97 for (x = 0; x < scrw; ++x, ++off) { 98 /* for each focus */ 99 for (i = m = 0; i < FOCI; ++i) { 100 dx = x - plasma_foci[i].x; 101 dy = y - plasma_foci[i].y; 102 sqd = ItoFP16(dx * dx + dy * dy); 103 d = fp16_sqrt(sqd); 104 /* divide by 4 to stretch out the pattern */ 105 m = fp16_sub(m, fp16_cos(d / 4)); 106 } 107 /* 108 * m is now in the range +/- FOCI, but we need a 109 * value between 0 and 255. We scale to +/- 127 110 * and add 127, which moves it into the range [0, 111 * 254]. 112 */ 113 m = fp16_mul(m, ItoFP16(127)); 114 m = fp16_div(m, ItoFP16(FOCI)); 115 m = fp16_add(m, ItoFP16(127)); 116 /* switch banks if necessary */ 117 if (off > banksize) { 118 off -= banksize; 119 org += banksize; 120 vidd_set_win_org(adp, org); 121 } 122 /* plot */ 123 vid[off] = FP16toI(m); 124 } 125 } 126 /* now move the foci */ 127 for (i = 0; i < FOCI; ++i) { 128 plasma_foci[i].x += plasma_foci[i].vx; 129 if (plasma_foci[i].x < 0) { 130 /* bounce against left wall */ 131 plasma_foci[i].vx = -plasma_foci[i].vx; 132 plasma_foci[i].x = -plasma_foci[i].x; 133 } else if (plasma_foci[i].x >= scrw) { 134 /* bounce against right wall */ 135 plasma_foci[i].vx = -plasma_foci[i].vx; 136 plasma_foci[i].x = scrw - (plasma_foci[i].x - scrw); 137 } 138 plasma_foci[i].y += plasma_foci[i].vy; 139 if (plasma_foci[i].y < 0) { 140 /* bounce against ceiling */ 141 plasma_foci[i].vy = -plasma_foci[i].vy; 142 plasma_foci[i].y = -plasma_foci[i].y; 143 } else if (plasma_foci[i].y >= scrh) { 144 /* bounce against floor */ 145 plasma_foci[i].vy = -plasma_foci[i].vy; 146 plasma_foci[i].y = scrh - (plasma_foci[i].y - scrh); 147 } 148 } 149 } 150 151 /* 152 * Start or stop the screensaver 153 */ 154 static int 155 plasma_saver(video_adapter_t *adp, int blank) 156 { 157 int pl; 158 159 if (blank) { 160 /* switch to graphics mode */ 161 if (blanked <= 0) { 162 pl = splhigh(); 163 vidd_set_mode(adp, scrmode); 164 vidd_load_palette(adp, (unsigned char *)plasma_pal); 165 vidd_set_border(adp, 0); 166 blanked++; 167 vid = (unsigned char *)adp->va_window; 168 banksize = adp->va_window_size; 169 splx(pl); 170 vidd_clear(adp); 171 } 172 /* update display */ 173 plasma_update(adp); 174 } else { 175 blanked = 0; 176 } 177 return (0); 178 } 179 180 /* 181 * Initialize on module load 182 */ 183 static int 184 plasma_init(video_adapter_t *adp) 185 { 186 video_info_t info; 187 int i; 188 189 /* select video mode */ 190 for (i = 0; modes[i] >= 0; ++i) 191 if (vidd_get_info(adp, modes[i], &info) == 0) 192 break; 193 if (modes[i] < 0) { 194 log(LOG_NOTICE, "%s: no supported video modes\n", SAVER_NAME); 195 return (ENODEV); 196 } 197 scrmode = modes[i]; 198 scrw = info.vi_width; 199 scrh = info.vi_height; 200 201 /* initialize the palette */ 202 for (i = 0; i < 256; ++i) 203 plasma_pal[i].r = plasma_pal[i].g = plasma_pal[i].b = i; 204 205 /* randomize the foci */ 206 for (i = 0; i < FOCI; i++) { 207 plasma_foci[i].x = random() % scrw; 208 plasma_foci[i].y = random() % scrh; 209 plasma_foci[i].vx = random() % 5 - 2; 210 plasma_foci[i].vy = random() % 5 - 2; 211 } 212 213 return (0); 214 } 215 216 /* 217 * Clean up before module unload 218 */ 219 static int 220 plasma_term(video_adapter_t *adp) 221 { 222 223 return (0); 224 } 225 226 /* 227 * Boilerplate 228 */ 229 static scrn_saver_t plasma_module = { 230 SAVER_NAME, 231 plasma_init, 232 plasma_term, 233 plasma_saver, 234 NULL 235 }; 236 237 SAVER_MODULE(plasma_saver, plasma_module); 238