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