1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* blot --- Rorschach's ink blot test */
3 
4 #if 0
5 static const char sccsid[] = "@(#)blot.c	5.00 2000/11/01 xlockmore";
6 
7 #endif
8 
9 /*-
10  * Copyright (c) 1992 by Jamie Zawinski
11  *
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.
17  *
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.
23  *
24  * 01-Nov-2000: Allocation checks
25  * 10-May-1997: Compatible with xscreensaver
26  * 05-Jan-1995: patch for Dual-Headed machines from Greg Onufer
27  *              <Greg.Onufer@Eng.Sun.COM>
28  * 07-Dec-1994: now randomly has xsym, ysym, or both.
29  * 02-Sep-1993: xlock version David Bagley <bagleyd AT verizon.net>
30  * 1992:        xscreensaver version Jamie Zawinski <jwz AT jwz.org>
31  */
32 
33 /*-
34  * original copyright
35  * Copyright (c) 1992 by Jamie Zawinski
36  * Permission to use, copy, modify, distribute, and sell this software and
37  * its documentation for any purpose is hereby granted without fee, provided
38  * that the above copyright notice appear in all copies and that both that
39  * copyright notice and this permission notice appear in supporting
40  * documentation.  No representations are made about the suitability of this
41  * software for any purpose.  It is provided "as is" without express or
42  * implied warranty.
43  */
44 
45 #ifdef STANDALONE
46 # define MODE_blot
47 # define DEFAULTS	"*delay: 2000000 \n" \
48 			"*count: 6 \n" \
49 			"*cycles: 30 \n" \
50 			"*ncolors: 200 \n" \
51 
52 # define reshape_blot 0
53 # define blot_handle_event 0
54 # include "xlockmore.h"		/* in xscreensaver distribution */
55 #else /* STANDALONE */
56 # include "xlock.h"		/* in xlockmore distribution */
57 #endif /* STANDALONE */
58 
59 #ifdef MODE_blot
60 
61 ENTRYPOINT ModeSpecOpt blot_opts =
62 {0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL};
63 
64 #ifdef USE_MODULES
65 const ModStruct blot_description =
66 {"blot", "init_blot", "draw_blot", "release_blot",
67  "refresh_blot", "init_blot", "free_blot", &blot_opts,
68  200000, 6, 30, 1, 64, 0.3, "",
69  "Shows Rorschach's ink blot test", 0, NULL};
70 
71 #endif
72 
73 typedef struct {
74 	int         width;
75 	int         height;
76 	int         xmid, ymid;
77 	int         offset;
78 	int         xsym, ysym;
79 	int         size;
80 	int         pix;
81 	int         count;
82 	XPoint     *pointBuffer;
83 	unsigned int pointBufferSize;
84 } blotstruct;
85 
86 static blotstruct *blots = (blotstruct *) NULL;
87 
88 ENTRYPOINT void
init_blot(ModeInfo * mi)89 init_blot(ModeInfo * mi)
90 {
91 	Display    *display = MI_DISPLAY(mi);
92 	blotstruct *bp;
93 
94 	MI_INIT(mi, blots);
95 	bp = &blots[MI_SCREEN(mi)];
96 
97 	bp->width = MI_WIDTH(mi);
98 	bp->height = MI_HEIGHT(mi);
99 	bp->xmid = bp->width / 2;
100 	bp->ymid = bp->height / 2;
101 
102 	bp->offset = 4;
103 	bp->ysym = (int) LRAND() & 1;
104 	bp->xsym = (bp->ysym) ? (int) LRAND() & 1 : 1;
105 	if (MI_NPIXELS(mi) > 2)
106 		bp->pix = NRAND(MI_NPIXELS(mi));
107 	if (bp->offset <= 0)
108 		bp->offset = 3;
109 	if (MI_COUNT(mi) < 0)
110 		bp->size = NRAND(-MI_COUNT(mi) + 1);
111 	else
112 		bp->size = MI_COUNT(mi);
113 
114 	/* Fudge the size so it takes up the whole screen */
115 	bp->size *= (bp->width / 32 + 1) * (bp->height / 32 + 1);
116 	if (!bp->pointBuffer || bp->pointBufferSize < bp->size * sizeof (XPoint)) {
117 		if (bp->pointBuffer != NULL)
118 			free(bp->pointBuffer);
119 		bp->pointBufferSize = bp->size * sizeof (XPoint);
120 		if ((bp->pointBuffer = (XPoint *) malloc(bp->pointBufferSize)) ==
121 				NULL) {
122 			return;
123 		}
124 	}
125 	MI_CLEARWINDOW(mi);
126 	XSetForeground(display, MI_GC(mi), MI_WHITE_PIXEL(mi));
127 	bp->count = 0;
128 }
129 
130 ENTRYPOINT void
draw_blot(ModeInfo * mi)131 draw_blot(ModeInfo * mi)
132 {
133 	blotstruct *bp;
134 	XPoint     *xp;
135 	int         x, y, k;
136 
137 	if (blots == NULL)
138 		return;
139 	bp = &blots[MI_SCREEN(mi)];
140 	xp = bp->pointBuffer;
141 	if (xp == NULL)
142 		init_blot(mi);
143 
144 	MI_IS_DRAWN(mi) = True;
145 	if (MI_NPIXELS(mi) > 2) {
146 		XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_PIXEL(mi, bp->pix));
147 		if (++bp->pix >= MI_NPIXELS(mi))
148 			bp->pix = 0;
149 	}
150 	x = bp->xmid;
151 	y = bp->ymid;
152 	k = bp->size;
153 	while (k >= 4) {
154 		x += (NRAND(1 + (bp->offset << 1)) - bp->offset);
155 		y += (NRAND(1 + (bp->offset << 1)) - bp->offset);
156 		k--;
157 		xp->x = x;
158 		xp->y = y;
159 		xp++;
160 		if (bp->xsym) {
161 			k--;
162 			xp->x = bp->width - x;
163 			xp->y = y;
164 			xp++;
165 		}
166 		if (bp->ysym) {
167 			k--;
168 			xp->x = x;
169 			xp->y = bp->height - y;
170 			xp++;
171 		}
172 		if (bp->xsym && bp->ysym) {
173 			k--;
174 			xp->x = bp->width - x;
175 			xp->y = bp->height - y;
176 			xp++;
177 		}
178 	}
179 	XDrawPoints(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
180 		    bp->pointBuffer, (bp->size - k), CoordModeOrigin);
181 	if (++bp->count > MI_CYCLES(mi))
182 		init_blot(mi);
183 }
184 
185 static void
free_blot_screen(blotstruct * bp)186 free_blot_screen(blotstruct *bp)
187 {
188 	if (bp == NULL) {
189 		return;
190 	}
191 	if (bp->pointBuffer != NULL) {
192 		free(bp->pointBuffer);
193 		bp->pointBuffer = NULL;
194 	}
195 	bp = NULL;
196 }
197 
198 
199 ENTRYPOINT void
free_blot(ModeInfo * mi)200 free_blot(ModeInfo * mi)
201 {
202         blotstruct *bp = &blots[MI_SCREEN(mi)];
203         free_blot_screen(bp);
204 }
205 
206 ENTRYPOINT void
release_blot(ModeInfo * mi)207 release_blot(ModeInfo * mi)
208 {
209 	if (blots != NULL) {
210 		int         screen;
211 
212 		for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
213 			free_blot_screen(&blots[screen]);
214 		}
215 		free(blots);
216 		blots = (blotstruct *) NULL;
217 	}
218 }
219 
220 #ifndef STANDALONE
221 ENTRYPOINT void
refresh_blot(ModeInfo * mi)222 refresh_blot(ModeInfo * mi)
223 {
224 	MI_CLEARWINDOW(mi);
225 }
226 #endif
227 
228 XSCREENSAVER_MODULE ("Blot", blot)
229 
230 #endif /* MODE_blot */
231