1411 lines
35 KiB
C
1411 lines
35 KiB
C
/* -*- Mode: C; tab-width: 4 -*- */
|
|
/* kaleid --- Brewster's Kaleidoscope */
|
|
|
|
#if !defined( lint ) && !defined( SABER )
|
|
static const char sccsid[] = "@(#)kaleid.c 5.00 2000/11/01 xlockmore";
|
|
|
|
#endif
|
|
|
|
/*-
|
|
*
|
|
* kaleid.c - Brewster's Kaleidoscope (Sir David Brewster invented the
|
|
* kaleidoscope in 1816 and patented it in 1817.)
|
|
*
|
|
* Copyright (c) 1998 by Robert Adam, II <raii@comm.net>
|
|
*
|
|
* Permission to use, copy, modify, and distribute this software and its
|
|
* documentation for any purpose and without fee is hereby granted,
|
|
* provided that the above copyright notice appear in all copies and that
|
|
* both that copyright notice and this permission notice appear in
|
|
* supporting documentation.
|
|
*
|
|
* This file is provided AS IS with no warranties of any kind. The author
|
|
* shall have no liability with respect to the infringement of copyrights,
|
|
* trade secrets or any patents by this file or any part thereof. In no
|
|
* event will the author be liable for any lost revenue or profits or
|
|
* other special, indirect and consequential damages.
|
|
*
|
|
* Revision History:
|
|
* 01-Nov-2000: Allocation checks
|
|
* 1998: Written
|
|
*
|
|
*
|
|
* -batchcount n number of pens [default 4]
|
|
*
|
|
* -cycle n percentage of black in the pattern (0%-95%)
|
|
*
|
|
* -size n symmetry mode [default -9]
|
|
* <0 = random from 0 to -number
|
|
* >0 = mirrored (-alternate)
|
|
* rotated (+alternate)
|
|
*
|
|
*
|
|
* -/+disconnected turn on/off disconnected pen movement
|
|
*
|
|
* -/+serial turn on/off sequential allocation of colors
|
|
*
|
|
* -/+alternate turn on/off alternate display mode
|
|
*
|
|
* -/+spiral turn on/off spiral mode
|
|
*
|
|
* -/+spots turn on/off spots mode
|
|
*
|
|
* -/+quad turn on/off quad mirrored/rotated mode similar
|
|
* to size 4, works with alternate
|
|
*
|
|
* -/+oct turn on/off oct mirrored/rotated moded similar
|
|
* to size 8, works with alternate
|
|
*
|
|
* -/+linear select Cartesian/Polar coordinate mode. Cartesian
|
|
* uses straight lines similar to -oct and -quad
|
|
* mode instead of the curved lines of Polar mode.
|
|
* [default off]
|
|
*
|
|
*/
|
|
|
|
#ifdef STANDALONE
|
|
#define MODE_kaleid
|
|
#define PROGCLASS "Kaleid"
|
|
#define HACK_INIT init_kaleid
|
|
#define HACK_DRAW draw_kaleid
|
|
#define kaleid_opts xlockmore_opts
|
|
#define DEFAULTS "*delay: 80000 \n" \
|
|
"*count: 4 \n" \
|
|
"*cycles: 40 \n" \
|
|
"*size: -9 \n" \
|
|
"*ncolors: 200 \n" \
|
|
"*disconnected: True \n" \
|
|
"*serial: False \n" \
|
|
"*alternate: False \n" \
|
|
"*spiral: False \n" \
|
|
"*spots: False \n" \
|
|
"*linear: False \n" \
|
|
"*quad: False \n" \
|
|
"*oct: False \n"
|
|
"*fullrandom: False \n"
|
|
#define UNIFORM_COLORS
|
|
#define BRIGHT_COLORS
|
|
#include "xlockmore.h" /* in xscreensaver distribution */
|
|
#else /* STANDALONE */
|
|
#include "xlock.h" /* in xlockmore distribution */
|
|
#endif /* STANDALONE */
|
|
|
|
#ifdef MODE_kaleid
|
|
|
|
#include <math.h>
|
|
|
|
#define DEF_DISCONNECTED "True"
|
|
#define DEF_SERIAL "False"
|
|
#define DEF_ALTERNATE "False"
|
|
#define DEF_QUAD "False"
|
|
#define DEF_OCT "False"
|
|
#define DEF_LINEAR "False"
|
|
#define DEF_SPIRAL "False"
|
|
#define DEF_SPOTS "False"
|
|
|
|
static Bool Disconnected;
|
|
static Bool Serial;
|
|
static Bool Alternate;
|
|
static Bool Quad;
|
|
static Bool Oct;
|
|
static Bool Linear;
|
|
static Bool Spiral;
|
|
static Bool Spots;
|
|
|
|
static XrmOptionDescRec opts[] =
|
|
{
|
|
{(char *) "-disconnected", (char *) ".kaleid.disconnected", XrmoptionNoArg, (caddr_t) "on"},
|
|
{(char *) "+disconnected", (char *) ".kaleid.disconnected", XrmoptionNoArg, (caddr_t) "off"},
|
|
{(char *) "-serial", (char *) ".kaleid.serial", XrmoptionNoArg, (caddr_t) "on"},
|
|
{(char *) "+serial", (char *) ".kaleid.serial", XrmoptionNoArg, (caddr_t) "off"},
|
|
{(char *) "-alternate", (char *) ".kaleid.alternate", XrmoptionNoArg, (caddr_t) "on"},
|
|
{(char *) "+alternate", (char *) ".kaleid.alternate", XrmoptionNoArg, (caddr_t) "off"},
|
|
{(char *) "-spiral", (char *) ".kaleid.spiral", XrmoptionNoArg, (caddr_t) "on"},
|
|
{(char *) "+spiral", (char *) ".kaleid.spiral", XrmoptionNoArg, (caddr_t) "off"},
|
|
{(char *) "-spots", (char *) ".kaleid.spots", XrmoptionNoArg, (caddr_t) "on"},
|
|
{(char *) "+spots", (char *) ".kaleid.spots", XrmoptionNoArg, (caddr_t) "off"},
|
|
{(char *) "-quad", (char *) ".kaleid.quad", XrmoptionNoArg, (caddr_t) "on"},
|
|
{(char *) "+quad", (char *) ".kaleid.quad", XrmoptionNoArg, (caddr_t) "off"},
|
|
{(char *) "-oct", (char *) ".kaleid.oct", XrmoptionNoArg, (caddr_t) "on"},
|
|
{(char *) "+oct", (char *) ".kaleid.oct", XrmoptionNoArg, (caddr_t) "off"},
|
|
{(char *) "-linear", (char *) ".kaleid.linear", XrmoptionNoArg, (caddr_t) "on"},
|
|
{(char *) "+linear", (char *) ".kaleid.linear", XrmoptionNoArg, (caddr_t) "off"}
|
|
};
|
|
|
|
static argtype vars[] =
|
|
{
|
|
{(void *) & Disconnected, (char *) "disconnected", (char *) "Disconnected", (char *) DEF_DISCONNECTED, t_Bool},
|
|
{(void *) & Serial, (char *) "serial", (char *) "Serial", (char *) DEF_SERIAL, t_Bool},
|
|
{(void *) & Alternate, (char *) "alternate", (char *) "Alternate", (char *) DEF_ALTERNATE, t_Bool},
|
|
{(void *) & Spiral, (char *) "spiral", (char *) "Spiral", (char *) DEF_SPIRAL, t_Bool},
|
|
{(void *) & Spots, (char *) "spots", (char *) "Spots", (char *) DEF_SPOTS, t_Bool},
|
|
{(void *) & Quad, (char *) "quad", (char *) "Quad", (char *) DEF_QUAD, t_Bool},
|
|
{(void *) & Oct, (char *) "oct", (char *) "Oct", (char *) DEF_OCT, t_Bool},
|
|
{(void *) & Linear, (char *) "linear", (char *) "Linear", (char *) DEF_LINEAR, t_Bool}
|
|
};
|
|
|
|
static OptionStruct desc[] =
|
|
{
|
|
{(char *) "-/+disconnected", (char *) "turn on/off disconnected pen movement"},
|
|
{(char *) "-/+serial", (char *) "turn on/off sequential color selection"},
|
|
{(char *) "-/+alternate", (char *) "turn on/off alternate display mode"},
|
|
{(char *) "-/+spiral", (char *) "turn on/off angular bounding mode"},
|
|
{(char *) "-/+spots", (char *) "turn on/off circle mode"},
|
|
{(char *) "-/+quad", (char *) "turn on/off quad mirrored display mode"},
|
|
{(char *) "-/+oct", (char *) "turn on/off oct mirrored display mode"},
|
|
{(char *) "-/+linear", (char *) "select Cartesian/Polar coordinate display mode"}
|
|
};
|
|
|
|
ModeSpecOpt kaleid_opts =
|
|
{sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
|
|
|
|
#ifdef USE_MODULES
|
|
ModStruct kaleid_description =
|
|
{
|
|
"kaleid", "init_kaleid", "draw_kaleid", "release_kaleid",
|
|
"refresh_kaleid", "init_kaleid", (char *) NULL, &kaleid_opts,
|
|
80000, 4, 40, -9, 64, 0.6, "",
|
|
"Shows Brewster's Kaleidoscope", 0, NULL
|
|
};
|
|
|
|
#endif
|
|
|
|
#define INTRAND(min,max) (NRAND(((max+1)-(min)))+(min))
|
|
|
|
#define MINPENS 1
|
|
#define MINSIZE 1
|
|
#define QUAD (-4)
|
|
#define OCT (-8)
|
|
|
|
#define SpotsMult 3
|
|
|
|
#define MinVelocity 6
|
|
#define MaxVelocity 4
|
|
|
|
#define MinRadialVelocity 6
|
|
#define MaxRadialVelocity 30
|
|
|
|
#define MinAngularVelocity 5
|
|
#define MaxAngularVelocity 3
|
|
|
|
#define WidthPercent 25
|
|
#define ChangeChance 2
|
|
|
|
#define ToRadians 0.017453293
|
|
#define ToDegrees 57.29577951
|
|
#define PolarToCartX(r, t) ((r) * cos((t) * ToRadians))
|
|
#define PolarToCartY(r, t) ((r) * sin((t) * ToRadians))
|
|
#define CartToRadius(x, y) (sqrt(((x)*(x)) + ((y)*(y))))
|
|
#define CartToAngle(x,y) ((((x) == 0.0) && ((y) == 0.0)) ? 0.0 : (atan2((y),(x)) * ToDegrees))
|
|
|
|
typedef struct {
|
|
double cx;
|
|
double cy;
|
|
double ox;
|
|
double oy;
|
|
double xv;
|
|
double yv;
|
|
int curlwidth;
|
|
int pix;
|
|
int White;
|
|
Bool RadiusOut;
|
|
Bool AngleOut;
|
|
Bool DeferredChange;
|
|
} penstruct;
|
|
|
|
typedef struct {
|
|
penstruct *pen;
|
|
|
|
int PercentBlack;
|
|
int PenCount;
|
|
int maxlwidth;
|
|
double width, widthby2;
|
|
double height, heightby2;
|
|
double radius;
|
|
double slice;
|
|
int bouncetype;
|
|
int modetype;
|
|
Bool alternate, disconnected, serial, linear, spiral, spots;
|
|
} kaleidstruct;
|
|
|
|
static kaleidstruct *kaleids = (kaleidstruct *) NULL;
|
|
|
|
/*-
|
|
*
|
|
*/
|
|
static void
|
|
QuadMirrored(
|
|
kaleidstruct * kp,
|
|
int pn,
|
|
XSegment segs[4]
|
|
)
|
|
{
|
|
kp->pen[pn].cx = kp->pen[pn].cx + kp->pen[pn].xv;
|
|
if (kp->pen[pn].cx < 0.0) {
|
|
kp->pen[pn].cx = -kp->pen[pn].cx;
|
|
kp->pen[pn].xv = -kp->pen[pn].xv;
|
|
} else if (kp->pen[pn].cx >= kp->widthby2) {
|
|
kp->pen[pn].cx = (kp->widthby2 - 1.0)
|
|
- (kp->pen[pn].cx - kp->widthby2);
|
|
kp->pen[pn].xv = -kp->pen[pn].xv;
|
|
}
|
|
kp->pen[pn].cy = kp->pen[pn].cy + kp->pen[pn].yv;
|
|
if (kp->pen[pn].cy < 0.0) {
|
|
kp->pen[pn].cy = -kp->pen[pn].cy;
|
|
kp->pen[pn].yv = -kp->pen[pn].yv;
|
|
} else if (kp->pen[pn].cy >= kp->heightby2) {
|
|
kp->pen[pn].cy = (kp->heightby2 - 1.0)
|
|
- (kp->pen[pn].cy - kp->heightby2);
|
|
kp->pen[pn].yv = -kp->pen[pn].yv;
|
|
}
|
|
segs[0].x1 = (int) kp->pen[pn].ox;
|
|
segs[0].y1 = (int) kp->pen[pn].oy;
|
|
segs[0].x2 = (int) kp->pen[pn].cx;
|
|
segs[0].y2 = (int) kp->pen[pn].cy;
|
|
|
|
segs[1].x1 = (int) (kp->width - kp->pen[pn].ox);
|
|
segs[1].y1 = (int) kp->pen[pn].oy;
|
|
segs[1].x2 = (int) (kp->width - kp->pen[pn].cx);
|
|
segs[1].y2 = (int) kp->pen[pn].cy;
|
|
|
|
segs[2].x1 = (int) (kp->width - kp->pen[pn].ox);
|
|
segs[2].y1 = (int) (kp->height - kp->pen[pn].oy);
|
|
segs[2].x2 = (int) (kp->width - kp->pen[pn].cx);
|
|
segs[2].y2 = (int) (kp->height - kp->pen[pn].cy);
|
|
|
|
segs[3].x1 = (int) kp->pen[pn].ox;
|
|
segs[3].y1 = (int) (kp->height - kp->pen[pn].oy);
|
|
segs[3].x2 = (int) kp->pen[pn].cx;
|
|
segs[3].y2 = (int) (kp->height - kp->pen[pn].cy);
|
|
|
|
}
|
|
|
|
/*-
|
|
*
|
|
*/
|
|
static void
|
|
QuadRotated(
|
|
kaleidstruct * kp,
|
|
int pn,
|
|
XSegment segs[4]
|
|
)
|
|
{
|
|
double oxscaled2y;
|
|
double oyscaled2x;
|
|
double cxscaled2y;
|
|
double cyscaled2x;
|
|
|
|
kp->pen[pn].cx = kp->pen[pn].cx + kp->pen[pn].xv;
|
|
if (kp->pen[pn].cx < 0.0) {
|
|
kp->pen[pn].cx = -kp->pen[pn].cx;
|
|
kp->pen[pn].xv = -kp->pen[pn].xv;
|
|
} else if (kp->pen[pn].cx >= kp->widthby2) {
|
|
kp->pen[pn].cx = (kp->widthby2 - 1.0)
|
|
- (kp->pen[pn].cx - kp->widthby2);
|
|
kp->pen[pn].xv = -kp->pen[pn].xv;
|
|
}
|
|
kp->pen[pn].cy = kp->pen[pn].cy + kp->pen[pn].yv;
|
|
if (kp->pen[pn].cy < 0.0) {
|
|
kp->pen[pn].cy = -kp->pen[pn].cy;
|
|
kp->pen[pn].yv = -kp->pen[pn].yv;
|
|
} else if (kp->pen[pn].cy >= kp->heightby2) {
|
|
kp->pen[pn].cy = (kp->heightby2 - 1.0)
|
|
- (kp->pen[pn].cy - kp->heightby2);
|
|
kp->pen[pn].yv = -kp->pen[pn].yv;
|
|
}
|
|
segs[0].x1 = (int) kp->pen[pn].ox;
|
|
segs[0].y1 = (int) kp->pen[pn].oy;
|
|
segs[0].x2 = (int) kp->pen[pn].cx;
|
|
segs[0].y2 = (int) kp->pen[pn].cy;
|
|
|
|
oxscaled2y = ((kp->pen[pn].ox * kp->heightby2) / kp->widthby2);
|
|
oyscaled2x = ((kp->pen[pn].oy * kp->widthby2) / kp->heightby2);
|
|
cxscaled2y = ((kp->pen[pn].cx * kp->heightby2) / kp->widthby2);
|
|
cyscaled2x = ((kp->pen[pn].cy * kp->widthby2) / kp->heightby2);
|
|
|
|
segs[1].x1 = (int) (kp->width - oyscaled2x);
|
|
segs[1].y1 = (int) oxscaled2y;
|
|
segs[1].x2 = (int) (kp->width - cyscaled2x);
|
|
segs[1].y2 = (int) cxscaled2y;
|
|
|
|
segs[2].x1 = (int) (kp->width - kp->pen[pn].ox);
|
|
segs[2].y1 = (int) (kp->height - kp->pen[pn].oy);
|
|
segs[2].x2 = (int) (kp->width - kp->pen[pn].cx);
|
|
segs[2].y2 = (int) (kp->height - kp->pen[pn].cy);
|
|
|
|
segs[3].x1 = (int) oyscaled2x;
|
|
segs[3].y1 = (int) (kp->height - oxscaled2y);
|
|
segs[3].x2 = (int) cyscaled2x;
|
|
segs[3].y2 = (int) (kp->height - cxscaled2y);
|
|
|
|
}
|
|
|
|
/*-
|
|
*
|
|
*/
|
|
static void
|
|
GeneralPolarMoveAndBounce(
|
|
kaleidstruct * kp,
|
|
int pn
|
|
)
|
|
{
|
|
kp->pen[pn].cx = kp->pen[pn].cx + kp->pen[pn].xv;
|
|
if (kp->pen[pn].cx < 0.0) {
|
|
kp->pen[pn].cx = -kp->pen[pn].cx;
|
|
kp->pen[pn].xv = -kp->pen[pn].xv;
|
|
} else if (kp->pen[pn].cx >= kp->radius) {
|
|
kp->pen[pn].cx = (kp->radius - 1.0)
|
|
- (kp->pen[pn].cx - kp->radius);
|
|
kp->pen[pn].xv = -kp->pen[pn].xv;
|
|
}
|
|
switch (kp->bouncetype) {
|
|
case 0:
|
|
{
|
|
kp->pen[pn].cy = kp->pen[pn].cy + kp->pen[pn].yv;
|
|
break;
|
|
}
|
|
case 1:
|
|
{
|
|
kp->pen[pn].cy = kp->pen[pn].cy
|
|
+ ((kp->pen[pn].yv * kp->pen[pn].cx) / kp->radius);
|
|
break;
|
|
}
|
|
case 2:
|
|
{
|
|
kp->pen[pn].cy = kp->pen[pn].cy
|
|
+ ((kp->pen[pn].yv * (kp->radius - kp->pen[pn].cx)) / kp->radius);
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
kp->pen[pn].cy = kp->slice / 2.0;
|
|
kp->pen[pn].cx = kp->radius / 2.0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (kp->pen[pn].cy < 0) {
|
|
if (kp->spiral) {
|
|
kp->pen[pn].RadiusOut = False;
|
|
kp->pen[pn].cy = kp->pen[pn].cy + 360.0;
|
|
} else {
|
|
kp->pen[pn].RadiusOut = True;
|
|
if (kp->pen[pn].oy >= 0) {
|
|
kp->pen[pn].yv = -kp->pen[pn].yv;
|
|
}
|
|
}
|
|
} else if (kp->spiral) {
|
|
if (kp->pen[pn].cy > 360.0) {
|
|
kp->pen[pn].RadiusOut = False;
|
|
kp->pen[pn].cy = kp->pen[pn].cy - 360.0;
|
|
}
|
|
} else if (kp->pen[pn].cy >= kp->slice) {
|
|
kp->pen[pn].RadiusOut = True;
|
|
if (kp->pen[pn].oy < kp->slice) {
|
|
kp->pen[pn].yv = -kp->pen[pn].yv;
|
|
}
|
|
} else {
|
|
kp->pen[pn].RadiusOut = False;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/*-
|
|
*
|
|
*/
|
|
static void
|
|
GeneralRotated(
|
|
kaleidstruct * kp,
|
|
int pn,
|
|
XSegment * segs
|
|
)
|
|
{
|
|
double Angle;
|
|
int segnum;
|
|
|
|
|
|
GeneralPolarMoveAndBounce(kp, pn);
|
|
|
|
Angle = 0.0;
|
|
for (segnum = 0; segnum < kp->modetype; segnum += 1) {
|
|
if (! kp->spots) {
|
|
segs[segnum].x1 = (int) (PolarToCartX(kp->pen[pn].ox,
|
|
kp->pen[pn].oy + Angle
|
|
) + kp->widthby2
|
|
);
|
|
|
|
segs[segnum].y1 = (int) (PolarToCartY(kp->pen[pn].ox,
|
|
kp->pen[pn].oy + Angle
|
|
) + kp->heightby2
|
|
);
|
|
}
|
|
segs[segnum].x2 = (int) (PolarToCartX(kp->pen[pn].cx,
|
|
kp->pen[pn].cy + Angle
|
|
) + kp->widthby2
|
|
);
|
|
segs[segnum].y2 = (int) (PolarToCartY(kp->pen[pn].cx,
|
|
kp->pen[pn].cy + Angle
|
|
) + kp->heightby2
|
|
);
|
|
|
|
if (kp->spots) {
|
|
segs[segnum].x1 = segs[segnum].x2;
|
|
segs[segnum].y1 = segs[segnum].y2;
|
|
}
|
|
|
|
Angle += kp->slice;
|
|
}
|
|
}
|
|
|
|
/*-
|
|
*
|
|
*/
|
|
static void
|
|
GeneralMirrored(
|
|
kaleidstruct * kp,
|
|
int pn,
|
|
XSegment * segs
|
|
)
|
|
{
|
|
double Angle;
|
|
int segnum;
|
|
|
|
GeneralPolarMoveAndBounce(kp, pn);
|
|
|
|
Angle = 0.0;
|
|
for (segnum = 0; segnum < kp->modetype; segnum += 2) {
|
|
if (! kp->spots) {
|
|
segs[segnum].x1 = (int) (PolarToCartX(kp->pen[pn].ox,
|
|
kp->pen[pn].oy + Angle
|
|
) + kp->widthby2
|
|
);
|
|
|
|
segs[segnum].y1 = (int) (PolarToCartY(kp->pen[pn].ox,
|
|
kp->pen[pn].oy + Angle
|
|
) + kp->heightby2
|
|
);
|
|
}
|
|
|
|
segs[segnum].x2 = (int) (PolarToCartX(kp->pen[pn].cx,
|
|
kp->pen[pn].cy + Angle
|
|
) + kp->widthby2
|
|
);
|
|
|
|
segs[segnum].y2 = (int) (PolarToCartY(kp->pen[pn].cx,
|
|
kp->pen[pn].cy + Angle
|
|
) + kp->heightby2
|
|
);
|
|
|
|
if (kp->spots) {
|
|
segs[segnum].x1 = segs[segnum].x2;
|
|
segs[segnum].y1 = segs[segnum].y2;
|
|
}
|
|
|
|
Angle += (2.0 * kp->slice);
|
|
}
|
|
|
|
Angle = 360.0 - kp->slice;
|
|
for (segnum = 1; segnum < kp->modetype; segnum += 2) {
|
|
if (! kp->spots) {
|
|
segs[segnum].x1 =
|
|
(int) (PolarToCartX(kp->pen[pn].ox,
|
|
(kp->slice - kp->pen[pn].oy) + Angle
|
|
) + kp->widthby2
|
|
);
|
|
|
|
segs[segnum].y1 =
|
|
(int) (PolarToCartY(kp->pen[pn].ox,
|
|
(kp->slice - kp->pen[pn].oy) + Angle
|
|
) + kp->heightby2
|
|
);
|
|
}
|
|
|
|
segs[segnum].x2 =
|
|
(int) (PolarToCartX(kp->pen[pn].cx,
|
|
(kp->slice - kp->pen[pn].cy) + Angle
|
|
) + kp->widthby2
|
|
);
|
|
|
|
segs[segnum].y2 =
|
|
(int) (PolarToCartY(kp->pen[pn].cx,
|
|
(kp->slice - kp->pen[pn].cy) + Angle
|
|
) + kp->heightby2
|
|
);
|
|
|
|
if (kp->spots) {
|
|
segs[segnum].x1 = segs[segnum].x2;
|
|
segs[segnum].y1 = segs[segnum].y2;
|
|
}
|
|
Angle -= (2.0 * kp->slice);
|
|
}
|
|
}
|
|
|
|
/*-
|
|
*
|
|
*/
|
|
static void
|
|
OctMirrored(
|
|
kaleidstruct * kp,
|
|
int pn,
|
|
XSegment * segs
|
|
)
|
|
{
|
|
double xdiag;
|
|
double ydiag;
|
|
double oxscaled2y, cxscaled2y;
|
|
double oyscaled2x, cyscaled2x;
|
|
|
|
/*
|
|
* I know that the "bounce" is not really accurate, but I like the way
|
|
* it looks.
|
|
*/
|
|
|
|
xdiag = (kp->widthby2 * kp->pen[pn].oy) / kp->heightby2;
|
|
|
|
kp->pen[pn].cx = kp->pen[pn].cx + kp->pen[pn].xv;
|
|
if (kp->pen[pn].cx < xdiag) {
|
|
kp->pen[pn].cx = xdiag + (xdiag - kp->pen[pn].cx);
|
|
kp->pen[pn].xv = -kp->pen[pn].xv;
|
|
} else if (kp->pen[pn].cx >= kp->widthby2) {
|
|
kp->pen[pn].cx = (kp->widthby2 - 1.0)
|
|
- (kp->pen[pn].cx - kp->widthby2);
|
|
kp->pen[pn].xv = -kp->pen[pn].xv;
|
|
}
|
|
ydiag = (kp->heightby2 * kp->pen[pn].cx) / kp->widthby2;
|
|
|
|
kp->pen[pn].cy = kp->pen[pn].cy + kp->pen[pn].yv;
|
|
if (kp->pen[pn].cy < 0.0) {
|
|
kp->pen[pn].cy = -kp->pen[pn].cy;
|
|
kp->pen[pn].yv = -kp->pen[pn].yv;
|
|
} else if (kp->pen[pn].cy > ydiag) {
|
|
kp->pen[pn].cy = ydiag - (kp->pen[pn].cy - ydiag);
|
|
kp->pen[pn].yv = -kp->pen[pn].yv;
|
|
}
|
|
segs[0].x1 = (int) kp->pen[pn].ox;
|
|
segs[0].y1 = (int) kp->pen[pn].oy;
|
|
segs[0].x2 = (int) kp->pen[pn].cx;
|
|
segs[0].y2 = (int) kp->pen[pn].cy;
|
|
|
|
segs[1].x1 = (int) (kp->width - kp->pen[pn].ox);
|
|
segs[1].y1 = (int) kp->pen[pn].oy;
|
|
segs[1].x2 = (int) (kp->width - kp->pen[pn].cx);
|
|
segs[1].y2 = (int) kp->pen[pn].cy;
|
|
|
|
segs[4].x1 = segs[1].x1;
|
|
segs[4].y1 = (int) kp->height - segs[0].y1;
|
|
segs[4].x2 = segs[1].x2;
|
|
segs[4].y2 = (int) kp->height - segs[0].y2;
|
|
|
|
segs[5].x1 = segs[0].x1;
|
|
segs[5].y1 = (int) kp->height - segs[0].y1;
|
|
segs[5].x2 = segs[0].x2;
|
|
segs[5].y2 = (int) kp->height - segs[0].y2;
|
|
|
|
|
|
oxscaled2y = ((kp->pen[pn].ox * kp->heightby2) / kp->widthby2);
|
|
oyscaled2x = ((kp->pen[pn].oy * kp->widthby2) / kp->heightby2);
|
|
cxscaled2y = ((kp->pen[pn].cx * kp->heightby2) / kp->widthby2);
|
|
cyscaled2x = ((kp->pen[pn].cy * kp->widthby2) / kp->heightby2);
|
|
|
|
|
|
segs[7].x1 = (int) oyscaled2x;
|
|
segs[7].y1 = (int) oxscaled2y;
|
|
segs[7].x2 = (int) cyscaled2x;
|
|
segs[7].y2 = (int) cxscaled2y;
|
|
|
|
|
|
segs[2].x1 = (int) kp->width - segs[7].x1;
|
|
segs[2].y1 = segs[7].y1;
|
|
segs[2].x2 = (int) kp->width - segs[7].x2;
|
|
segs[2].y2 = segs[7].y2;
|
|
|
|
segs[6].x1 = segs[7].x1;
|
|
segs[6].y1 = (int) kp->height - segs[7].y1;
|
|
segs[6].x2 = segs[7].x2;
|
|
segs[6].y2 = (int) kp->height - segs[7].y2;
|
|
|
|
segs[3].x1 = (int) kp->width - segs[7].x1;
|
|
segs[3].y1 = segs[6].y1;
|
|
segs[3].x2 = (int) kp->width - segs[7].x2;
|
|
segs[3].y2 = segs[6].y2;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*-
|
|
*
|
|
*/
|
|
#if 0
|
|
static void
|
|
OldOctRotated(
|
|
kaleidstruct * kp,
|
|
int pn,
|
|
XSegment * segs
|
|
)
|
|
{
|
|
double angle, radius;
|
|
double oangle, oradius;
|
|
double rv, av;
|
|
double perp, para;
|
|
int i;
|
|
|
|
/*
|
|
* I know that the "bounce" is not really accurate, but I like the way
|
|
* it looks.
|
|
*/
|
|
|
|
kp->pen[pn].cx = kp->pen[pn].cx + kp->pen[pn].xv;
|
|
kp->pen[pn].cy = kp->pen[pn].cy + kp->pen[pn].yv;
|
|
angle = CartToAngle(kp->pen[pn].cx, kp->pen[pn].cy);
|
|
radius = CartToRadius(kp->pen[pn].cx, kp->pen[pn].cy);
|
|
|
|
oangle = CartToAngle(kp->pen[pn].ox, kp->pen[pn].oy);
|
|
oradius = CartToRadius(kp->pen[pn].ox, kp->pen[pn].oy);
|
|
|
|
if (radius < 0.0) {
|
|
if (kp->pen[pn].xv < 0.0) {
|
|
kp->pen[pn].xv = -kp->pen[pn].xv;
|
|
}
|
|
} else if (radius > kp->radius) {
|
|
if (kp->pen[pn].xv > 0.0) {
|
|
kp->pen[pn].xv = -kp->pen[pn].xv;
|
|
}
|
|
}
|
|
if (angle < 0.0) {
|
|
if (oangle > 0.0) {
|
|
kp->pen[pn].yv = -kp->pen[pn].yv;
|
|
}
|
|
} else if (angle > 45.0) {
|
|
if (oangle < 45.0) {
|
|
rv = CartToRadius(kp->pen[pn].xv, kp->pen[pn].yv);
|
|
av = CartToAngle(kp->pen[pn].xv, kp->pen[pn].yv);
|
|
|
|
para = PolarToCartX(rv, av - 45.0);
|
|
perp = PolarToCartY(rv, av - 45.0);
|
|
|
|
rv = CartToRadius(para, -perp);
|
|
av = CartToAngle(para, -perp);
|
|
|
|
kp->pen[pn].xv = PolarToCartX(rv, av + 45.0);
|
|
kp->pen[pn].yv = PolarToCartY(rv, av + 45.0);
|
|
}
|
|
}
|
|
for (i = 0; i < 8; i += 1) {
|
|
segs[i].x1 = (int) (kp->widthby2 + PolarToCartX(oradius, oangle));
|
|
segs[i].y1 = (int) (kp->heightby2 - PolarToCartY(oradius, oangle));
|
|
segs[i].x2 = (int) (kp->widthby2 + PolarToCartX(radius, angle));
|
|
segs[i].y2 = (int) (kp->heightby2 - PolarToCartY(radius, angle));
|
|
|
|
oangle += 45.0;
|
|
angle += 45.0;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
/*-
|
|
*
|
|
*/
|
|
static void
|
|
OctRotated(
|
|
kaleidstruct * kp,
|
|
int pn,
|
|
XSegment * segs
|
|
)
|
|
{
|
|
double xdiag;
|
|
double ydiag;
|
|
double radius, angle;
|
|
double oradius, oangle;
|
|
double ox, oy, cx, cy;
|
|
double offset;
|
|
int i;
|
|
|
|
/*
|
|
* I know that the "bounce" is not really accurate, but I like the way
|
|
* it looks.
|
|
*/
|
|
|
|
xdiag = (kp->widthby2 * kp->pen[pn].oy) / kp->heightby2;
|
|
|
|
kp->pen[pn].cx = kp->pen[pn].cx + kp->pen[pn].xv;
|
|
if (kp->pen[pn].cx < xdiag) {
|
|
kp->pen[pn].cx = xdiag + (xdiag - kp->pen[pn].cx);
|
|
kp->pen[pn].xv = -kp->pen[pn].xv;
|
|
} else if (kp->pen[pn].cx >= kp->widthby2) {
|
|
kp->pen[pn].cx = (kp->widthby2 - 1.0)
|
|
- (kp->pen[pn].cx - kp->widthby2);
|
|
kp->pen[pn].xv = -kp->pen[pn].xv;
|
|
}
|
|
ydiag = (kp->heightby2 * kp->pen[pn].cx) / kp->widthby2;
|
|
|
|
kp->pen[pn].cy = kp->pen[pn].cy + kp->pen[pn].yv;
|
|
if (kp->pen[pn].cy < 0.0) {
|
|
kp->pen[pn].cy = -kp->pen[pn].cy;
|
|
kp->pen[pn].yv = -kp->pen[pn].yv;
|
|
} else if (kp->pen[pn].cy > ydiag) {
|
|
kp->pen[pn].cy = ydiag - (kp->pen[pn].cy - ydiag);
|
|
kp->pen[pn].yv = -kp->pen[pn].yv;
|
|
}
|
|
offset = CartToRadius(kp->heightby2, kp->widthby2);
|
|
ox = (kp->pen[pn].ox * offset) / kp->widthby2;
|
|
oy = (kp->pen[pn].oy * offset) / kp->heightby2;
|
|
cx = (kp->pen[pn].cx * offset) / kp->widthby2;
|
|
cy = (kp->pen[pn].cy * offset) / kp->heightby2;
|
|
|
|
angle = CartToAngle(cx - offset,
|
|
offset - cy
|
|
) - 90.0;
|
|
radius = CartToRadius(cx - offset,
|
|
offset - cy
|
|
);
|
|
|
|
oangle = CartToAngle(ox - offset,
|
|
offset - oy
|
|
) - 90.0;
|
|
oradius = CartToRadius(ox - offset,
|
|
offset - oy
|
|
);
|
|
|
|
|
|
for (i = 0; i < 8; i += 1) {
|
|
segs[i].x1 = (int) (kp->widthby2 + PolarToCartX(oradius, oangle));
|
|
segs[i].y1 = (int) (kp->heightby2 - PolarToCartY(oradius, oangle));
|
|
segs[i].x2 = (int) (kp->widthby2 + PolarToCartX(radius, angle));
|
|
segs[i].y2 = (int) (kp->heightby2 - PolarToCartY(radius, angle));
|
|
|
|
oangle += 45.0;
|
|
angle += 45.0;
|
|
}
|
|
|
|
}
|
|
|
|
/*-
|
|
*
|
|
*/
|
|
static void
|
|
GeneralLinearMoveAndBounce(
|
|
kaleidstruct * kp,
|
|
int pn,
|
|
double *angle,
|
|
double *radius,
|
|
double *oangle,
|
|
double *oradius
|
|
)
|
|
{
|
|
double rv, av;
|
|
double perp, para;
|
|
|
|
kp->pen[pn].cx = kp->pen[pn].cx + kp->pen[pn].xv;
|
|
kp->pen[pn].cy = kp->pen[pn].cy + kp->pen[pn].yv;
|
|
|
|
*angle = CartToAngle(kp->pen[pn].cx, kp->pen[pn].cy);
|
|
*radius = CartToRadius(kp->pen[pn].cx, kp->pen[pn].cy);
|
|
|
|
*oangle = CartToAngle(kp->pen[pn].ox, kp->pen[pn].oy);
|
|
*oradius = CartToRadius(kp->pen[pn].ox, kp->pen[pn].oy);
|
|
|
|
if (*radius < 0.0) {
|
|
kp->pen[pn].RadiusOut = True;
|
|
if (*oradius > 0.0) {
|
|
rv = CartToRadius(kp->pen[pn].xv, kp->pen[pn].yv);
|
|
av = CartToAngle(kp->pen[pn].xv, kp->pen[pn].yv);
|
|
|
|
para = PolarToCartX(rv, av - (*angle + 90.0));
|
|
perp = PolarToCartY(rv, av - (*angle + 90.0));
|
|
|
|
rv = CartToRadius(para, -perp);
|
|
av = CartToAngle(para, -perp);
|
|
|
|
kp->pen[pn].xv = PolarToCartX(rv, av + (*angle + 90.0));
|
|
kp->pen[pn].yv = PolarToCartY(rv, av + (*angle + 90.0));
|
|
}
|
|
} else if (*radius > kp->radius) {
|
|
kp->pen[pn].RadiusOut = True;
|
|
if (*oradius < kp->radius) {
|
|
rv = CartToRadius(kp->pen[pn].xv, kp->pen[pn].yv);
|
|
av = CartToAngle(kp->pen[pn].xv, kp->pen[pn].yv);
|
|
|
|
para = PolarToCartX(rv, av - (*angle + 90.0));
|
|
perp = PolarToCartY(rv, av - (*angle + 90.0));
|
|
|
|
rv = CartToRadius(para, -perp);
|
|
av = CartToAngle(para, -perp);
|
|
|
|
kp->pen[pn].xv = PolarToCartX(rv, av + (*angle + 90.0));
|
|
kp->pen[pn].yv = PolarToCartY(rv, av + (*angle + 90.0));
|
|
}
|
|
} else {
|
|
kp->pen[pn].RadiusOut = False;
|
|
}
|
|
|
|
|
|
if (*angle < 0.0) {
|
|
if (kp->spiral) {
|
|
kp->pen[pn].AngleOut = False;
|
|
*angle = *angle + 360.0;
|
|
} else {
|
|
kp->pen[pn].AngleOut = True;
|
|
if (*oangle > 0.0) {
|
|
rv = CartToRadius(kp->pen[pn].xv, kp->pen[pn].yv);
|
|
av = CartToAngle(kp->pen[pn].xv, kp->pen[pn].yv);
|
|
|
|
para = PolarToCartX(rv, av);
|
|
perp = PolarToCartY(rv, av);
|
|
|
|
rv = CartToRadius(para, -perp);
|
|
av = CartToAngle(para, -perp);
|
|
|
|
kp->pen[pn].xv = PolarToCartX(rv, av);
|
|
kp->pen[pn].yv = PolarToCartY(rv, av);
|
|
}
|
|
}
|
|
} else if (kp->spiral) {
|
|
if (*angle > 360.0) {
|
|
kp->pen[pn].AngleOut = False;
|
|
*angle = *angle - 360.0;
|
|
}
|
|
} else if (*angle > kp->slice) {
|
|
kp->pen[pn].AngleOut = True;
|
|
if (*oangle < kp->slice) {
|
|
rv = CartToRadius(kp->pen[pn].xv, kp->pen[pn].yv);
|
|
av = CartToAngle(kp->pen[pn].xv, kp->pen[pn].yv);
|
|
|
|
para = PolarToCartX(rv, av - kp->slice);
|
|
perp = PolarToCartY(rv, av - kp->slice);
|
|
|
|
rv = CartToRadius(para, -perp);
|
|
av = CartToAngle(para, -perp);
|
|
|
|
kp->pen[pn].xv = PolarToCartX(rv, av + kp->slice);
|
|
kp->pen[pn].yv = PolarToCartY(rv, av + kp->slice);
|
|
}
|
|
} else {
|
|
kp->pen[pn].AngleOut = False;
|
|
}
|
|
}
|
|
|
|
/*-
|
|
*
|
|
*/
|
|
static void
|
|
GeneralLinearRotated(
|
|
kaleidstruct * kp,
|
|
int pn,
|
|
XSegment * segs
|
|
)
|
|
{
|
|
double angle, radius;
|
|
double oangle, oradius;
|
|
int i;
|
|
|
|
GeneralLinearMoveAndBounce(kp, pn, &angle, &radius, &oangle, &oradius);
|
|
|
|
for (i = 0; i < kp->modetype; i += 1) {
|
|
if (! kp->spots) {
|
|
segs[i].x1 = (int) (kp->widthby2 + PolarToCartX(oradius, oangle));
|
|
segs[i].y1 = (int) (kp->heightby2 - PolarToCartY(oradius, oangle));
|
|
}
|
|
|
|
segs[i].x2 = (int) (kp->widthby2 + PolarToCartX(radius, angle));
|
|
segs[i].y2 = (int) (kp->heightby2 - PolarToCartY(radius, angle));
|
|
|
|
if (kp->spots) {
|
|
segs[i].x1 = segs[i].x2;
|
|
segs[i].y1 = segs[i].y2;
|
|
}
|
|
|
|
oangle += kp->slice;
|
|
angle += kp->slice;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*-
|
|
*
|
|
*/
|
|
static void
|
|
GeneralLinearMirrored(
|
|
kaleidstruct * kp,
|
|
int pn,
|
|
XSegment * segs
|
|
)
|
|
{
|
|
double hangle, angle, radius;
|
|
double hoangle, oangle, oradius;
|
|
int i;
|
|
|
|
|
|
GeneralLinearMoveAndBounce(kp, pn, &angle, &radius, &oangle, &oradius);
|
|
|
|
hoangle = oangle;
|
|
hangle = angle;
|
|
|
|
for (i = 0; i < kp->modetype; i += 2) {
|
|
if (! kp->spots) {
|
|
segs[i].x1 = (int) (kp->widthby2 + PolarToCartX(oradius, oangle));
|
|
segs[i].y1 = (int) (kp->heightby2 - PolarToCartY(oradius, oangle));
|
|
}
|
|
|
|
segs[i].x2 = (int) (kp->widthby2 + PolarToCartX(radius, angle));
|
|
segs[i].y2 = (int) (kp->heightby2 - PolarToCartY(radius, angle));
|
|
|
|
if (kp->spots) {
|
|
segs[i].x1 = segs[i].x2;
|
|
segs[i].y1 = segs[i].y2;
|
|
}
|
|
|
|
oangle += 2.0 * kp->slice;
|
|
angle += 2.0 * kp->slice;
|
|
}
|
|
|
|
oangle = kp->slice * 2.0;
|
|
angle = kp->slice * 2.0;
|
|
for (i = 1; i < kp->modetype; i += 2) {
|
|
if (! kp->spots) {
|
|
segs[i].x1 = (int) (kp->widthby2 + PolarToCartX(oradius, oangle - hoangle));
|
|
segs[i].y1 = (int) (kp->heightby2 - PolarToCartY(oradius, oangle - hoangle));
|
|
}
|
|
|
|
segs[i].x2 = (int) (kp->widthby2 + PolarToCartX(radius, angle - hangle));
|
|
segs[i].y2 = (int) (kp->heightby2 - PolarToCartY(radius, angle - hangle));
|
|
|
|
if (kp->spots) {
|
|
segs[i].x1 = segs[i].x2;
|
|
segs[i].y1 = segs[i].y2;
|
|
}
|
|
|
|
oangle += 2.0 * kp->slice;
|
|
angle += 2.0 * kp->slice;
|
|
}
|
|
}
|
|
|
|
/*-
|
|
*
|
|
*/
|
|
static void
|
|
random_velocity(kaleidstruct * kp, int i)
|
|
{
|
|
int tMxRV, tMnRV;
|
|
int tMxAV, tMnAV;
|
|
int tMxV, tMnV;
|
|
|
|
if (kp->spots) {
|
|
tMxRV = MaxRadialVelocity * SpotsMult;
|
|
tMnRV = MinRadialVelocity * SpotsMult;
|
|
tMxAV = MaxAngularVelocity * SpotsMult;
|
|
tMnAV = MinAngularVelocity * SpotsMult;
|
|
tMxV = MaxVelocity * SpotsMult;
|
|
tMnV = MinVelocity * SpotsMult;
|
|
} else {
|
|
tMxRV = MaxRadialVelocity;
|
|
tMnRV = MinRadialVelocity;
|
|
tMxAV = MaxAngularVelocity;
|
|
tMnAV = MinAngularVelocity;
|
|
tMxV = MaxVelocity;
|
|
tMnV = MinVelocity;
|
|
}
|
|
|
|
|
|
if (kp->modetype > 0) {
|
|
kp->pen[i].xv = INTRAND(-tMxRV, tMxRV);
|
|
if (kp->pen[i].xv > 0.0) {
|
|
kp->pen[i].xv += tMnRV;
|
|
} else if (kp->pen[i].xv < 0.0) {
|
|
kp->pen[i].xv -= tMnRV;
|
|
}
|
|
kp->pen[i].yv = INTRAND(-tMxAV, tMxAV);
|
|
if (kp->pen[i].yv > 0.0) {
|
|
kp->pen[i].yv += tMnAV;
|
|
} else if (kp->pen[i].yv < 0.0) {
|
|
kp->pen[i].yv -= tMnAV;
|
|
}
|
|
} else {
|
|
kp->pen[i].xv = INTRAND(-tMxV, tMxV);
|
|
if (kp->pen[i].xv > 0.0) {
|
|
kp->pen[i].xv += tMnV;
|
|
} else if (kp->pen[i].xv < 0.0) {
|
|
kp->pen[i].xv -= tMnV;
|
|
}
|
|
kp->pen[i].yv = INTRAND(-tMxV, tMxV);
|
|
if (kp->pen[i].yv > 0.0) {
|
|
kp->pen[i].yv += tMnV;
|
|
} else if (kp->pen[i].yv < 0.0) {
|
|
kp->pen[i].yv -= tMnV;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
random_position(kaleidstruct * kp, int i)
|
|
{
|
|
|
|
if (kp->modetype >= 0) {
|
|
if (kp->linear) {
|
|
double radius, angle;
|
|
|
|
radius = (double) INTRAND(0, (int) (kp->radius - 1.0));
|
|
angle = (double) INTRAND(0, (int) (kp->slice - 1.0));
|
|
|
|
kp->pen[i].cx = PolarToCartX(radius, angle);
|
|
kp->pen[i].cy = PolarToCartY(radius, angle);
|
|
} else {
|
|
kp->pen[i].cx = (double) INTRAND(0, (int) (kp->radius - 1.0));
|
|
kp->pen[i].cy = (double) INTRAND(0, (int) (kp->slice - 1.0));
|
|
}
|
|
} else if (kp->modetype == OCT) {
|
|
double radius, angle;
|
|
|
|
radius = (double) INTRAND(0, (int) (kp->radius - 1.0));
|
|
angle = (double) INTRAND(0, 44);
|
|
|
|
kp->pen[i].cx = PolarToCartX(radius, angle);
|
|
kp->pen[i].cy = PolarToCartY(radius, angle);
|
|
} else {
|
|
kp->pen[i].cx = (double) INTRAND(0, (int) (kp->widthby2 - 1.0));
|
|
kp->pen[i].cy = (double) INTRAND(0,
|
|
(int) ((kp->heightby2 * kp->pen[i].cx) / kp->widthby2));
|
|
}
|
|
}
|
|
|
|
|
|
/*-
|
|
*
|
|
*/
|
|
void
|
|
init_kaleid(ModeInfo * mi)
|
|
{
|
|
int i;
|
|
kaleidstruct *kp;
|
|
|
|
|
|
if (kaleids == NULL) {
|
|
if ((kaleids = (kaleidstruct *) calloc(MI_NUM_SCREENS(mi),
|
|
sizeof (kaleidstruct))) == NULL)
|
|
return;
|
|
}
|
|
kp = &kaleids[MI_SCREEN(mi)];
|
|
|
|
kp->PenCount = MI_COUNT(mi);
|
|
|
|
if (MI_IS_FULLRANDOM(mi)) {
|
|
kp->alternate = (Bool) (LRAND() & 1);
|
|
kp->disconnected = (Bool) (LRAND() & 1);
|
|
kp->serial = (Bool) (LRAND() & 1);
|
|
kp->linear = (Bool) (LRAND() & 1);
|
|
kp->spiral = (Bool) (LRAND() & 1);
|
|
kp->spots = (Bool) (LRAND() & 1);
|
|
} else {
|
|
kp->alternate = Alternate;
|
|
kp->disconnected = Disconnected;
|
|
kp->serial = Serial;
|
|
kp->linear = Linear;
|
|
kp->spiral = Spiral;
|
|
kp->spots = Spots;
|
|
}
|
|
|
|
if (kp->PenCount < -MINPENS) {
|
|
/* if kp->PenCount is random ... the size can change */
|
|
if (kp->pen != NULL) {
|
|
free(kp->pen);
|
|
kp->pen = (penstruct *) NULL;
|
|
}
|
|
kp->PenCount = NRAND(-kp->PenCount - MINPENS + 1) + MINPENS;
|
|
} else if (kp->PenCount < MINPENS)
|
|
kp->PenCount = MINPENS;
|
|
|
|
if (kp->pen == NULL) {
|
|
if ((kp->pen = (penstruct *) malloc(kp->PenCount *
|
|
sizeof (penstruct))) == NULL)
|
|
return;
|
|
}
|
|
|
|
if ((MI_SIZE(mi)) > MINSIZE) {
|
|
kp->modetype = (!kp->alternate + 1) * MI_SIZE(mi);
|
|
} else if ((MI_SIZE(mi)) < -MINSIZE) {
|
|
kp->modetype = (!kp->alternate + 1) * (NRAND(-MI_SIZE(mi) + 1) + MINSIZE);
|
|
} else {
|
|
kp->modetype = (!kp->alternate + 1) * MINSIZE;
|
|
}
|
|
if (MI_IS_FULLRANDOM(mi)) {
|
|
int tmp;
|
|
|
|
tmp = NRAND(ABS(MI_SIZE(mi)) + 2);
|
|
if (tmp == 0)
|
|
kp->modetype = OCT;
|
|
else if (tmp == 1)
|
|
kp->modetype = QUAD;
|
|
} else {
|
|
if (Oct)
|
|
kp->modetype = OCT;
|
|
else if (Quad)
|
|
kp->modetype = QUAD;
|
|
}
|
|
|
|
kp->PercentBlack = (int) MAX(0, MIN(MI_CYCLES(mi), 95));
|
|
|
|
|
|
/* set various size parameters */
|
|
|
|
kp->width = (double) MI_WIDTH(mi);
|
|
kp->height = (double) MI_HEIGHT(mi);
|
|
|
|
if (kp->width < 2.0)
|
|
kp->width = 2.0;
|
|
if (kp->height < 2.0)
|
|
kp->height = 2.0;
|
|
|
|
kp->radius = sqrt(((kp->width * kp->width) +
|
|
(kp->height * kp->height)
|
|
) / 4.0
|
|
);
|
|
|
|
|
|
if (kp->modetype >= 0) {
|
|
kp->bouncetype = INTRAND(0, 2);
|
|
|
|
kp->slice = 360.0 / (double) kp->modetype;
|
|
|
|
kp->widthby2 = kp->width / 2.0;
|
|
kp->heightby2 = kp->height / 2.0;
|
|
} else {
|
|
kp->widthby2 = kp->width / 2.0;
|
|
kp->heightby2 = kp->height / 2.0;
|
|
}
|
|
|
|
/* set the maximum pen width */
|
|
if (kp->modetype >= 0) {
|
|
if ((kp->slice == 360.0) || (kp->slice == 180.0)) {
|
|
kp->maxlwidth = (int) ((((double) MIN(kp->widthby2, kp->heightby2)) *
|
|
(double) WidthPercent) / 100.0);
|
|
} else {
|
|
kp->maxlwidth = (int) (((sin(kp->slice * ToRadians) *
|
|
MIN(kp->widthby2, kp->heightby2)) *
|
|
(double) WidthPercent) / 100.0);
|
|
}
|
|
} else {
|
|
kp->maxlwidth = (int) ((MIN(kp->widthby2,
|
|
kp->heightby2
|
|
) * (double) WidthPercent
|
|
) / 100.0
|
|
);
|
|
}
|
|
|
|
if (kp->spots) {
|
|
kp->maxlwidth = 2 * kp->maxlwidth;
|
|
}
|
|
|
|
if (kp->maxlwidth <= 0) {
|
|
kp->maxlwidth = 1;
|
|
}
|
|
|
|
for (i = 0; i < kp->PenCount; i += 1) {
|
|
if (MI_NPIXELS(mi) > 2) {
|
|
kp->pen[i].pix = NRAND(MI_NPIXELS(mi));
|
|
kp->pen[i].White = 1;
|
|
} else {
|
|
kp->pen[i].White = 1;
|
|
}
|
|
|
|
kp->pen[i].curlwidth = INTRAND(1, kp->maxlwidth);
|
|
|
|
kp->pen[i].RadiusOut = False;
|
|
kp->pen[i].AngleOut = False;
|
|
|
|
random_position(kp, i);
|
|
|
|
kp->pen[i].ox = kp->pen[i].cx;
|
|
kp->pen[i].oy = kp->pen[i].cy;
|
|
kp->pen[i].DeferredChange = False;
|
|
|
|
random_velocity(kp, i);
|
|
}
|
|
|
|
MI_CLEARWINDOW(mi);
|
|
|
|
}
|
|
|
|
/*-
|
|
*
|
|
*/
|
|
static void
|
|
set_pen_attributes(ModeInfo * mi, kaleidstruct * kp, int i)
|
|
{
|
|
Display *display = MI_DISPLAY(mi);
|
|
GC gc = MI_GC(mi);
|
|
|
|
if (kp->pen[i].White) {
|
|
if (MI_NPIXELS(mi) > 2)
|
|
XSetForeground(display, gc, MI_PIXEL(mi, kp->pen[i].pix));
|
|
else
|
|
XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
|
|
} else {
|
|
XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
|
|
}
|
|
XSetLineAttributes(display, gc,
|
|
kp->pen[i].curlwidth, LineSolid, CapRound, JoinRound);
|
|
}
|
|
|
|
/*-
|
|
*
|
|
*/
|
|
static void
|
|
change_pen(ModeInfo * mi, kaleidstruct * kp, int i)
|
|
{
|
|
if (INTRAND(0, 100) < kp->PercentBlack) {
|
|
kp->pen[i].White = 0;
|
|
} else {
|
|
kp->pen[i].White = 1;
|
|
if (kp->serial) {
|
|
if (MI_NPIXELS(mi) > 2) {
|
|
if (++kp->pen[i].pix >= MI_NPIXELS(mi))
|
|
kp->pen[i].pix = 0;
|
|
}
|
|
} else {
|
|
if (MI_NPIXELS(mi) > 2) {
|
|
kp->pen[i].pix = NRAND(MI_NPIXELS(mi));
|
|
}
|
|
}
|
|
}
|
|
|
|
random_velocity(kp, i);
|
|
|
|
kp->pen[i].curlwidth = INTRAND(1, kp->maxlwidth);
|
|
|
|
if (kp->modetype >= 0) {
|
|
kp->bouncetype = INTRAND(0, 2);
|
|
}
|
|
if (kp->disconnected) {
|
|
random_position(kp, i);
|
|
kp->pen[i].ox = kp->pen[i].cx;
|
|
kp->pen[i].oy = kp->pen[i].cy;
|
|
}
|
|
}
|
|
|
|
/*-
|
|
*
|
|
*/
|
|
void
|
|
draw_kaleid(ModeInfo * mi)
|
|
{
|
|
Display *display = MI_DISPLAY(mi);
|
|
GC gc = MI_GC(mi);
|
|
XSegment *segs;
|
|
int NumberOfSegments;
|
|
int i;
|
|
kaleidstruct *kp;
|
|
|
|
if (kaleids == NULL)
|
|
return;
|
|
kp = &kaleids[MI_SCREEN(mi)];
|
|
if (kp->pen == NULL)
|
|
return;
|
|
|
|
MI_IS_DRAWN(mi) = True;
|
|
if (kp->modetype == QUAD) {
|
|
NumberOfSegments = 4;
|
|
} else if (kp->modetype == OCT) {
|
|
NumberOfSegments = 8;
|
|
} else { /* if (kp->modetype > 0) */
|
|
NumberOfSegments = kp->modetype;
|
|
}
|
|
if ((segs = (XSegment *) malloc(NumberOfSegments *
|
|
sizeof (XSegment))) == NULL) {
|
|
free(kp->pen);
|
|
kp->pen = (penstruct *) NULL;
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < kp->PenCount; i++) {
|
|
set_pen_attributes(mi, kp, i);
|
|
|
|
if (kp->modetype == QUAD) {
|
|
if (kp->alternate) {
|
|
QuadRotated(kp, i, segs);
|
|
} else {
|
|
QuadMirrored(kp, i, segs);
|
|
}
|
|
} else if (kp->modetype == OCT) {
|
|
if (kp->alternate) {
|
|
OctRotated(kp, i, segs);
|
|
} else {
|
|
OctMirrored(kp, i, segs);
|
|
}
|
|
} else {
|
|
if (kp->alternate) {
|
|
|
|
if (kp->linear) {
|
|
GeneralLinearRotated(kp, i, segs);
|
|
} else {
|
|
GeneralRotated(kp, i, segs);
|
|
}
|
|
} else {
|
|
if (kp->linear) {
|
|
GeneralLinearMirrored(kp, i, segs);
|
|
} else {
|
|
GeneralMirrored(kp, i, segs);
|
|
}
|
|
}
|
|
}
|
|
XDrawSegments(
|
|
display,
|
|
MI_WINDOW(mi),
|
|
gc,
|
|
segs,
|
|
NumberOfSegments
|
|
);
|
|
|
|
kp->pen[i].ox = kp->pen[i].cx;
|
|
kp->pen[i].oy = kp->pen[i].cy;
|
|
|
|
|
|
if ((INTRAND(0, 100) < ChangeChance) || kp->pen[i].DeferredChange) {
|
|
if (!kp->pen[i].AngleOut && !kp->pen[i].RadiusOut) {
|
|
kp->pen[i].DeferredChange = False;
|
|
change_pen(mi, kp, i);
|
|
} else {
|
|
kp->pen[i].DeferredChange = True;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
XSetLineAttributes(display, gc, 1, LineSolid, CapRound, JoinRound);
|
|
free(segs);
|
|
}
|
|
|
|
/*-
|
|
*
|
|
*/
|
|
void
|
|
release_kaleid(ModeInfo * mi)
|
|
{
|
|
if (kaleids != NULL) {
|
|
int screen;
|
|
|
|
for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
|
|
kaleidstruct *kp = &kaleids[screen];
|
|
|
|
if (kp->pen != NULL)
|
|
free(kp->pen);
|
|
}
|
|
free(kaleids);
|
|
kaleids = (kaleidstruct *) NULL;
|
|
}
|
|
}
|
|
|
|
/*-
|
|
*
|
|
*/
|
|
void
|
|
refresh_kaleid(ModeInfo * mi)
|
|
{
|
|
MI_CLEARWINDOW(mi);
|
|
}
|
|
|
|
#endif /* MODE_kaleid */
|