1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* fiberlamp --- A Fiber Optic Lamp */
4 #if !defined( lint ) && !defined( SABER )
5 static const char sccsid[] = "@(#)fiberlamp.c 5.00 2000/11/01 xlockmore";
10 * Copyright (c) 2005 by Tim Auckland <Tim.Auckland@Procket.com>
12 * Permission to use, copy, modify, and distribute this software and its
13 * documentation for any purpose and without fee is hereby granted,
14 * provided that the above copyright notice appear in all copies and that
15 * both that copyright notice and this permission notice appear in
16 * supporting documentation.
18 * This file is provided AS IS with no warranties of any kind. The author
19 * shall have no liability with respect to the infringement of copyrights,
20 * trade secrets or any patents by this file or any part thereof. In no
21 * event will the author be liable for any lost revenue or profits or
22 * other special, indirect and consequential damages.
24 * "fiberlamp" shows Fiber Optic Lamp. Since there is no closed-form
25 * solution to the large-amplitude cantilever equation, the flexible
26 * fiber is modeled as a set of descrete nodes.
29 * 13-Jan-2005: Initial development.
33 #define MODE_fiberlamp
34 #define PROGCLASS "Fiberlamp"
35 #define HACK_INIT init_fiberlamp
36 #define HACK_DRAW draw_fiberlamp
37 #define HACK_RESHAPE reshape_fiberlamp
38 #define _no_HACK_FREE release_fiberlamp
39 #define fiberlamp_opts xlockmore_opts
40 #define DEFAULTS "*delay: 10000 \n" \
44 #define UNIFORM_COLORS
45 #include "xlockmore.h" /* in xscreensaver distribution */
47 # define MI_DEPTH MI_WIN_DEPTH
49 #else /* STANDALONE */
50 #include "xlock.h" /* in xlockmore distribution */
51 #endif /* STANDALONE */
55 ModeSpecOpt fiberlamp_opts =
56 {0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL};
59 ModStruct fiberlamp_description =
60 {"fiberlamp", "init_fiberlamp", "draw_fiberlamp", "release_fiberlamp",
61 "draw_fiberlamp", "change_fiberlamp", (char *) NULL, &fiberlamp_opts,
62 1000, 500, 10000, 0, 64, 1.0, "", "Shows a Fiber Optic Lamp", 0, NULL};
66 #define SPREAD (30.0) /* Angular spread at the base */
67 #define SCALE (MI_WIDTH(mi)/2) /* Screen size */
68 #define NODES (20) /* Number of nodes in a fiber. Variable with range
69 10 .. 30, if desired. High values have
70 stability problems unless you use small DT */
72 /* Physics parameters. Tune carefully to keep realism and avoid instability*/
73 #define DT (0.5) /* Time increment: Low is slow, High is less stable. */
74 #define PY (0.12) /* Rigidity: Low droops, High is stiff. */
75 #define DAMPING (0.055) /* Damping: Low allows oscillations, High is boring. */
77 #undef PLAN /* Plan view (for debugging) */
78 #undef CHECKCOLORWHEEL /* Plan view with no spread */
80 #define DRAND(v) (LRAND()/MAXRAND*(v)) /* double random 0 - v */
82 /* Length of nodes. Uniform except for shorter notes at the tips for
83 colour highlights. Sum from 0..NODES-1 should exactly 1.0 */
84 #define LEN(A) ((A<NODES-3) ? 1.0/(NODES-2.5) : 0.25/(NODES-2.5))
105 double rx, ry; /* Coordinates relative to root */
107 Pixmap buffer; /* Double Buffer */
108 long bright, medium, dim; /* "White" colors */
111 static fiberlampstruct *fiberlamps = (fiberlampstruct *) NULL;
114 change_fiberlamp(ModeInfo * mi)
117 if (fiberlamps == NULL)
119 fl = &fiberlamps[MI_SCREEN(mi)];
120 fl->cx = (DRAND(SCALE/4)-SCALE/8)/SCALE; /* Knock the lamp */
121 fl->count = 0; /* Reset counter */
122 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi));
123 XFillRectangle(MI_DISPLAY(mi), fl->buffer, MI_GC(mi), 0, 0,
124 MI_WIDTH(mi), MI_HEIGHT(mi));
128 free_fiber(fiberlampstruct *fl)
133 for (f = 0; f < fl->nfibers; f++) {
134 fiberstruct *fs = fl->fiber + f;
149 free_fiberlamp(Display *display, fiberlampstruct *fl)
151 if (fl->buffer != None) {
152 XFreePixmap(display, fl->buffer);
159 init_fiberlamp(ModeInfo * mi)
164 if (fiberlamps == NULL) {
167 (fiberlampstruct *) calloc(MI_NUM_SCREENS(mi),
168 sizeof (fiberlampstruct))) == NULL)
171 fl = &fiberlamps[MI_SCREEN(mi)];
173 /* Create or Resize double buffer */
174 if(fl->buffer != None)
175 XFreePixmap(MI_DISPLAY(mi), fl->buffer);
176 fl->buffer = XCreatePixmap(MI_DISPLAY(mi), MI_WINDOW(mi),
177 MI_WIDTH(mi), MI_HEIGHT(mi), MI_DEPTH(mi));
178 if (fl->buffer == None) {
179 free_fiberlamp(MI_DISPLAY(mi), fl);
182 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi));
183 XFillRectangle(MI_DISPLAY(mi), fl->buffer, MI_GC(mi), 0, 0,
184 MI_WIDTH(mi), MI_HEIGHT(mi));
186 if(!init) /* Nothing else to do (probably a resize) */
189 fl->nfibers = MI_COUNT(mi);
190 /* Allocate fibers */
192 (fiberstruct*) calloc(fl->nfibers, sizeof (fiberstruct))) == NULL) {
193 free_fiberlamp(MI_DISPLAY(mi), fl);
197 for(f = 0; f < fl->nfibers; f++) {
198 fiberstruct *fs = fl->fiber + f;
200 (nodestruct*) calloc(NODES, sizeof (nodestruct))) == NULL
202 (XPoint*) calloc(NODES, sizeof (XPoint))) == NULL
204 (XPoint*) calloc(NODES, sizeof (XPoint))) == NULL) {
205 free_fiberlamp(MI_DISPLAY(mi), fl);
213 for(f = 0; f < fl->nfibers; f++) {
214 double phi = M_PI/180 * DRAND(SPREAD);
215 double eta = DRAND(2*M_PI) - M_PI;
216 for(i = 0; i < NODES; i++) {
217 nodestruct *n = &fl->fiber[f].node[i];
223 fl->fiber[f].node[0].etadash = 0.002/DT;
224 fl->fiber[f].node[0].y = 0;
225 fl->fiber[f].node[0].z = 0;
230 /* Set up rotation */
231 fl->psi = DRAND(2*M_PI);
234 /* no "NoExpose" events from XCopyArea wanted */
235 XSetGraphicsExposures(MI_DISPLAY(mi), MI_GC(mi), False);
237 /* Make sure we're using 'thin' lines */
238 XSetLineAttributes(MI_DISPLAY(mi), MI_GC(mi), 0, LineSolid, CapNotLast,
240 #ifdef CHECKCOLORWHEEL
241 /* Only interested in tips, leave the rest black */
242 fl->bright = fl->medium = fl->dim = MI_BLACK_PIXEL(mi);
244 if(MI_NPIXELS(mi) > 2) {
245 /* Set up colours for the fiber bodies. Tips handled seperately */
247 if(XAllocNamedColor(MI_DISPLAY(mi), MI_COLORMAP(mi), "#E0E0C0", &c, &t)){
248 fl->bright = c.pixel;
250 fl->bright = MI_WHITE_PIXEL(mi);
252 if(XAllocNamedColor(MI_DISPLAY(mi), MI_COLORMAP(mi), "#808070", &c, &t)){
253 fl->medium = c.pixel;
255 fl->medium = MI_WHITE_PIXEL(mi);
257 if(XAllocNamedColor(MI_DISPLAY(mi), MI_COLORMAP(mi), "#404020", &c, &t)){
260 fl->dim = MI_BLACK_PIXEL(mi);
263 fl->bright = MI_WHITE_PIXEL(mi);
264 fl->medium = MI_WHITE_PIXEL(mi);
265 fl->dim = MI_BLACK_PIXEL(mi);
269 /* Clear the background. */
271 change_fiberlamp(mi);
275 /* Used by xscreensaver. xlock just uses init_fiberlamp */
277 reshape_fiberlamp(ModeInfo * mi, int width, int height)
284 draw_fiberlamp(ModeInfo * mi)
291 short cx = MI_WIDTH(mi)/2;
292 #if defined PLAN || defined CHECKCOLORWHEEL
293 short cy = MI_HEIGHT(mi)/2;
295 short cy = MI_HEIGHT(mi);
298 if (fiberlamps == NULL)
300 fl = &fiberlamps[MI_SCREEN(mi)];
302 fl->psi += fl->dpsi; /* turn colorwheel */
304 XTranslateCoordinates(MI_DISPLAY(mi), MI_WINDOW(mi),
305 RootWindow(MI_DISPLAY(mi),MI_SCREEN(mi)),
306 cx, cy, &x, &y, &unused);
308 for(f = 0; f < fl->nfibers; f++) {
309 fiberstruct *fs = fl->fiber + f;
311 fs->node[0].eta += DT*fs->node[0].etadash;
312 fs->node[0].x = fl->cx; /* Handle center movement */
313 /* Handle window move. NOTE, only x is deflected, since y doesn't
314 directly affect the physics */
315 fs->node[NODES-2].x *= 0.1*(fl->ry - y);
316 fs->node[NODES-2].x += 0.05*(fl->rx - x);
318 /* 2nd order diff equation */
319 for(i = 1; i < NODES; i++) {
320 nodestruct *n = fs->node+i;
321 nodestruct *p = fs->node+i-1;
324 double pstress = (n->phi - p->phi)*PY;
325 double estress = (n->eta - p->eta)*PY;
326 double dxi = n->x - p->x;
327 double dzi = n->z - p->z;
328 double li = sqrt(dxi*dxi + dzi*dzi)/LEN(i);
329 double drag = DAMPING*LEN(i)*LEN(i)*NODES*NODES;
333 for(j = i+1; j < NODES; j++) {
334 nodestruct *nn = fs->node+j;
335 double dxj = nn->x - n->x;
336 double dzj = nn->z - n->z;
338 pload += LEN(j)*(dxi*dxj + dzi*dzj)/li; /* Radial load */
339 eload += LEN(j)*(dxi*dzj - dzi*dxj)/li; /* Transverse load */
340 /* Not a perfect simulation: in reality the transverse load
341 is only indirectly coupled to the eta deflection, but of
342 all the approaches I've tried this produces the most
343 stable model and looks the most realistic. */
347 #ifndef CHECKCOLORWHEEL
348 n->phidash += DT*(pload - pstress - drag*n->phidash)/LEN(i);
349 n->phi += DT*n->phidash;
352 n->etadash += DT*(eload - estress - drag*n->etadash)/LEN(i);
353 n->eta += DT*n->etadash;
356 double sp = sin(p->phi);
357 double cp = cos(p->phi);
358 double se = sin(p->eta);
359 double ce = cos(p->eta);
361 n->x = p->x + LEN(i-1) * ce * sp;
362 n->y = p->y - LEN(i-1) * cp;
363 n->z = p->z + LEN(i-1) * se * sp;
366 fs->draw[i-1].x = cx + MI_WIDTH(mi)/2*n->x;
367 #if defined PLAN || defined CHECKCOLORWHEEL /* Plan */
368 fs->draw[i-1].y = cy + MI_WIDTH(mi)/2*n->z;
369 #else /* Elevation */
370 fs->draw[i-1].y = cy + MI_WIDTH(mi)/2*n->y;
373 MI_IS_DRAWN(mi) = True;
375 /* Erase: this may only be erasing an off-screen buffer, but on a
376 slow system it may still be faster than XFillRectangle() */
377 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi));
378 XDrawLines(MI_DISPLAY(mi), fl->buffer, MI_GC(mi),
379 fs->erase, NODES-1, CoordModeOrigin);
382 double x = fs->node[1].x - fl->cx + 0.025;
383 double y = fs->node[1].z + 0.02;
384 double angle = atan2(y, x) + fl->psi;
385 int tipcolor = MI_PIXEL(mi,
386 (int)(MI_NPIXELS(mi)*angle/(2*M_PI)) % MI_NPIXELS(mi));
390 if(fs->node[1].z < 0.0) { /* Back */
392 fibercolor = fl->dim;
393 }else if(fs->node[NODES-1].z < 0.7) { /* Middle */
395 fibercolor = fl->medium;
398 fibercolor = fl->bright;
401 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), fibercolor);
402 XDrawLines(MI_DISPLAY(mi), fl->buffer, MI_GC(mi),
403 fs->draw, NODES-tiplen, CoordModeOrigin);
405 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), tipcolor);
406 XDrawLines(MI_DISPLAY(mi), fl->buffer, MI_GC(mi),
407 fs->draw+NODES-1-tiplen, tiplen, CoordModeOrigin);
410 { /* Switch buffers */
411 XPoint *buffer = fs->draw;
412 fs->draw = fs->erase;
417 /* Update the screen from the double-buffer */
418 XCopyArea(MI_DISPLAY(mi), fl->buffer, MI_WINDOW(mi), MI_GC(mi), 0, 0,
419 MI_WIDTH(mi), MI_HEIGHT(mi), 0, 0);
424 if(fl->count++ > MI_CYCLES(mi)) {
425 change_fiberlamp(mi);
430 release_fiberlamp(ModeInfo * mi)
432 if (fiberlamps != NULL) {
435 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
436 free_fiberlamp(MI_DISPLAY(mi), &fiberlamps[screen]);
438 fiberlamps = (fiberlampstruct *) NULL;
444 refresh_fiberlamp(ModeInfo * mi)
449 #endif /* MODE_fiberlamp */