1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* fiberlamp --- A Fiber Optic Lamp */
5 static const char sccsid[] = "@(#)fiberlamp.c 5.00 2000/11/01 xlockmore";
10 * Copyright (c) 2005 by Tim Auckland <tda10.geo@yahoo.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 DEFAULTS "*delay: 10000 \n" \
40 # define UNIFORM_COLORS
41 # define release_fiberlamp 0
42 # define reshape_fiberlamp 0
43 # define fiberlamp_handle_event 0
44 # include "xlockmore.h" /* in xscreensaver distribution */
45 #else /* STANDALONE */
46 # include "xlock.h" /* in xlockmore distribution */
47 #endif /* STANDALONE */
51 ENTRYPOINT ModeSpecOpt fiberlamp_opts =
52 {0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL};
55 ModStruct fiberlamp_description =
56 {"fiberlamp", "init_fiberlamp", "draw_fiberlamp", (char *) NULL,
57 "draw_fiberlamp", "change_fiberlamp", "free_fiberlamp", &fiberlamp_opts,
58 1000, 500, 10000, 0, 64, 1.0, "", "Shows a Fiber Optic Lamp", 0, NULL};
62 #define SPREAD (30.0) /* Angular spread at the base */
63 #define SCALE (MI_WIDTH(mi)/2) /* Screen size */
64 #define NODES (20L) /* Number of nodes in a fiber. Variable with range
65 10 .. 30, if desired. High values have
66 stability problems unless you use small DT */
68 /* Physics parameters. Tune carefully to keep realism and avoid instability*/
69 #define DT (0.5) /* Time increment: Low is slow, High is less stable. */
70 #define PY (0.12) /* Rigidity: Low droops, High is stiff. */
71 #define DAMPING (0.055) /* Damping: Low allows oscillations, High is boring. */
73 #undef PLAN /* Plan view (for debugging) */
74 #undef CHECKCOLORWHEEL /* Plan view with no spread */
76 #define DRAND(v) (LRAND()/MAXRAND*(v)) /* double random 0 - v */
78 /* Length of nodes. Uniform except for shorter notes at the tips for
79 colour highlights. Sum from 0..NODES-1 should exactly 1.0 */
80 #define LEN(A) ((A<NODES-3) ? 1.0/(NODES-2.5) : 0.25/(NODES-2.5))
102 double rx, ry; /* Coordinates relative to root */
105 Pixmap buffer; /* Double Buffer */
106 long bright, medium, dim; /* "White" colors */
109 static fiberlampstruct *fiberlamps = (fiberlampstruct *) NULL;
112 change_fiberlamp(ModeInfo * mi)
115 if (fiberlamps == NULL)
117 fl = &fiberlamps[MI_SCREEN(mi)];
118 fl->cx = (DRAND(SCALE/4)-SCALE/8)/SCALE; /* Knock the lamp */
119 fl->count = 0; /* Reset counter */
121 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi));
122 XFillRectangle(MI_DISPLAY(mi), fl->buffer, MI_GC(mi), 0, 0,
123 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;
147 free_fiberlamp(ModeInfo *mi)
149 fiberlampstruct *fl = &fiberlamps[MI_SCREEN(mi)];
150 if (fl->buffer != None && fl->dbufp) {
151 XFreePixmap(MI_DISPLAY(mi), fl->buffer);
158 init_fiberlamp(ModeInfo * mi)
162 MI_INIT (mi, fiberlamps);
163 fl = &fiberlamps[MI_SCREEN(mi)];
165 /* Create or Resize double buffer */
166 #ifdef HAVE_JWXYZ /* Don't second-guess Quartz's double-buffering */
172 if(fl->buffer != None && fl->buffer != MI_WINDOW(mi) && fl->dbufp)
173 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) {
183 fl->buffer = MI_WINDOW(mi);
186 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi));
187 XFillRectangle(MI_DISPLAY(mi), fl->buffer, MI_GC(mi), 0, 0,
188 MI_WIDTH(mi), MI_HEIGHT(mi));
190 if(fl->init) /* Nothing else to do (probably a resize) */
194 fl->nfibers = MI_COUNT(mi);
195 /* Allocate fibers */
197 (fiberstruct*) calloc(fl->nfibers, sizeof (fiberstruct))) == NULL) {
202 for(f = 0; f < fl->nfibers; f++) {
203 fiberstruct *fs = fl->fiber + f;
205 (nodestruct*) calloc(NODES, sizeof (nodestruct))) == NULL
207 (XPoint*) calloc(NODES, sizeof (XPoint))) == NULL) {
216 for(f = 0; f < fl->nfibers; f++) {
217 double phi = M_PI/180 * DRAND(SPREAD);
218 double eta = DRAND(2*M_PI) - M_PI;
219 for(i = 0; i < NODES; i++) {
220 nodestruct *n = &fl->fiber[f].node[i];
226 fl->fiber[f].node[0].etadash = 0.002/DT;
227 fl->fiber[f].node[0].y = 0;
228 fl->fiber[f].node[0].z = 0;
233 /* Set up rotation */
234 fl->psi = DRAND(2*M_PI);
237 /* no "NoExpose" events from XCopyArea wanted */
238 XSetGraphicsExposures(MI_DISPLAY(mi), MI_GC(mi), False);
240 /* Make sure we're using 'thin' lines */
241 XSetLineAttributes(MI_DISPLAY(mi), MI_GC(mi), 0, LineSolid, CapNotLast,
243 #ifdef CHECKCOLORWHEEL
244 /* Only interested in tips, leave the rest black */
245 fl->bright = fl->medium = fl->dim = MI_BLACK_PIXEL(mi);
247 if(MI_NPIXELS(mi) > 2) {
248 /* Set up colours for the fiber bodies. Tips handled seperately */
250 if(XAllocNamedColor(MI_DISPLAY(mi), MI_COLORMAP(mi), "#E0E0C0", &c, &t)){
251 fl->bright = c.pixel;
253 fl->bright = MI_WHITE_PIXEL(mi);
255 if(XAllocNamedColor(MI_DISPLAY(mi), MI_COLORMAP(mi), "#808070", &c, &t)){
256 fl->medium = c.pixel;
258 fl->medium = MI_WHITE_PIXEL(mi);
260 if(XAllocNamedColor(MI_DISPLAY(mi), MI_COLORMAP(mi), "#404020", &c, &t)){
263 fl->dim = MI_BLACK_PIXEL(mi);
266 fl->bright = MI_WHITE_PIXEL(mi);
267 fl->medium = MI_WHITE_PIXEL(mi);
268 fl->dim = MI_BLACK_PIXEL(mi);
272 /* Clear the background. */
274 change_fiberlamp(mi);
277 /* sort fibers so they get drawn back-to-front, one bubble pass is
278 enough as the order only changes slowly */
280 sort_fibers(fiberlampstruct *fl)
284 for(i = 1; i < fl->nfibers; i++) {
285 if (fl->fiber[i - 1].node[NODES - 1].z > fl->fiber[i].node[NODES - 1].z) {
286 fiberstruct tmp = fl->fiber[i - 1];
287 fl->fiber[i - 1] = fl->fiber[i];
294 draw_fiberlamp (ModeInfo * mi)
307 #if defined PLAN || defined CHECKCOLORWHEEL
308 cy = MI_HEIGHT(mi)/2;
313 if (ww > hh * 5 || /* window has weird aspect */
329 if (fiberlamps == NULL)
331 fl = &fiberlamps[MI_SCREEN(mi)];
333 fl->psi += fl->dpsi; /* turn colorwheel */
335 XTranslateCoordinates(MI_DISPLAY(mi), MI_WINDOW(mi),
336 RootWindow(MI_DISPLAY(mi),0/*#### MI_SCREEN(mi)*/),
337 cx, cy, &x, &y, &unused);
340 for(f = 0; f < fl->nfibers; f++) {
341 fiberstruct *fs = fl->fiber + f;
343 fs->node[0].eta += DT*fs->node[0].etadash;
344 fs->node[0].x = fl->cx; /* Handle center movement */
345 /* Handle window move. NOTE, only x is deflected, since y doesn't
346 directly affect the physics */
347 fs->node[NODES-2].x *= 0.1*(fl->ry - y);
348 fs->node[NODES-2].x += 0.05*(fl->rx - x);
350 /* 2nd order diff equation */
351 for(i = 1; i < NODES; i++) {
352 nodestruct *n = fs->node+i;
353 nodestruct *p = fs->node+i-1;
356 double pstress = (n->phi - p->phi)*PY;
357 double estress = (n->eta - p->eta)*PY;
358 double dxi = n->x - p->x;
359 double dzi = n->z - p->z;
360 double li = sqrt(dxi*dxi + dzi*dzi)/LEN(i);
361 double drag = DAMPING*LEN(i)*LEN(i)*NODES*NODES;
365 for(j = i+1; j < NODES; j++) {
366 nodestruct *nn = fs->node+j;
367 double dxj = nn->x - n->x;
368 double dzj = nn->z - n->z;
370 pload += LEN(j)*(dxi*dxj + dzi*dzj)/li; /* Radial load */
371 eload += LEN(j)*(dxi*dzj - dzi*dxj)/li; /* Transverse load */
372 /* Not a perfect simulation: in reality the transverse load
373 is only indirectly coupled to the eta deflection, but of
374 all the approaches I've tried this produces the most
375 stable model and looks the most realistic. */
379 #ifndef CHECKCOLORWHEEL
380 n->phidash += DT*(pload - pstress - drag*n->phidash)/LEN(i);
381 n->phi += DT*n->phidash;
384 n->etadash += DT*(eload - estress - drag*n->etadash)/LEN(i);
385 n->eta += DT*n->etadash;
388 double sp = sin(p->phi);
389 double cp = cos(p->phi);
390 double se = sin(p->eta);
391 double ce = cos(p->eta);
393 n->x = p->x + LEN(i-1) * ce * sp;
394 n->y = p->y - LEN(i-1) * cp;
395 n->z = p->z + LEN(i-1) * se * sp;
398 fs->draw[i-1].x = cx + ww/2*n->x;
399 #if defined PLAN || defined CHECKCOLORWHEEL /* Plan */
400 fs->draw[i-1].y = cy + ww/2*n->z;
401 #else /* Elevation */
402 fs->draw[i-1].y = cy + ww/2*n->y;
405 MI_IS_DRAWN(mi) = True;
407 /* Erase: this may only be erasing an off-screen buffer, but on a
408 slow system it may still be faster than XFillRectangle() */
409 /* That's unpossible. -jwz */
412 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi));
413 XFillRectangle(MI_DISPLAY(mi), fl->buffer, MI_GC(mi),
414 0, 0, MI_WIDTH(mi), MI_HEIGHT(mi));
416 for(f = 0; f < fl->nfibers; f++) {
417 fiberstruct *fs = fl->fiber + f;
420 double x = fs->node[1].x - fl->cx + 0.025;
421 double y = fs->node[1].z + 0.02;
422 double angle = atan2(y, x) + fl->psi;
423 long tipcolor = (int)(MI_NPIXELS(mi)*angle/(2*M_PI)) % MI_NPIXELS(mi);
427 if (tipcolor < 0) tipcolor += MI_NPIXELS(mi);
428 tipcolor = MI_PIXEL(mi, tipcolor);
430 if(fs->node[1].z < 0.0) { /* Back */
432 fibercolor = fl->dim;
433 }else if(fs->node[NODES-1].z < 0.7) { /* Middle */
435 fibercolor = fl->medium;
438 fibercolor = fl->bright;
441 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), fibercolor);
442 XDrawLines(MI_DISPLAY(mi), fl->buffer, MI_GC(mi),
443 fs->draw, NODES-tiplen, CoordModeOrigin);
445 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), tipcolor);
446 XDrawLines(MI_DISPLAY(mi), fl->buffer, MI_GC(mi),
447 fs->draw+NODES-1-tiplen, tiplen, CoordModeOrigin);
451 /* Update the screen from the double-buffer */
453 XCopyArea(MI_DISPLAY(mi), fl->buffer, MI_WINDOW(mi), MI_GC(mi), 0, 0,
454 MI_WIDTH(mi), MI_HEIGHT(mi), 0, 0);
459 if(fl->count++ > MI_CYCLES(mi)) {
460 change_fiberlamp(mi);
466 refresh_fiberlamp(ModeInfo * mi)
472 XSCREENSAVER_MODULE ("Fiberlamp", fiberlamp)
474 #endif /* MODE_fiberlamp */