Edit

IABSD.fr/xenocara/app/xlockmore/modes/petal.c

Branch :

  • Show log

    Commit

  • Author : matthieu
    Date : 2006-11-26 11:07:42
    Hash : 110b2a92
    Message : Importing xlockmore 5.22

  • app/xlockmore/modes/petal.c
  • /* -*- Mode: C; tab-width: 4 -*- */
    /* petal --- mathematical flowers */
    
    #if !defined( lint ) && !defined( SABER )
    static const char sccsid[] = "@(#)petal.c	5.00 2000/11/01 xlockmore";
    
    #endif
    
    /*-
     * 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
     * 10-May-1997: Compatible with xscreensaver
     * 12-Aug-1995: xlock version
     * Jan-1995: xscreensaver version (Jamie Zawinski <jwz@jwz.org>)
     * 24-Jun-1994: X11 version (Dale Moore  <Dale.Moore@cs.cmu.edu>)
     *              Based on a program for some old PDP-11 Graphics
     *              Display Processors at CMU.
     */
    
    /*-
     * original copyright
     * Copyright \(co 1994, by Carnegie Mellon University.  Permission to use,
     * copy, modify, distribute, and sell this software and its documentation
     * for any purpose is hereby granted without fee, provided fnord that the
     * above copyright notice appear in all copies and that both that copyright
     * notice and this permission notice appear in supporting documentation.
     * No representations are made about the  suitability of fnord this software
     * for any purpose.  It is provided "as is" without express or implied
     * warranty.
     */
    
    #ifdef STANDALONE
    #define MODE_petal
    #define PROGCLASS "Petal"
    #define HACK_INIT init_petal
    #define HACK_DRAW draw_petal
    #define petal_opts xlockmore_opts
    #define DEFAULTS "*delay: 10000 \n" \
     "*count: -500 \n" \
     "*cycles: 400 \n" \
     "*ncolors: 64 \n" \
     "*wireframe: False \n" \
     "*fullrandom: False \n"
    #include "xlockmore.h"		/* in xscreensaver distribution */
    #else /* STANDALONE */
    #include "xlock.h"		/* in xlockmore distribution */
    #endif /* STANDALONE */
    
    #ifdef MODE_petal
    
    ModeSpecOpt petal_opts =
    {0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL};
    
    #ifdef USE_MODULES
    ModStruct   petal_description =
    {"petal", "init_petal", "draw_petal", "release_petal",
     "refresh_petal", "init_petal", (char *) NULL, &petal_opts,
     10000, -500, 400, 1, 64, 1.0, "",
     "Shows various GCD Flowers", 0, NULL};
    
    #endif
    
    #define TWOPI (2.0*M_PI)
    
    /*-
     * If MAXLINES is too big, we might not be able to get it
     * to the X server in the 2byte length field.
     * Must be less * than 16k
     */
    #define MAXLINES (16*1024)
    
    /*-
     * If the petal has only this many lines, it must be ugly and we do not
     * want to see it.
     */
    #define MINLINES 5
    
    typedef struct {
    	Bool        painted;
    	int         width, height;
    	int         lines;
    	int         time;
    	int         npoints;
    	long        color;
    	XPoint     *points;
    	Bool        wireframe;
    } petalstruct;
    
    static petalstruct *petals = (petalstruct *) NULL;
    
    /*-
     * Macro:
     *   sine
     *   cosine
     * Description:
     *   Assume that degrees is .. oh 360... meaning that
     *   there are 360 degress in a circle.  Then this function
     *   would return the sin of the angle in degrees.  But lets
     *   say that they are really big degrees, with 4 big degrees
     *   the same as one regular degree.  Then this routine
     *   would be called mysin(t, 90) and would return sin(t degrees * 4)
     */
    #define sine(t, degrees) sin(t * TWOPI / (degrees))
    #define cosine(t, degrees) cos(t * TWOPI / (degrees))
    
    /*-
     * Macro:
     *   rand_range
     * Description:
     *   Return a random number between a inclusive  and b exclusive.
     *    rand (3, 6) returns 3 or 4 or 5, but not 6.
     */
    #define rand_range(a, b) (a + NRAND(b - a))
    
    static int
    gcd(int m, int n)
    /*-
     * Greatest Common Divisor (also Greatest common factor).
     */
    {
    	int         r;
    
    	for (;;) {
    		r = m % n;
    		if (r == 0)
    			return (n);
    		m = n;
    		n = r;
    	}
    }
    
    static int
    numlines(int a, int b, int d)
    /*-
     * Description:
     *
     *      Given parameters a and b, how many lines will we have to draw?
     *
     * Algorithm:
     *
     *      This algorithm assumes that r = sin (theta * a), where we
     *      evaluate theta on multiples of b.
     *
     *      LCM (i, j) = i * j / GCD (i, j);
     *
     *      So, at LCM (b, 360) we start over again.  But since we
     *      got to LCM (b, 360) by steps of b, the number of lines is
     *      LCM (b, 360) / b.
     *
     *      If a is odd, then at 180 we cross over and start the
     *      negative.  Someone should write up an elegant way of proving
     *      this.  Why?  Because I'm not convinced of it myself.
     *
     */
    {
    #define odd(x) (x & 1)
    #define even(x) (!odd(x))
    	if (odd(a) && odd(b) && even(d))
    		d /= 2;
    	return (d / gcd(d, b));
    #undef odd
    }
    
    static int
    compute_petal(XPoint * points, int lines, int sizex, int sizey)
    /*-
     * Description:
     *
     *    Basically, it's combination spirograph and string art.
     *    Instead of doing lines, we just use a complex polygon,
     *    and use an even/odd rule for filling in between.
     *
     *    The spirograph, in mathematical terms is a polar
     *    plot of the form r = sin (theta * c);
     *    The string art of this is that we evaluate that
     *    function only on certain multiples of theta.  That is
     *    we let theta advance in some random increment.  And then
     *    we draw a straight line between those two adjacent points.
     *
     *    Eventually, the lines will start repeating themselves
     *    if we've evaluated theta on some rational portion of the
     *    whole.
     *
     *    The number of lines generated is limited to the
     *    ratio of the increment we put on theta to the whole.
     *    If we say that there are 360 degrees in a circle, then we
     *    will never have more than 360 lines.
     *
     * Return:
     *
     *    The number of points.
     *
     */
    {
    	int         a, b, d;	/* These describe a unique petal */
    
    	double      r;
    	int         theta = 0;
    	XPoint     *p = points;
    	int         count;
    	int         npoints;
    
    	for (;;) {
    		d = lines;
    
    		a = rand_range(1, d);
    		b = rand_range(1, d);
    		npoints = numlines(a, b, d);
    		if (npoints >= MINLINES)
    			break;
    	}
    
    	/* it might be nice to try to move as much sin and cos computing
    	 * (or at least the argument computing) out of the loop.
    	 */
    	for (count = npoints; count--;) {
    		r = sine(theta * a, d);
    
    		/* Convert from polar to cartesian coordinates */
    		/* We could round the results, but coercing seems just fine */
    		p->x = (int) (sine(theta, d) * r * sizex + sizex);
    		p->y = (int) (cosine(theta, d) * r * sizey + sizey);
    
    		/* Advance index into array */
    		p++;
    
    		/* Advance theta */
    		theta += b;
    		theta %= d;
    	}
    	*p = points[0];		/* Tack on another for XDrawLines */
    
    	return (npoints);
    }
    
    static void
    petal(ModeInfo * mi)
    {
    	petalstruct *pp = &petals[MI_SCREEN(mi)];
    
    	XSetForeground(MI_DISPLAY(mi), MI_GC(mi), pp->color);
    	if (pp->wireframe) {
    		XDrawLines(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
    			   pp->points, pp->npoints + 1, CoordModeOrigin);
    	} else {
    		XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
    			  pp->points, pp->npoints, Complex, CoordModeOrigin);
    	}
    }
    
    static void
    random_petal(ModeInfo * mi)
    {
    	petalstruct *pp = &petals[MI_SCREEN(mi)];
    
    	pp->npoints = compute_petal(pp->points, pp->lines,
    				    pp->width / 2, pp->height / 2);
    
    	if (MI_NPIXELS(mi) <= 2)
    		pp->color = MI_WHITE_PIXEL(mi);
    	else
    		pp->color = MI_PIXEL(mi, NRAND(MI_NPIXELS(mi)));
    	petal(mi);
    }
    
    void
    init_petal(ModeInfo * mi)
    {
    	petalstruct *pp;
    
    	if (petals == NULL) {
    		if ((petals = (petalstruct *) calloc(MI_NUM_SCREENS(mi),
    					      sizeof (petalstruct))) == NULL)
    			return;
    	}
    	pp = &petals[MI_SCREEN(mi)];
    
    	pp->lines = MI_COUNT(mi);
    	if (pp->lines > MAXLINES)
    		pp->lines = MAXLINES;
    	else if (pp->lines < -MINLINES) {
    		if (pp->points) {
    			free(pp->points);
    			pp->points = (XPoint *) NULL;
    		}
    		pp->lines = NRAND(-pp->lines - MINLINES + 1) + MINLINES;
    	} else if (pp->lines < MINLINES)
    		pp->lines = MINLINES;
    	if (!pp->points)
    		if ((pp->points = (XPoint *) malloc((pp->lines + 1) *
    				sizeof (XPoint))) == NULL) {
    			return;
    		}
    	pp->width = MI_WIDTH(mi);
    	pp->height = MI_HEIGHT(mi);
    
    	pp->time = 0;
    	if (MI_IS_FULLRANDOM(mi))
    		pp->wireframe = (Bool) (LRAND() & 1);
    	else
    		pp->wireframe = MI_IS_WIREFRAME(mi);
    
    	MI_CLEARWINDOW(mi);
    	pp->painted = False;
    
    	random_petal(mi);
    }
    
    void
    draw_petal(ModeInfo * mi)
    {
    	petalstruct *pp;
    
    	if (petals == NULL)
    		return;
    	pp = &petals[MI_SCREEN(mi)];
    
    	MI_IS_DRAWN(mi) = True;
    	if (++pp->time > MI_CYCLES(mi))
    		init_petal(mi);
    	else
    		pp->painted = True;
    }
    
    void
    release_petal(ModeInfo * mi)
    {
    	if (petals != NULL) {
    		int         screen;
    
    		for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
    			petalstruct *pp = &petals[screen];
    
    			if (pp->points)
    				free(pp->points);
    		}
    		free(petals);
    		petals = (petalstruct *) NULL;
    	}
    }
    
    void
    refresh_petal(ModeInfo * mi)
    {
    	petalstruct *pp;
    
    	if (petals == NULL)
    		return;
    	pp = &petals[MI_SCREEN(mi)];
    
    	if (pp->painted) {
    		MI_CLEARWINDOW(mi);
    		petal(mi);
    		pp->painted = False;
    	}
    }
    
    #endif /* MODE_petal */