Subversion Repositories Kolibri OS

Rev

Rev 8129 | Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1769 yogev_ezra 1
#include 
2
#include 
3
#include 
4
#include "lifegen.h"
5
#include "life_bmp.h"
6
#include "me_cdlg.h"
7
 
8
using namespace Menuet;
9
 
10
/***
11
#define StrLen   LibbStrLen
12
#define StrCopy  LibbStrCopy
13
#define MemCopy  LibbMemCopy
14
#define MemSet   LibbMemSet
15
#define Floor    LibbFloor
16
 
17
unsigned int (*StrLen)(const char *str) = 0;
18
char *(*StrCopy)(char *dest, const char *src) = 0;
19
void *(*MemCopy)(void *dest, const void *src, unsigned int n) = 0;
20
void *(*MemSet)(void *s, char c, unsigned int n) = 0;
21
double (*Floor)(double x) = 0;
22
 
23
#include 
24
void LibbInit()
25
{
26
	HINSTANCE hLib = LoadLibrary("Libb.dll");
27
	if (!hLib)
28
	{
29
		DebugPutString("Can't load the library.\n");
30
		Menuet::Abort();
31
	}
32
	StrLen = (unsigned int(*)(const char *str))GetProcAddress(hLib, "StrLen");
33
	StrCopy = (char *(*)(char *dest, const char *src))GetProcAddress(hLib, "StrCopy");
34
	MemCopy = (void *(*)(void *dest, const void *src, unsigned int n))GetProcAddress(hLib, "MemCopy");
35
	MemSet = (void *(*)(void *s, char c, unsigned int n))GetProcAddress(hLib, "MemSet");
36
	Floor = (double (*)(double x))GetProcAddress(hLib, "Floor");
37
}
38
 
39
#pragma startup LibbInit
40
/**/
41
 
42
void __stdcall OneGeneration(int w, int h, void *dest, const void *src, int flag);
43
 
44
struct GenerateParam
45
{
46
	unsigned int gps;
47
	unsigned int paint_time, time, count;
48
	bool stop;
49
	int paint;
50
	double speed;
51
};
52
 
53
struct AxisParam
54
{
55
	unsigned int win;
56
	int p;
57
	double shift;
58
};
59
 
60
struct MouseParam
61
{
62
	int hit_x, hit_y, last_x, last_y;
63
	int button, hit_type;
64
 
65
	enum {HitNull = 0, HitLine, HitCircle, HitScroll};
66
};
67
 
68
struct MenuButtonParam
69
{
70
	int left, size, border;
71
	bool check;
72
	const unsigned char *bitmap;
73
 
74
	int Left() const {return left;}
75
	int Right() const {return left + size;}
76
};
77
 
78
const int MenuDig = 10;
79
 
80
struct MenuParam
81
{
82
	enum {Size = 20, NButton = 14};
83
 
84
	bool draw;
85
	int pressed, current, edit;
86
	int edit_index, edit_num[2], edit_num_max;
87
	MenuButtonParam button[NButton];
88
	const unsigned char *digit[MenuDig];
89
};
90
 
91
struct TimeGeneration
92
{
93
	unsigned int t, g;
94
};
95
 
96
enum MenuItem {MenuIHide, MenuIClear, MenuIOpen, MenuIAbout, MenuIExit,
97
				MenuIGenerate, MenuIRandom, MenuIVCircle, MenuIHCircle,
98
				MenuILine, MenuIScroll, MenuIWinSize, MenuISize, MenuISpeed};
99
 
100
enum {PaintWNull = 0, PaintWPole = 1, PaintWMenuBorder = 2, PaintWMenu = 6,
101
		PaintWSpeed = 8, PaintWAll = 15, PaintWFast = 64, PaintWNow = 128};
102
 
103
enum {TimeGenLength = 500};
104
 
105
unsigned char *life_data = 0, *picture = 0;
106
GenerateParam generate = {0, 0, 0, 0, false, PaintWNull, 0};
107
AxisParam xpar = {0, 0, 0};
108
AxisParam ypar = {0, 0, 0};
109
MouseParam mpar = {0, 0, 0, 0, 0, MouseParam::HitNull};
110
MenuParam menu;
111
TOpenFileStruct open_file_str = MENUET_OPEN_FILE_INIT;
112
TimeGeneration timegen[TimeGenLength];
113
int timegenpos = 0;
114
 
115
#ifdef __MENUET__
116
 
117
inline int abs(int i) {return (i >= 0) ? i : (-i);}
118
 
119
unsigned int rand_data[4];
120
 
121
void randomize()
122
{
123
	rand_data[0] = (unsigned int)Clock();
124
	rand_data[1] = (unsigned int)GetPackedTime();
125
	rand_data[2] = (unsigned int)GetPackedDate();
126
	rand_data[3] = (unsigned int)0xA3901BD2 ^ GetPid();
127
}
128
 
129
unsigned int rand()
130
{
131
	rand_data[0] ^= _HashDword(rand_data[3] + 0x2835C013U);
132
	rand_data[1] += _HashDword(rand_data[0]);
133
	rand_data[2] -= _HashDword(rand_data[1]);
134
	rand_data[3] ^= _HashDword(rand_data[2]);
135
	return rand_data[3];
136
}
137
 
138
#define random(k)  (rand() % (k))
139
 
140
#else
141
 
142
#include 
143
 
144
#endif
145
 
146
/*void DebugPutNumber(int x)
147
{
148
	char word[12], *w = word, *s, c;
149
	int i;
150
	if (x < 0) {*(w++) = '-'; x = -x;}
151
	s = w;
152
	do
153
	{
154
		*(s++) = char('0' + (unsigned int)x % 10U);
155
		(unsigned int&)x /= 10U;
156
	} while(x);
157
	for (i = 0; w + i < s - 1 - i; i++)
158
	{
159
		c = w[i]; w[i] = s[-1 - i]; s[-1 - i] = c;
160
	}
161
	*s = 0;
162
	DebugPutString(word);
163
}*/
164
 
165
bool SetPictureSize(int w = -1, int h = -1)
166
{
167
	if (w > 32767) w = 32767;
168
	if (h > 32767) h = 32767;
169
	if (w > 0) xpar.win = (unsigned short)w;
170
	if (h > 0) ypar.win = (unsigned short)h;
171
	if (picture) {Free(picture); picture = 0;}
172
	if (w == 0 || h == 0 || xpar.win == 0 || ypar.win == 0) return true;
173
	picture = (unsigned char*)Alloc(3 * xpar.win * ypar.win);
174
	return picture != 0;
175
 
176
}
177
 
178
bool SetPoleSize(int w = -1, int h = -1)
179
{
180
	int s;
181
	if (w > 32767) w = 32767;
182
	if (h > 32767) h = 32767;
183
	if (w > 0) xpar.p = (unsigned short)w;
184
	if (h > 0) ypar.p = (unsigned short)h;
185
	if (xpar.p < 4) xpar.p = 4;
186
	if (ypar.p < 4) ypar.p = 4;
187
	if (life_data) {Free(life_data); life_data = 0;}
188
	if (w == 0 || h == 0) return true;
189
	s = GetDataSize(xpar.p, ypar.p);
190
	life_data = (unsigned char*)Alloc(2*s + DataMemAdd);
191
	if (!life_data) return false;
192
	MemSet(GetDataAddress(life_data), 0, s);
193
	return true;
194
}
195
 
196
int GetMenuHeight();
197
 
198
void GetPaintSize(int &w, int &h, int &xx, int &yy)
199
{
200
	int t = GetMenuHeight();
201
	w = xpar.win; h = ypar.win - t;
202
	xx = 0; yy = t;
203
}
204
 
205
double GetAxisRatio(const AxisParam &par, int s)
206
{
207
	int t = par.p - s;
208
	if (s <= 0 || t <= 0) return 0;
209
	return double(t) / 2;
210
}
211
 
212
void GetAxisShift(const AxisParam &par, int &s, int &k, int &kk)
213
{
214
	int t = par.p - s;
215
	if (t < 0) {kk += (-t) / 2; t = 0; s = par.p;}
216
	if (s <= 0 || t <= 0) k = 0;
217
	else
218
	{
219
		double r = double(t) / 2;
220
		k = (int)Floor(r * (1 + par.shift));
221
		if (k < 0) k = 0;
222
		else if (k > t) k = t;
223
	}
224
}
225
 
226
void GetPaintOrigin(int &w, int &h, int &x, int &y, int &xx, int &yy)
227
{
228
	GetPaintSize(w, h, xx, yy);
229
	GetAxisShift(xpar, w, x, xx);
230
	GetAxisShift(ypar, h, y, yy);
231
}
232
 
233
void ApplyScroll(unsigned char *data1 = life_data, unsigned char *data0 = 0)
234
{
235
	if (!data0) data0 = data1;
236
	data0 = (unsigned char*)GetDataAddress(data0);
237
	data1 = (unsigned char*)GetDataAddress(data1);
238
	const double min_ratio = 1e-2;
239
	double r;
240
	int w, h, xx, yy;
241
	GetPaintSize(w, h, xx, yy);
242
	xx = 0; yy = 0;
243
	r = GetAxisRatio(xpar, w);
244
	if (menu.button[MenuIHCircle].check)
245
	{
246
		xx = mpar.hit_x - mpar.last_x + (int)Floor(xpar.shift * r + 0.5);
247
		xx %= xpar.p - 2;
248
		if (xx < 0) xx += xpar.p - 2;
249
		xpar.shift = 0;
250
	}
251
	else if (r < min_ratio) xpar.shift = 0;
252
	else
253
	{
254
		xpar.shift -= double(mpar.last_x - mpar.hit_x) / r;
255
		if (xpar.shift < -1) xpar.shift = -1;
256
		else if (xpar.shift > 1) xpar.shift = 1;
257
	}
258
	r = GetAxisRatio(ypar, h);
259
	if (menu.button[MenuIVCircle].check)
260
	{
261
		yy = mpar.hit_y - mpar.last_y + (int)Floor(ypar.shift * r + 0.5);
262
		yy %= ypar.p - 2;
263
		if (yy < 0) yy += ypar.p - 2;
264
		ypar.shift = 0;
265
	}
266
	else if (r < min_ratio) ypar.shift = 0;
267
	else
268
	{
269
		ypar.shift -= double(mpar.last_y - mpar.hit_y) / r;
270
		if (ypar.shift < -1) ypar.shift = -1;
271
		else if (ypar.shift > 1) ypar.shift = 1;
272
	}
273
	if (xx == 0 && yy == 0)
274
	{
275
		if (data0 != data1) MemCopy(data0, data1, GetDataSize(xpar.p, ypar.p));
276
	}
277
	else
278
	{
279
		int i, j;
280
		i = GetDataSize(xpar.p, ypar.p);
281
		if (data0 == data1)
282
		{
283
			data1 += i;
284
			MemCopy(data1, data0, i);
285
		}
286
		MemSet(data0, 0, i);
287
		APosPixel pixel0(xpar.p, ypar.p, data0);
288
		APosPixel pixel1(xpar.p, ypar.p, data1);
289
		for (i = 0; i < xpar.p; i++)
290
		{
291
			pixel0.SetTo(i, 0);
292
			pixel1.SetTo(xx, yy);
293
			j = ypar.p - yy;
294
			for (;;)
295
			{
296
				if (pixel1.GetPixel()) pixel0.Set1Pixel();
297
				if (--j == 0) break;
298
				pixel0.AddY1(); pixel1.AddY1();
299
			}
300
			if (yy)
301
			{
302
				pixel0.AddY1();
303
				pixel1.SetTo(xx, 2);
304
				j = yy;
305
				for (;;)
306
				{
307
					if (pixel1.GetPixel()) pixel0.Set1Pixel();
308
					if (--j == 0) break;
309
					pixel0.AddY1(); pixel1.AddY1();
310
				}
311
			}
312
			xx++;
313
			if (xx >= xpar.p) xx = 2;
314
		}
315
	}
316
}
317
 
318
void DrawLine(int x0, int y0, int x1, int y1, bool c, unsigned char *data0 = life_data)
319
{
320
	int i;
321
	if (y0 == y1)
322
	{
323
		if (x0 > x1) {i = x0; x0 = x1; x1 = i;}
324
		if (x1 < 0 || x0 >= xpar.p || y1 < 0 || y0 >= ypar.p) return;
325
		if (x0 < 0) x0 = 0;
326
		if (x1 >= xpar.p) x1 = xpar.p - 1;
327
		APosPixel pixel(xpar.p, ypar.p, data0, x0, y0);
328
		for (i = x1 - x0; i >= 0; pixel.AddX1(), i--) pixel.SetPixel(c);
329
	}
330
	else if (x0 == x1)
331
	{
332
		if (y0 > y1) {i = y0; y0 = y1; y1 = i;}
333
		if (x1 < 0 || x0 >= xpar.p || y1 < 0 || y0 >= ypar.p) return;
334
		if (y0 < 0) y0 = 0;
335
		if (y1 >= ypar.p) y1 = ypar.p - 1;
336
		APosPixel pixel(xpar.p, ypar.p, data0, x0, y0);
337
		for (i = y1 - y0; i >= 0; pixel.AddY1(), i--) pixel.SetPixel(c);
338
	}
339
	else
340
	{
341
		long dx = x1 - x0, dy = y1 - y0;
342
		int i;
343
		if (abs(dx) >= abs(dy))
344
		{
345
			if (dx < 0)
346
			{
347
				i = x0; x0 = x1; x1 = i; dx = -dx;
348
				y0 = y1; dy = -dy;
349
			}
350
			long vy = 0, b_x = dx / 2;
351
			APosPixel pixel(xpar.p, ypar.p, data0, x0, y0);
352
			for (i = x0;; i++, pixel.AddX1())
353
			{
354
				pixel.SetPixel(c);
355
				if (i >= x1) break;
356
				vy += dy;
357
				if (vy > b_x)
358
				{
359
					vy -= dx;
360
					pixel.AddY1();
361
				}
362
				else if (vy < -b_x)
363
				{
364
					vy += dx;
365
					pixel.SubY1();
366
				}
367
			}
368
		}
369
		else
370
		{
371
			if (dy < 0)
372
			{
373
				i = y0; y0 = y1; y1 = i; dy = -dy;
374
				x0 = x1; dx = -dx;
375
			}
376
			long vx = 0, b_y = dy / 2;
377
			APosPixel pixel(xpar.p, ypar.p, data0, x0, y0);
378
			for (i = y0;; i++, pixel.AddY1())
379
			{
380
				pixel.SetPixel(c);
381
				if (i >= y1) break;
382
				vx += dx;
383
				if (vx > b_y)
384
				{
385
					vx -= dy;
386
					pixel.AddX1();
387
				}
388
				else if (vx < -b_y)
389
				{
390
					vx += dy;
391
					pixel.SubX1();
392
				}
393
			}
394
		}
395
	}
396
}
397
 
398
void FillCircle(int x0, int y0, int r, bool c, unsigned char *data0 = life_data)
399
{
400
	int x = 0, y = r, v = 0;
401
	while (x <= y)
402
	{
403
		DrawLine(x0 - x, y0 + y, x0 + x, y0 + y, c, data0);
404
		if (y) DrawLine(x0 - x, y0 - y, x0 + x, y0 - y, c, data0);
405
		if (x < y)
406
		{
407
			DrawLine(x0 - y, y0 + x, x0 + y, y0 + x, c, data0);
408
			DrawLine(x0 - y, y0 - x, x0 + y, y0 - x, c, data0);
409
		}
410
		v += 2 * (x++) + 1;
411
		if (v >= y) v -= 2 * (y--) - 1;
412
	}
413
}
414
 
415
void RandomDraw(unsigned char *data0 = life_data)
416
{
417
	if (!data0 || random(300) >= 1) return;
418
	int d = xpar.p;
419
	if (d > ypar.p) d = ypar.p;
420
	data0 = (unsigned char*)GetDataAddress(data0);
421
	d = random((d * 3) / 4);
422
	int x = random(xpar.p - d), y = random(ypar.p - d);
423
	if (random(10) < 1)
424
	{
425
		int NBusy, NTest = 4096;
426
		NBusy = 5 * xpar.p * ypar.p;
427
		if (NTest > NBusy) NTest = NBusy;
428
		NBusy = 0;
429
		for (int k = 0; k < NTest; k++)
430
		{
431
			if (GetDataBit(GetDataWidth(xpar.p), GetDataHeight(ypar.p), data0, random(xpar.p), random(ypar.p))) NBusy++;
432
		}
433
		if (NBusy * 100 < NTest)
434
		{
435
			if (random(3) == 0)
436
			{
437
				DrawLine(x, y, x + d, y + d, true, data0);
438
				DrawLine(x, y + d, x + d, y, true, data0);
439
			}
440
			else
441
			{
442
				DrawLine(x + d/2, y, x + d/2, y + d, true, data0);
443
				DrawLine(x, y + d/2, x + d, y + d/2, true, data0);
444
			}
445
			return;
446
		}
447
	}
448
	if (2*d < xpar.p && 2*d < ypar.p && random(10) < 3)
449
	{
450
		FillCircle(x + d/2, y + d/2, d/2, false, data0);
451
	}
452
	else if (random(2)) DrawLine(x, y, x + d, y + d, true, data0);
453
	else DrawLine(x, y + d, x + d, y, true, data0);
454
}
455
 
456
void LineInScreen(int ax, int ay, int bx, int by, bool c, unsigned char *data0 = life_data)
457
{
458
	int mul = 1, sbeg, send, t0, t1;
459
	if (ax != bx) mul *= abs(ax - bx);
460
	if (ay != by) mul *= abs(ay - by);
461
	sbeg = 0; send = mul;
462
	if (ax != bx)
463
	{
464
		t0 = ax * (mul / (ax - bx));
465
		t1 = (ax - xpar.p + 1) * (mul / (ax - bx));
466
		if (t0 < t1)
467
		{
468
			if (sbeg < t0) sbeg = t0;
469
			if (send > t1) send = t1;
470
		}
471
		else
472
		{
473
			if (sbeg < t1) sbeg = t1;
474
			if (send > t0) send = t0;
475
		}
476
	}
477
	else if (ax < 0 || ax >= xpar.p) return;
478
	if (ay != by)
479
	{
480
		t0 = ay * (mul / (ay - by));
481
		t1 = (ay - ypar.p + 1) * (mul / (ay - by));
482
		if (t0 < t1)
483
		{
484
			if (sbeg < t0) sbeg = t0;
485
			if (send > t1) send = t1;
486
		}
487
		else
488
		{
489
			if (sbeg < t1) sbeg = t1;
490
			if (send > t0) send = t0;
491
		}
492
	}
493
	else if (ay < 0 || ay > ypar.p) return;
494
	if (send < sbeg) return;
495
	DrawLine(ax + (bx - ax) * sbeg / mul, ay + (by - ay) * sbeg / mul,
496
			ax + (bx - ax) * send / mul, ay + (by - ay) * send / mul, c, data0);
497
}
498
 
499
int GetRadius(int ax, int ay, int bx, int by)
500
{
501
	int s, t0, t1, t, tt;
502
	bx -= ax; by -= ay;
503
	s = bx*bx + by*by;
504
	t0 = 0; t1 = s;
505
	while (t0 + 1 < t1)
506
	{
507
		t = (t0 + t1) / 2;
508
		tt = t*t;
509
		if (tt / t == t && s > tt + t) t0 = t; else t1 = t;
510
	}
511
	return t1;
512
}
513
 
514
int ReadNumberFromString(const unsigned char *&str)
515
{
516
	int x = 0, s = 1;
517
	while (*str == ' ' || *str == '\t' || *str == '\r') str++;
518
	if (*str == '-') {s = -1; str++;}
519
	else if (*str == '+') str++;
520
	while (*str >= '0' && *str <= '9')
521
	{
522
		x = 10*x + (*str - '0');
523
		str++;
524
	}
525
	return x*s;
526
}
527
 
528
const unsigned char *StringPrefSpace(const unsigned char *pict, int size, const unsigned char *pref)
529
{
530
	const unsigned char *pict_end = pict + size;
531
	for (;;)
532
	{
533
		if (!*pref) return pict;
534
		else if (*pref == ' ')
535
		{
536
			if (pict >= pict_end || !(*pict == ' ' || *pict == '\t' || *pict == '\r')) return 0;
537
			while (pict < pict_end && (*pict == ' ' || *pict == '\t' || *pict == '\r')) pict++;
538
			pref++;
539
		}
540
		else if (*pref == '\n')
541
		{
542
			while (pict < pict_end && (*pict == ' ' || *pict == '\t' || *pict == '\r')) pict++;
543
			if (pict >= pict_end || *pict != '\n') return 0;
544
			pict++; pref++;
545
		}
546
		else if (pict >= pict_end || *pict != *pref) return 0;
547
		else {pict++; pref++;}
548
	}
549
}
550
 
551
int LifeGetPictureType(const unsigned char *&pict, int size)
552
{
553
	const unsigned char *p;
554
	p = StringPrefSpace(pict, size, (const unsigned char*)"#LifeBin 2.0\n");
555
	if (p && p + 4 <= pict + size) {pict = p; return 1;}
556
	p = StringPrefSpace(pict, size, (const unsigned char*)"#Life 1.05\n");
557
	if (p) {pict = p; return 2;}
558
	if (size >= 54 && pict[0] == 'B' && pict[1] == 'M' && *(int*)(pict+6) == 0 &&
559
		*(int*)(pict+14) == 0x28 && *(short*)(pict+26) == 1 && *(int*)(pict+30) == 0 &&
560
		*(short*)(pict+28) > 0 && *(short*)(pict+28) <= 32 &&
561
		*(int*)(pict+18) >= 0 && *(int*)(pict+22) >= 0 &&
562
		*(int*)(pict+10) >= 54 && *(int*)(pict+10) <= *(int*)(pict+2) &&
563
		*(int*)(pict+2) <= size && *(int*)(pict+34) >= 0 &&
564
		*(int*)(pict+34) <= *(int*)(pict+2) - *(int*)(pict+10) &&
565
		*(int*)(pict+46) <= 256 && *(int*)(pict+50) <= *(int*)(pict+46) &&
566
		(*(short*)(pict+28) >= 8 || *(int*)(pict+46) <= (1 << *(short*)(pict+28))))
567
	{
568
		if (*(int*)(pict+18) == 0 || *(int*)(pict+22) == 0) return 3;
569
		int s = *(int*)(pict+34);
570
		if (s == 0)
571
		{
572
			s = ((*(int*)(pict+18) * *(short*)(pict+28) - 1) / 32 + 1) * *(int*)(pict+22) * 4;
573
		}
574
		if (s > 0 && s <= *(int*)(pict+2) - *(int*)(pict+10))
575
		{
576
			s /= *(int*)(pict+22);
577
			if (s < (1 << 28) && (s * 8) / *(short*)(pict+28) >= *(int*)(pict+18)) return 3;
578
		}
579
	}
580
	return 0;
581
}
582
 
583
void LifeGetPictureSize(int &w, int &h, const unsigned char *pict, int size)
584
{
585
	const unsigned char *pict_end = pict + size;
586
	int type = LifeGetPictureType(pict, size);
587
	w = 0; h = 0;
588
	if (type == 1)
589
	{
590
		w = (int)pict[0] + ((int)pict[1] << 8);
591
		h = (int)pict[2] + ((int)pict[3] << 8);
592
	}
593
	else if (type == 2)
594
	{
595
		int x = 0, y = 0, xb = x;
596
		int x0 = 0, y0 = 0, x1 = -1, y1 = -1;
597
		while (pict < pict_end && *pict)
598
		{
599
			while (pict < pict_end && *pict == '\n') pict++;
600
			if (pict < pict_end && *pict == '#')
601
			{
602
				pict++;
603
				if (pict < pict_end && (*pict == 'p' || *pict == 'P'))
604
				{
605
					pict++;
606
					x = ReadNumberFromString(pict);
607
					y = ReadNumberFromString(pict);
608
					xb = x;
609
				}
610
				while (pict < pict_end && *pict)
611
				{
612
					if (*pict == '\n') {pict++; break;}
613
					pict++;
614
				}
615
				continue;
616
			}
617
			for (; pict < pict_end && *pict; pict++)
618
			{
619
				if (*pict == '\n')
620
				{
621
					x = xb; y++;
622
					if (pict + 1 < pict_end && pict[1] == '#') break;
623
					continue;
624
				}
625
				else if (*pict == '\r') continue;
626
				if (*pict == '*')
627
				{
628
					if (x0 > x) x0 = x;
629
					if (x1 < x) x1 = x;
630
					if (y0 > y) y0 = y;
631
					if (y1 < y) y1 = y;
632
				}
633
				x++;
634
			}
635
		}
636
		x0 = -2*x0; x1 = 2*x1 + 1;
637
		y0 = -2*y0; y1 = 2*y1 + 1;
638
		w = (x0 < x1) ? x1 : x0;
639
		h = (y0 < y1) ? y1 : y0;
640
	}
641
	else if (type == 3)
642
	{
643
		w = *(int*)(pict+18);
644
		h = *(int*)(pict+22);
645
		if (w == 0) h = 0;
646
		else if (h == 0) w = 0;
647
	}
648
}
649
 
650
void LifePutPicture(int x0, int y0, const unsigned char *pict, int size, unsigned char *data0 = life_data)
651
{
652
	const unsigned char *pict_end = pict + size;
653
	int type = LifeGetPictureType(pict, size);
654
	if (type == 1)
655
	{
656
		int w = (int)pict[0] + ((int)pict[1] << 8);
657
		int h = (int)pict[2] + ((int)pict[3] << 8);
658
		if (w && h)
659
		{
660
			int i, j, x, y;
661
			pict += 4;
662
			x0 -= w / 2; y0 -= h / 2;
663
			x = x0 + w; y = y0 - 1;
664
			APosPixel pixel(xpar.p, ypar.p, data0);
665
			while (pict < pict_end)
666
			{
667
				if (x >= x0 + w)
668
				{
669
					i = (x - x0) / w;
670
					x -= i * w; y += i;
671
					if (y >= y0 + h) break;
672
					j = 0;
673
					if (x >= 0 && x < xpar.p) j |= 1;
674
					if (y >= 0 && y < ypar.p) j |= 2;
675
					if (j == 3)	pixel.SetTo(x, y);
676
				}
677
				i = *(pict++);
678
				if (i == 0)
679
				{
680
					if (j == 3) pixel.Set1Pixel();
681
					i = 1;
682
				}
683
				x += i;
684
				if ((j & 2) && x < x0 + w)
685
				{
686
					if (x >= 0 && x < xpar.p)
687
					{
688
						if ((j & 1) && i < 5)
689
						{
690
							while (i--) pixel.AddX1();
691
						}
692
						else
693
						{
694
							j |= 1;
695
							pixel.SetTo(x, y);
696
						}
697
					}
698
					else j &= ~1;
699
				}
700
			}
701
		}
702
	}
703
	else if (type == 2)
704
	{
705
		int x = x0, y = y0, xb = x;
706
		while (pict < pict_end && *pict)
707
		{
708
			while (pict < pict_end && *pict == '\n') pict++;
709
			if (pict < pict_end && *pict == '#')
710
			{
711
				pict++;
712
				if (pict < pict_end && (*pict == 'p' || *pict == 'P'))
713
				{
714
					pict++;
715
					x = x0 + ReadNumberFromString(pict);
716
					y = y0 + ReadNumberFromString(pict);
717
					xb = x;
718
				}
719
				while (pict < pict_end && *pict)
720
				{
721
					if (*pict == '\n') {pict++; break;}
722
					pict++;
723
				}
724
				continue;
725
			}
726
			if (y >= ypar.p || x >= xpar.p)
727
			{
728
				for (; pict < pict_end && *pict; pict++) if (*pict == '\n')
729
				{
730
					y++;
731
					if (pict + 1 < pict_end && pict[1] == '#') break;
732
				}
733
				continue;
734
			}
735
			if (y < 0)
736
			{
737
				for (; pict < pict_end && *pict; pict++) if (*pict == '\n')
738
				{
739
					y++;
740
					if (y >= 0 || (pict + 1 < pict_end && pict[1] == '#')) break;
741
				}
742
				if (pict + 1 < pict_end && *pict == '\n' && pict[1] == '#') continue;
743
			}
744
			APosPixel pixel(xpar.p, ypar.p, data0);
745
			if (x >= 0) pixel.SetTo(x, y);
746
			for (; pict < pict_end && *pict; pict++)
747
			{
748
				if (*pict == '\n')
749
				{
750
					x = xb; y++;
751
					if (y >= ypar.p) break;
752
					if (x >= 0) pixel.SetTo(x, y);
753
					if (pict + 1 < pict_end && pict[1] == '#') break;
754
					continue;
755
				}
756
				else if (*pict == '\r') continue;
757
				if (*pict == '*') pixel.Set1Pixel();
758
				x++;
759
				if (x < 0) continue;
760
				if (x >= xpar.p)
761
				{
762
					while (pict < pict_end && *pict && *pict != '\n') pict++;
763
					if (pict < pict_end && *pict == '\n') pict--;
764
					continue;
765
				}
766
				if (x == 0) pixel.SetTo(0, y);
767
				else pixel.AddX1();
768
			}
769
		}
770
	}
771
	else if (type == 3)
772
	{
773
		int w = *(int*)(pict+18), h = *(int*)(pict+22);
774
		if (w && h)
775
		{
776
			int n, i, j;
777
			unsigned char ch;
778
			const unsigned char *p = pict + *(int*)(pict+10);
779
			short bp = *(short*)(pict+28);
780
			int s = *(int*)(pict+34);
781
			x0 -= w / 2; y0 -= h / 2;
782
			if (x0 < xpar.p && y0 < ypar.p && x0 + w > 0 && y0 + h > 0)
783
			{
784
				if (s) s /= *(int*)(pict+22);
785
				else s = ((*(int*)(pict+18) * *(short*)(pict+28) - 1) / 32 + 1) * 4;
786
				n = (*(int*)(pict+10) - 54) / 4;
787
				APosPixel pixel(xpar.p, ypar.p, data0);
788
				if (y0 + h <= ypar.p) i = h - 1;
789
				else
790
				{
791
					i = ypar.p - y0 - 1;
792
					p += (ypar.p - y0) * s;
793
				}
794
				for (; i >= 0; i--)
795
				{
796
					int tj = 0, tl = 0;
797
					if (y0 + i < 0) break;
798
					if (x0 > 0) pixel.SetTo(x0, y0 + i);
799
					for (j = 0; j < 8*s; j += 8)
800
					{
801
						if (tj >= w || x0 + tj >= xpar.p) {p += (s - j/8); break;}
802
						ch = *(p++);
803
						while (tj < w && x0 + tj < xpar.p && j + 8 >= (tj+1) * bp)
804
						{
805
							union
806
							{
807
								long za;
808
								unsigned char z[4];
809
							};
810
 
811
							tl |= (unsigned long)(ch) >> ((int)j + 8 - (tj+1) * bp);
812
							if (n)
813
							{
814
								if (tl >= n) za = 0;
815
								else
816
								{
817
									const unsigned char *zp = pict + 54 + 4*tl;
818
									z[0] = zp[3];
819
									z[1] = zp[2];
820
									z[2] = zp[1];
821
									z[3] = zp[0];
822
								}
823
							}
824
							else if (bp == 8)
825
							{
826
								z[0] = 0;
827
								z[1] = z[2] = z[3] = (char)tl;
828
							}
829
							else if (bp == 32) za = tl;
830
							else za = tl << (32 - bp);
831
 
832
							if (x0 + tj >= 0)
833
							{
834
								if (x0 + tj == 0) pixel.SetTo(0, y0 + i);
835
								else pixel.AddX1();
836
								if ((int)z[1] + (int)z[2] + (int)z[3] >= 384)
837
								{
838
									pixel.Set1Pixel();
839
								}
840
							}
841
 
842
							tl = 0;
843
							ch &= (unsigned char)((1 << ((int)j + 8 - (tj+1) * bp)) - 1);
844
							tj++;
845
						}
846
						tl |= (int)ch << ((tj+1) * bp - (j + 8));
847
					}
848
				}
849
			}
850
		}
851
	}
852
}
853
 
854
void ApplyHit(unsigned char *data1 = life_data, unsigned char *data0 = 0)
855
{
856
	if (!data0) data0 = data1;
857
	if (!data0) return;
858
	data0 = (unsigned char*)GetDataAddress(data0);
859
	data1 = (unsigned char*)GetDataAddress(data1);
860
	if (data0 != data1 && mpar.hit_type != MouseParam::HitScroll)
861
	{
862
		MemCopy(data0, data1, GetDataSize(xpar.p, ypar.p));
863
	}
864
	switch (mpar.hit_type)
865
	{
866
	case MouseParam::HitLine:
867
		LineInScreen(mpar.hit_x, mpar.hit_y, mpar.last_x, mpar.last_y, true, data0);
868
		break;
869
	case MouseParam::HitCircle:
870
		FillCircle(mpar.hit_x, mpar.hit_y,
871
				GetRadius(mpar.hit_x, mpar.hit_y, mpar.last_x, mpar.last_y), false, data0);
872
		break;
873
	case MouseParam::HitScroll:
874
		ApplyScroll(data1, data0);
875
		break;
876
	}
877
}
878
 
879
void MoveGenerateTime(unsigned int t)
880
{
881
	static const unsigned int COUNT_MAX = 1 << 24;
882
 
883
	if (generate.stop)
884
	{
885
		if (generate.count > COUNT_MAX) generate.count = COUNT_MAX;
886
	}
887
	else if (!generate.gps) generate.count = COUNT_MAX;
888
	else if (t > 100 || generate.count >= generate.gps)
889
	{
890
		generate.count = generate.gps;
891
	}
892
	else if (t)
893
	{
894
		generate.count += (generate.gps * t -
895
					(((generate.time + t) % 100U) * generate.gps) % 100 +
896
					((generate.time % 100U) * generate.gps) % 100) / 100;
897
		if (generate.count > generate.gps) generate.count = generate.gps;
898
	}
899
	generate.time += t;
900
	if (timegen[timegenpos].t > (~t)) timegen[timegenpos].t = -1;
901
	else timegen[timegenpos].t += t;
902
}
903
 
904
void ResetGenerate()
905
{
906
	generate.time = Clock();
907
	generate.paint_time = generate.time - 100;
908
	generate.count = 0;
909
	if (generate.stop)
910
	{
911
		generate.stop = false;
912
		menu.button[MenuIGenerate].check = false;
913
	}
914
}
915
 
916
void InitGenerate()
917
{
918
	int i;
919
	for (i = 0; i < TimeGenLength; i++)
920
	{
921
		timegen[timegenpos].t = -1;
922
		timegen[timegenpos].g = 0;
923
	}
924
	ResetGenerate();
925
}
926
 
927
bool AddGenerateCount(int c)
928
{
929
	if (c < 0) return false;
930
	if (!menu.button[MenuIGenerate].check)
931
	{
932
		ResetGenerate();
933
		menu.button[MenuIGenerate].check = true;
934
		generate.paint |= PaintWMenuBorder | PaintWSpeed;
935
		generate.stop = true;
936
		generate.count += c;
937
	}
938
	else if (generate.stop) generate.count += c;
939
	else return false;
940
	return true;
941
}
942
 
943
void InitMenuButton()
944
{
945
	int i;
946
	const unsigned char *p = menu_picture, *p_end = menu_picture + sizeof(menu_picture);
947
	const unsigned int separator = 5;
948
	for (i = 0; i < MenuParam::NButton; i++)
949
	{
950
		menu.button[i].left = 0;
951
		menu.button[i].size = MenuParam::Size - 2;
952
		menu.button[i].border = 2;
953
		menu.button[i].check = false;
954
		menu.button[i].bitmap = p;
955
		if (p && !p[0])
956
		{
957
			menu.button[i].bitmap = 0;
958
			if (p[1]) p = 0;
959
		}
960
		if (p)
961
		{
962
			p += 2 + 3 * (int)p[0] * (int)p[1];
963
			if (p > p_end) menu.button[i].bitmap = 0;
964
			if (p >= p_end) p = 0;
965
		}
966
	}
967
	p = digits_picture; p_end = digits_picture + sizeof(digits_picture);
968
	for (i = 0; i < MenuDig; i++)
969
	{
970
		menu.digit[i] = p;
971
		if (p && !p[0])
972
		{
973
			menu.digit[i] = 0;
974
			if (p[1]) p = 0;
975
		}
976
		if (p)
977
		{
978
			p += 2 + ((int)p[0] * (int)p[1] + 7) / 8;
979
			if (p > p_end) menu.digit[i] = 0;
980
			if (p >= p_end) p = 0;
981
		}
982
	}
983
	menu.draw = false;
984
	menu.pressed = -1;
985
	menu.current = MenuILine;
986
	menu.edit = -1;
987
	menu.button[menu.current].check = true;
988
	menu.button[MenuIHide].size /= 2;
989
	menu.button[MenuIGenerate].left += separator;
990
	menu.button[MenuIGenerate].check = true;
991
	menu.button[MenuIRandom].check = true;
992
	menu.button[MenuILine].left += separator;
993
	menu.button[MenuIWinSize].left += separator;
994
	menu.button[MenuISize].size += 80;
995
	menu.button[MenuISpeed].left += separator;
996
	menu.button[MenuISpeed].size += 60;
997
	menu.button[0].left = 1;
998
	for (i = 1; i < MenuParam::NButton; i++)
999
	{
1000
		menu.button[i].left += menu.button[i-1].left + menu.button[i-1].size;
1001
	}
1002
}
1003
 
1004
int GetMenuYPos()
1005
{
1006
	return 0;
1007
}
1008
 
1009
int GetMenuHeight()
1010
{
1011
	if (!menu.draw) return 0;
1012
	return (ypar.win <= MenuParam::Size) ? 0 : MenuParam::Size;
1013
}
1014
 
1015
int GetMenuNumber(int k, int i)
1016
{
1017
	if (k == menu.edit) return menu.edit_num[i];
1018
	switch (k)
1019
	{
1020
	case MenuISize:
1021
		return i ? ypar.p : xpar.p;
1022
	case MenuISpeed:
1023
		return menu.button[MenuIGenerate].check ? (int)Floor(generate.speed + 0.5) : 0;
1024
	default:
1025
		return 0;
1026
	}
1027
}
1028
 
1029
void WinDrawRect(int x, int y, int w, int h, const unsigned char *const *color)
1030
{
1031
	unsigned char *p = picture + 3 * (y * xpar.win + x);
1032
	int j;
1033
	w--; h--;
1034
	for (j = w; j > 0; j--)
1035
	{
1036
		p[0] = color[0][0]; p[1] = color[0][1]; p[2] = color[0][2];
1037
		p += 3;
1038
	}
1039
	for (j = h; j > 0; j--)
1040
	{
1041
		p[0] = color[1][0]; p[1] = color[1][1]; p[2] = color[1][2];
1042
		p += 3 * xpar.win;
1043
	}
1044
	for (j = w; j > 0; j--)
1045
	{
1046
		p[0] = color[2][0]; p[1] = color[2][1]; p[2] = color[2][2];
1047
		p -= 3;
1048
	}
1049
	for (j = h; j > 0; j--)
1050
	{
1051
		p[0] = color[3][0]; p[1] = color[3][1]; p[2] = color[3][2];
1052
		p -= 3 * xpar.win;
1053
	}
1054
}
1055
 
1056
void WinFillRect(int x, int y, int w, int h, const unsigned char *color)
1057
{
1058
	if (x >= xpar.win || y >= ypar.win || w <= 0 || h <= 0) return;
1059
	if (w > xpar.win - x) w = xpar.win - x;
1060
	if (h > ypar.win - y) h = ypar.win - y;
1061
	unsigned char *p, *pp = picture + 3 * (y * xpar.win + x);
1062
	int i, j;
1063
	for (i = h; i > 0; i--)
1064
	{
1065
		p = pp;
1066
		for (j = w; j > 0; j--)
1067
		{
1068
			*(p++) = color[0]; *(p++) = color[1]; *(p++) = color[2];
1069
		}
1070
		pp += 3 * xpar.win;
1071
	}
1072
}
1073
 
1074
void WinBitmapRect(int x, int y, const unsigned char *bmp)
1075
{
1076
	if (!bmp || !bmp[0] || !bmp[1]) return;
1077
	int w = bmp[0], h = bmp[1], strl = 3 * (int)bmp[0];
1078
	bmp += 2;
1079
	x -= w/2; y -= h/2;
1080
	if (x >= xpar.win || y >= ypar.win) return;
1081
	if (w > xpar.win - x) w = xpar.win - x;
1082
	if (h > ypar.win - y) h = ypar.win - y;
1083
	unsigned char *p, *pp = picture + 3 * (y * xpar.win + x);
1084
	const unsigned char *b;
1085
	int i, j;
1086
	for (i = h; i > 0; i--)
1087
	{
1088
		p = pp; b = bmp;
1089
		for (j = w; j > 0; j--)
1090
		{
1091
			*(p++) = *(b++); *(p++) = *(b++); *(p++) = *(b++);
1092
		}
1093
		pp += 3 * xpar.win; bmp += strl;
1094
	}
1095
}
1096
 
1097
void WinBitSetRect(int x, int y, const unsigned char *set, const unsigned char *color)
1098
{
1099
	if (!set || !set[0] || !set[1]) return;
1100
	int w = set[0], h = set[1], strr = (int)set[0];
1101
	set += 2;
1102
	x -= w/2; y -= h/2;
1103
	if (x >= xpar.win || y >= ypar.win) return;
1104
	if (w > xpar.win - x) w = xpar.win - x;
1105
	if (h > ypar.win - y) h = ypar.win - y;
1106
	strr -= w;
1107
	unsigned char *p, *pp = picture + 3 * (y * xpar.win + x);
1108
	int i, j, m = 1;
1109
	for (i = h; i > 0; i--)
1110
	{
1111
		p = pp;
1112
		for (j = w; j > 0; j--)
1113
		{
1114
			if (*set & m) {p[0] = color[0]; p[1] = color[1]; p[2] = color[2];}
1115
			p += 3;
1116
			m <<= 1;
1117
			if (!(m & 255)) {m = 1; set++;}
1118
		}
1119
		pp += 3 * xpar.win;
1120
		m <<= strr % 8; set += strr / 8;
1121
		if (!(m & 255)) {m >>= 8; set++;}
1122
	}
1123
}
1124
 
1125
void WinNumberRect(int x, int y, unsigned int n, const unsigned char *color)
1126
{
1127
	int w, m, i;
1128
	w = 0; m = n;
1129
	do
1130
	{
1131
		i = m % MenuDig; m /= MenuDig;
1132
		if (menu.digit[i]) w += 2 + menu.digit[i][0];
1133
	} while(m);
1134
	if (w <= 2) return;
1135
	x += w - (w-2) / 2;
1136
	m = n;
1137
	do
1138
	{
1139
		i = m % MenuDig; m /= MenuDig;
1140
		if (menu.digit[i])
1141
		{
1142
			x -= 2 + menu.digit[i][0];
1143
			WinBitSetRect(x + menu.digit[i][0] / 2, y, menu.digit[i], color);
1144
		}
1145
	} while(m);
1146
}
1147
 
1148
void WinNumberEditRect(int x, int y, int w, int h, unsigned int n,
1149
			const unsigned char *color, const unsigned char *bg_color)
1150
{
1151
	if (bg_color) WinFillRect(x, y, w, h, bg_color);
1152
	WinNumberRect(x + w/2, y + h/2, n, color);
1153
}
1154
 
1155
void MenuPaint(int what)
1156
{
1157
	static const unsigned char color_light0[3] = {255, 255, 255};
1158
	static const unsigned char color_light[3] = {208, 208, 208};
1159
	static const unsigned char color_face[3] = {192, 192, 192};
1160
	static const unsigned char color_shadow[3] = {128, 128, 128};
1161
	static const unsigned char color_shadow0[3] = {64, 64, 64};
1162
	static const unsigned char color_black[3] = {0, 0, 0};
1163
	static const unsigned char (&color_white)[3] = color_light0;
1164
 
1165
	if (GetMenuHeight() < MenuParam::Size) return;
1166
	const unsigned char *color[4];
1167
	int menuy = GetMenuYPos(), i, k, x, xx, y, yy;
1168
	if ((what & PaintWSpeed) && !(what & (PaintWMenu & ~PaintWMenuBorder)) &&
1169
				menu.button[MenuISpeed].Right() < xpar.win)
1170
	{
1171
		k = MenuISpeed;
1172
		i = menu.button[k].border + 1;
1173
		xx = menu.button[k].Left() + i;
1174
		yy = menuy + 1 + i;
1175
		x = menu.button[k].size - 2*i;
1176
		y = MenuParam::Size - 2 - 2*i;
1177
		i = 0;
1178
		if (menu.button[k].bitmap) i += menu.button[k].bitmap[0] + 2;
1179
		WinNumberEditRect(xx + i, yy, x - i, y, GetMenuNumber(k, 0), color_black,
1180
					(menu.edit == k && menu.edit_index == 0) ? color_white : color_face);
1181
	}
1182
	if (!(what & PaintWMenu)) return;
1183
	if (what & (PaintWMenu & ~PaintWMenuBorder))
1184
	{
1185
		x = menu.button[MenuParam::NButton - 1].Right();
1186
		WinFillRect(0, menuy, x, 1, color_face);
1187
		WinFillRect(0, menuy + MenuParam::Size - 1, x, 1, color_face);
1188
		WinFillRect(x, menuy, xpar.win - x, MenuParam::Size, color_face);
1189
	}
1190
	for (k = 0; k < MenuParam::NButton; k++)
1191
	{
1192
		xx = menu.button[k].Left();
1193
		yy = menuy + 1;
1194
		x = menu.button[k].size;
1195
		y = MenuParam::Size - 2;
1196
		if (xx + x >= xpar.win)
1197
		{
1198
			if (what & (PaintWMenu & ~PaintWMenuBorder))
1199
			{
1200
				i = (k >= 1) ? menu.button[k-1].Right() : 0;
1201
				WinFillRect(i, yy, xpar.win - i, y, color_face);
1202
			}
1203
			break;
1204
		}
1205
		if (what & (PaintWMenu & ~PaintWMenuBorder))
1206
		{
1207
			i = (k >= 1) ? menu.button[k-1].Right() : 0;
1208
			WinFillRect(i, yy, xx - i, y, color_face);
1209
		}
1210
		for (i = 0; i < menu.button[k].border; i++)
1211
		{
1212
			if (i <= 1)
1213
			{
1214
				if (menu.button[k].check)
1215
				{
1216
					color[0] = color[3] = i ? color_shadow : color_shadow0;
1217
					color[1] = color[2] = i ? color_light : color_light0;
1218
				}
1219
				else
1220
				{
1221
					color[0] = color[3] = i ? color_light : color_light0;
1222
					color[1] = color[2] = i ? color_shadow : color_shadow0;
1223
				}
1224
			}
1225
			WinDrawRect(xx, yy, x, y, color);
1226
			xx++; yy++; x -= 2; y -= 2;
1227
		}
1228
		if (what & (PaintWMenu & ~PaintWMenuBorder))
1229
		{
1230
			WinFillRect(xx, yy, x, y, color_face);
1231
			if (menu.button[k].bitmap)
1232
			{
1233
				i = (k == MenuISpeed) ? (1 + menu.button[k].bitmap[0] / 2) : (x / 2);
1234
				WinBitmapRect(xx + i, yy + y/2, menu.button[k].bitmap);
1235
			}
1236
			if (k == MenuISize)
1237
			{
1238
				xx++; yy++; x -= 2; y -= 2;
1239
				i = x - 4;
1240
				if (menu.button[k].bitmap) i -= menu.button[k].bitmap[0];
1241
				i /= 2;
1242
				WinNumberEditRect(xx, yy, i, y, GetMenuNumber(k, 0), color_black,
1243
							(menu.edit == k && menu.edit_index == 0) ? color_white : 0);
1244
				WinNumberEditRect(xx + x - i, yy, i, y, GetMenuNumber(k, 1), color_black,
1245
							(menu.edit == k && menu.edit_index == 1) ? color_white : 0);
1246
			}
1247
			else if (k == MenuISpeed)
1248
			{
1249
				xx++; yy++; x -= 2; y -= 2;
1250
				i = 0;
1251
				if (menu.button[k].bitmap) i += menu.button[k].bitmap[0] + 2;
1252
				WinNumberEditRect(xx + i, yy, x - i, y, GetMenuNumber(k, 0), color_black,
1253
							(menu.edit == k && menu.edit_index == 0) ? color_white : 0);
1254
			}
1255
		}
1256
	}
1257
}
1258
 
1259
void Paint(int what, TThreadData th);
1260
 
1261
void SetMenuDraw(bool draw, TThreadData th)
1262
{
1263
	if (draw == menu.draw) return;
1264
	if (menu.pressed >= 0) menu.button[menu.pressed].check = false;
1265
	menu.pressed = -1;
1266
	menu.draw = draw;
1267
	Paint(PaintWAll | PaintWFast, th);
1268
}
1269
 
1270
void SetMenuPressed(int k, TThreadData th)
1271
{
1272
	if (menu.pressed == k) return;
1273
	if (menu.pressed >= 0) menu.button[menu.pressed].check = false;
1274
	if (k >= 0) menu.button[k].check = true;
1275
	menu.pressed = k;
1276
	Paint(PaintWMenuBorder | PaintWFast, th);
1277
}
1278
 
1279
void SetMenuCurrent(int k, TThreadData th)
1280
{
1281
	if (menu.current == k) return;
1282
	if (menu.current >= 0) menu.button[menu.current].check = false;
1283
	if (k >= 0) menu.button[k].check = true;
1284
	menu.current = k;
1285
	Paint(PaintWMenuBorder | PaintWFast, th);
1286
}
1287
 
1288
void SetMenuEdit(int k, int i, TThreadData th)
1289
{
1290
	if (menu.edit != k)
1291
	{
1292
		if (menu.edit >= 0) menu.button[menu.edit].check = false;
1293
		if (k >= 0) menu.button[k].check = true;
1294
		if (k == MenuISize) {menu.edit_num[0] = xpar.p; menu.edit_num[1] = ypar.p;}
1295
		else if (k == MenuISpeed) menu.edit_num[0] = generate.gps;
1296
	}
1297
	else if (menu.edit_index == i) return;
1298
	if (k == MenuISize) menu.edit_num_max = 32767;
1299
	else if (k == MenuISpeed) menu.edit_num_max = 9999999;
1300
	menu.edit = k; menu.edit_index = i;
1301
	Paint(PaintWMenu | PaintWFast, th);
1302
}
1303
 
1304
void ApplyMenuEdit(TThreadData th)
1305
{
1306
	if (menu.edit < 0) return;
1307
	if (menu.edit == MenuISize)
1308
	{
1309
		int w = menu.edit_num[0], h = menu.edit_num[1];
1310
		ResetGenerate();
1311
		if (xpar.p != w || ypar.p != h)
1312
		{
1313
			if (w <= 0) w = 1;
1314
			if (h <= 0) h = 1;
1315
			SetPoleSize(w, h);
1316
			generate.paint |= PaintWPole | PaintWMenu | PaintWFast;
1317
		}
1318
	}
1319
	else if (menu.edit == MenuISpeed)
1320
	{
1321
		generate.gps = menu.edit_num[0];
1322
	}
1323
	SetMenuEdit(-1, -1, th);
1324
}
1325
 
1326
int GetMenuEditIndex(int k, int x)
1327
{
1328
	if (k == MenuISize) return x >= menu.button[k].left + menu.button[k].size / 2;
1329
	else return 0;
1330
}
1331
 
1332
void LifeScreenPutPicture(const unsigned char *pict, int size, TThreadData th)
1333
{
1334
	int w, h;
1335
	ResetGenerate();
1336
	LifeGetPictureSize(w, h, pict, size);
1337
	w += 10; h += 10;
1338
	if (!life_data || xpar.p < w || ypar.p < h)
1339
	{
1340
		if (xpar.p >= w) w = xpar.p;
1341
		if (ypar.p >= h) h = ypar.p;
1342
		SetPoleSize(w, h);
1343
		if (!life_data)
1344
		{
1345
			Paint(PaintWMenu | PaintWFast, th);
1346
			return;
1347
		}
1348
	}
1349
	MemSet(GetDataAddress(life_data), 0, GetDataSize(xpar.p, ypar.p));
1350
	LifePutPicture(xpar.p / 2, ypar.p / 2, pict, size, life_data);
1351
	menu.button[MenuIRandom].check = false;
1352
	xpar.shift = 0; ypar.shift = 0;
1353
	generate.paint |= PaintWPole | PaintWMenu | PaintWFast;
1354
//	SetMenuCurrent(MenuIScroll, th);
1355
	Paint(PaintWNull, th);
1356
}
1357
 
1358
void MenuOpenDialogEnd(TThreadData th)
1359
{
1360
	int state = OpenFileGetState(open_file_str);
1361
	if (state <= 0) return;
1362
	OpenFileSetState(open_file_str, 0);
1363
	if (state != 2) return;
1364
	char *name = OpenFileGetName(open_file_str);
1365
	if (!name) return;
1366
	TFileData file = FileOpen(name);
1367
	if (!file) return;
1368
	int k = FileGetLength(file);
1369
	unsigned char *pict = 0;
1370
	if (k > 0 && k < (1 << 24))
1371
	{
1372
		pict = (unsigned char*)Alloc(k+1);
1373
		if (pict)
1374
		{
1375
			if (FileRead(file, pict, k) == k) pict[k] = 0;
1376
			else {Free(pict); pict = 0;}
1377
		}
1378
	}
1379
	FileClose(file);
1380
	if (!pict) return;
1381
	LifeScreenPutPicture(pict, k, th);
1382
	Free(pict);
1383
}
1384
 
1385
void MenuWinSizeClick(TThreadData th)
1386
{
1387
	int w = xpar.win, h = ypar.win - GetMenuHeight();
1388
	ResetGenerate();
1389
	if (w > 0 && h > 0 && (xpar.p != w || ypar.p != h))
1390
	{
1391
		SetPoleSize(w, h);
1392
		Paint(PaintWPole | PaintWMenu | PaintWFast, th);
1393
	}
1394
}
1395
 
1396
void MenuGenerateClick(TThreadData th)
1397
{
1398
	generate.stop = false;
1399
	ResetGenerate();
1400
	menu.button[MenuIGenerate].check = !menu.button[MenuIGenerate].check;
1401
	Paint(PaintWMenuBorder | PaintWSpeed | PaintWFast, th);
1402
}
1403
 
1404
void MenuClearClick(TThreadData th)
1405
{
1406
	ResetGenerate();
1407
	if (life_data) MemSet(GetDataAddress(life_data), 0, GetDataSize(xpar.p, ypar.p));
1408
	Paint(PaintWPole | PaintWFast, th);
1409
}
1410
 
1411
void MenuAboutClick(TThreadData th)
1412
{
1413
	generate.stop = false;
1414
	menu.button[MenuIGenerate].check = true;
1415
	generate.paint |= PaintWSpeed;
1416
	LifeScreenPutPicture(about_picture, sizeof(about_picture), th);
1417
}
1418
 
1419
void MenuMouseClick(int x, int y, int m, TThreadData th)
1420
{
1421
	int k, i, j = GetMenuYPos();
1422
	if (menu.edit >= 0)
1423
	{
1424
		k = menu.edit;
1425
		j = GetMenuYPos();
1426
		if (GetMenuHeight() < MenuParam::Size || y < j + 1 || y >= j + MenuParam::Size - 1 ||
1427
					x < menu.button[k].Left() || x >= menu.button[k].Right())
1428
		{
1429
			if (m == 1) ApplyMenuEdit(th);
1430
			else SetMenuEdit(-1, -1, th);
1431
		}
1432
		else SetMenuEdit(k, GetMenuEditIndex(k, x), th);
1433
		return;
1434
	}
1435
	if (GetMenuHeight() < MenuParam::Size || y < j + 1 || y >= j + MenuParam::Size - 1)
1436
	{
1437
		if (m < 0) x = -1;
1438
		else return;
1439
	}
1440
	if (m < 0)
1441
	{
1442
		if (menu.pressed < 0) return;
1443
		k = menu.pressed;
1444
		if (x < menu.button[k].Left() || x >= menu.button[k].Right())
1445
		{
1446
			if (menu.button[k].check)
1447
			{
1448
				menu.button[k].check = false;
1449
				Paint(PaintWMenuBorder | PaintWFast, th);
1450
			}
1451
		}
1452
		else if (!menu.button[k].check)
1453
		{
1454
			menu.button[k].check = true;
1455
			Paint(PaintWMenuBorder | PaintWFast, th);
1456
		}
1457
		return;
1458
	}
1459
	if (m == 0)
1460
	{
1461
		if (menu.pressed < 0 || !menu.button[menu.pressed].check) return;
1462
		switch (menu.pressed)
1463
		{
1464
		case MenuIHide:
1465
			SetMenuDraw(false, th);
1466
			break;
1467
		case MenuIClear:
1468
			MenuClearClick(th);
1469
			break;
1470
		case MenuIOpen:
1471
			if (OpenFileGetState(open_file_str) < 0) break;
1472
			OpenFileDialog(open_file_str);
1473
			break;
1474
		case MenuIAbout:
1475
			MenuAboutClick(th);
1476
			break;
1477
		case MenuIExit:
1478
			CloseWindow(th);
1479
			break;
1480
		case MenuIWinSize:
1481
			MenuWinSizeClick(th);
1482
			break;
1483
		}
1484
		return;
1485
	}
1486
	k = -1; i = MenuParam::NButton;
1487
	while (k + 1 < i)
1488
	{
1489
		j = (k + i) / 2;
1490
		if (x < menu.button[j].Left()) i = j;
1491
		else k = j;
1492
	}
1493
	i = menu.button[k].Right();
1494
	if (k < 0 || x >= i || i >= xpar.win) return;
1495
	switch (k)
1496
	{
1497
	case MenuIHide:
1498
	case MenuIClear:
1499
	case MenuIOpen:
1500
	case MenuIAbout:
1501
	case MenuIExit:
1502
	case MenuIWinSize:
1503
		SetMenuPressed(k, th);
1504
		break;
1505
	case MenuIGenerate:
1506
		MenuGenerateClick(th);
1507
		break;
1508
	case MenuIRandom:
1509
	case MenuIVCircle:
1510
	case MenuIHCircle:
1511
		menu.button[k].check = !menu.button[k].check;
1512
		Paint(PaintWMenuBorder | PaintWFast, th);
1513
		break;
1514
	case MenuILine:
1515
	case MenuIScroll:
1516
		SetMenuCurrent(k, th);
1517
		break;
1518
	case MenuISize:
1519
	case MenuISpeed:
1520
		SetMenuEdit(k, GetMenuEditIndex(k, x), th);
1521
		break;
1522
	}
1523
}
1524
 
1525
void PoleMouseClick(int m, TThreadData th)
1526
{
1527
	if (m != 1 && m != 2) return;
1528
	mpar.hit_type = MouseParam::HitNull;
1529
	switch (menu.current)
1530
	{
1531
	case MenuILine:
1532
		if (menu.draw)
1533
		{
1534
			menu.button[MenuIRandom].check = false;
1535
			generate.paint |= PaintWMenuBorder | PaintWFast;
1536
			if (m == 1) mpar.hit_type = MouseParam::HitLine;
1537
			else mpar.hit_type = MouseParam::HitCircle;
1538
		}
1539
		break;
1540
	case MenuIScroll:
1541
		if (m == 1) mpar.hit_type = MouseParam::HitScroll;
1542
		break;
1543
	}
1544
	if (mpar.hit_type) Paint(PaintWPole | PaintWFast, th);
1545
	else if (!menu.draw) SetMenuDraw(true, th);
1546
}
1547
 
1548
void MenuEditPressKey(int ch, TThreadData th)
1549
{
1550
	if (menu.edit < 0) return;
1551
	int &num = menu.edit_num[menu.edit_index];
1552
	if (ch == 27) SetMenuEdit(-1, -1, th);
1553
	else if (ch == '\r') ApplyMenuEdit(th);
1554
	else if (ch == 8) {num /= 10; Paint(PaintWMenu | PaintWFast, th);}
1555
	else if (ch >= '0' && ch <= '9')
1556
	{
1557
		num = 10 * num + (ch - '0');
1558
		if (num >= menu.edit_num_max) num = menu.edit_num_max;
1559
		Paint(PaintWMenu | PaintWFast, th);
1560
	}
1561
	else if (menu.edit == MenuISize)
1562
	{
1563
		if (ch == '\t') SetMenuEdit(MenuISize, !menu.edit_index, th);
1564
		else if (ch == 'x' || ch == 'X') SetMenuEdit(MenuISize, 0, th);
1565
		else if (ch == 'y' || ch == 'Y') SetMenuEdit(MenuISize, 1, th);
1566
	}
1567
}
1568
 
1569
void CalculateSpeed()
1570
{
1571
	double t = 0, g = 0, dn, n = 0, st = 0, sg = 0, ss = 0, sp = 0;
1572
	int i = timegenpos;
1573
	do
1574
	{
1575
		if (t >= 500) break;
1576
		g += timegen[i].g;
1577
		dn = timegen[i].g;
1578
		n += dn * (500 - t);
1579
		st += dn * t;
1580
		sg += dn * g;
1581
		ss += dn * t * t;
1582
		sp += dn * g * t;
1583
		if (--i < 0) i = TimeGenLength;
1584
		t += timegen[i].t;
1585
	} while(i != timegenpos);
1586
	ss = n * ss - st * st;
1587
	sp = n * sp - sg * st;
1588
	if (st < 1e-4 || ss < 1e-4 * st * st) g = 0;
1589
	else g = sp / ss;
1590
	generate.speed = 100 * g;
1591
}
1592
 
1593
void Paint(int what, TThreadData th)
1594
{
1595
	what |= generate.paint;
1596
	if (!(what & PaintWAll) || !life_data || xpar.win <= 0 || ypar.win <= 0) return;
1597
 
1598
	const unsigned int FAST_PAINT_TIME = 2, WAIT_PAINT_TIME = 8;
1599
	unsigned int t = Clock() - generate.paint_time;
1600
	unsigned int wt = (what & PaintWFast) ? FAST_PAINT_TIME : WAIT_PAINT_TIME;
1601
	if (!(what & PaintWNow) && t >= (unsigned int)(-WAIT_PAINT_TIME))
1602
	{
1603
		if ((unsigned int)(-t) > wt) generate.paint_time += t + wt;
1604
		generate.paint = what;
1605
		return;
1606
	}
1607
	generate.paint_time += t + wt;
1608
	generate.paint = PaintWNull;
1609
 
1610
	if (!picture)
1611
	{
1612
		SetPictureSize();
1613
		if (!picture) return;
1614
	}
1615
	if (what & PaintWPole)
1616
	{
1617
		const unsigned char bgcolor[3] = {128, 128, 0};
1618
		int w, h, x, y, xx, yy, i, j;
1619
		int menu0 = GetMenuYPos(), menu1 = menu0 + GetMenuHeight();
1620
		unsigned char *p = picture;
1621
		unsigned char *data0 = (unsigned char*)GetDataAddress(life_data);
1622
		int size = GetDataSize(xpar.p, ypar.p);
1623
		if (xpar.win <= 0 || ypar.win <= 0) return;
1624
		if (mpar.hit_type > 0)
1625
		{
1626
			double shift_x = xpar.shift, shift_y = ypar.shift;
1627
			ApplyHit(data0, data0 + size);
1628
			data0 += size;
1629
			GetPaintOrigin(w, h, x, y, xx, yy);
1630
			xpar.shift = shift_x; ypar.shift = shift_y;
1631
		}
1632
		else GetPaintOrigin(w, h, x, y, xx, yy);
1633
		APosPixel pixel(xpar.p, ypar.p, data0);
1634
		j = menu0;
1635
		if (j < 0) j = 0;
1636
		else if (j > yy) j = yy;
1637
		for (i = j * xpar.win; i > 0; i--)
1638
		{
1639
			*(p++) = bgcolor[0]; *(p++) = bgcolor[1]; *(p++) = bgcolor[2];
1640
		}
1641
		i = menu1;
1642
		if (i < 0) i = 0;
1643
		else if (i > yy) i = yy;
1644
		p += 3 * xpar.win * (i - j);
1645
		for (i = (yy - i) * xpar.win; i > 0; i--)
1646
		{
1647
			*(p++) = bgcolor[0]; *(p++) = bgcolor[1]; *(p++) = bgcolor[2];
1648
		}
1649
		for (i = 0; i < h; i++)
1650
		{
1651
			for (j = xx; j > 0; j--)
1652
			{
1653
				*(p++) = bgcolor[0]; *(p++) = bgcolor[1]; *(p++) = bgcolor[2];
1654
			}
1655
			pixel.SetTo(x, (y + i) % ypar.p);
1656
			j = xpar.p - x;
1657
			if (j > w) j = w;
1658
			for (;;)
1659
			{
1660
				if (pixel.GetPixel()) {*(p++) = 255; *(p++) = 255; *(p++) = 255;}
1661
				else {*(p++) = 0; *(p++) = 0; *(p++) = 0;}
1662
				if (--j <= 0) break;
1663
				pixel.AddX1();
1664
			}
1665
			j = w - (xpar.p - x);
1666
			if (j > 0)
1667
			{
1668
				pixel.SetTo(0, (y + i) % ypar.p);
1669
				for (;;)
1670
				{
1671
					if (pixel.GetPixel()) {*(p++) = 255; *(p++) = 255; *(p++) = 255;}
1672
					else {*(p++) = 0; *(p++) = 0; *(p++) = 0;}
1673
					if (--j <= 0) break;
1674
					pixel.AddX1();
1675
				}
1676
			}
1677
			for (j = xpar.win - xx - w; j > 0; j--)
1678
			{
1679
				*(p++) = bgcolor[0]; *(p++) = bgcolor[1]; *(p++) = bgcolor[2];
1680
			}
1681
		}
1682
		j = menu0;
1683
		if (j < yy + h) j = yy + h;
1684
		else if (j > ypar.win) j = ypar.win;
1685
		for (i = (j - yy - h) * xpar.win; i > 0; i--)
1686
		{
1687
			*(p++) = bgcolor[0]; *(p++) = bgcolor[1]; *(p++) = bgcolor[2];
1688
		}
1689
		i = menu1;
1690
		if (i < yy + h) i = yy + h;
1691
		else if (i > ypar.win) i = ypar.win;
1692
		p += 3 * xpar.win * (i - j);
1693
		for (i = (ypar.win - i) * xpar.win; i > 0; i--)
1694
		{
1695
			*(p++) = bgcolor[0]; *(p++) = bgcolor[1]; *(p++) = bgcolor[2];
1696
		}
1697
	}
1698
	if (what & PaintWSpeed) CalculateSpeed();
1699
	MenuPaint(what);
1700
	SetPicture(picture, (unsigned short)xpar.win, (unsigned short)ypar.win, th);
1701
}
1702
 
1703
bool MenuetOnStart(TStartData &me_start, TThreadData th)
1704
{
1705
	randomize();
1706
	me_start.WinData.Title = "Black and white Life";
1707
	me_start.Width = 500; me_start.Height = 400;
1708
	InitGenerate();
1709
	InitMenuButton();
1710
	if (CommandLine[0])
1711
	{
1712
		open_file_str.state = 2;
1713
		OpenFileSetName(open_file_str, CommandLine);
1714
	}
1715
	return true;
1716
}
1717
 
1718
bool MenuetOnClose(TThreadData)
1719
{
1720
	SetPictureSize(0, 0);
1721
	SetPoleSize(0, 0);
1722
	return true;
1723
}
1724
 
1725
int MenuetOnIdle(TThreadData th)
1726
{
1727
	static const unsigned int WAIT_TIME = 2, GEN_TIME = 1;
1728
	int res = -1;
1729
	if (OpenFileGetState(open_file_str) > 0)
1730
	{
1731
		MenuOpenDialogEnd(th);
1732
		res = 0;
1733
	}
1734
	else
1735
	{
1736
		if (life_data && menu.button[MenuIGenerate].check)
1737
		{
1738
			unsigned int t = Clock() - generate.time;
1739
			if (t >= (unsigned int)(-WAIT_TIME)) res = -t;
1740
			else
1741
			{
1742
				MoveGenerateTime(t);
1743
				if (generate.count > 0)
1744
				{
1745
					unsigned char *data0 = (unsigned char*)GetDataAddress(life_data);
1746
					int size = GetDataSize(xpar.p, ypar.p);
1747
					int flag = (menu.button[MenuIHCircle].check ? 4 : 1) +
1748
								(menu.button[MenuIVCircle].check ? 8 : 2);
1749
					if (++timegenpos >= TimeGenLength) timegenpos = 0;
1750
					timegen[timegenpos].t = 0;
1751
					timegen[timegenpos].g = 0;
1752
					for (;;)
1753
					{
1754
						OneGeneration(xpar.p, ypar.p, data0 + size, data0, flag);
1755
						if (menu.button[MenuIRandom].check) RandomDraw(data0 + size);
1756
						timegen[timegenpos].g++;
1757
						if (--generate.count == 0 || (unsigned int)(Clock() - generate.time) >= GEN_TIME)
1758
						{
1759
							MemCopy(data0, data0 + size, size);
1760
							break;
1761
						}
1762
						OneGeneration(xpar.p, ypar.p, data0, data0 + size, flag);
1763
						if (menu.button[MenuIRandom].check) RandomDraw(data0);
1764
						timegen[timegenpos].g++;
1765
						if (--generate.count == 0 || (unsigned int)(Clock() - generate.time) >= GEN_TIME) break;
1766
					}
1767
					generate.paint |= PaintWPole | PaintWSpeed;
1768
				}
1769
				if (generate.stop && generate.count == 0)
1770
				{
1771
					ResetGenerate();
1772
					menu.button[MenuIGenerate].check = false;
1773
					generate.paint |= PaintWMenuBorder | PaintWSpeed;
1774
					res = -1;
1775
				}
1776
				else
1777
				{
1778
					MoveGenerateTime(Clock() - generate.time);
1779
					res = (generate.count <= generate.gps / 100) ? WAIT_TIME : 0;
1780
					MoveGenerateTime(res);
1781
				}
1782
			}
1783
		}
1784
	}
1785
	if (generate.paint)
1786
	{
1787
		Paint((res < 0 || res > WAIT_TIME) ? (PaintWNull | PaintWNow) : PaintWNull, th);
1788
	}
1789
	return res;
1790
}
1791
 
1792
void MenuetOnSize(int window_rect[], Menuet::TThreadData th)
1793
{
1794
	unsigned short w, h;
1795
	GetClientSize(w, h, window_rect[2], window_rect[3], th);
1796
	SetPictureSize(w, h);
1797
	generate.paint |= PaintWAll | PaintWFast;
1798
	if (!life_data) MenuWinSizeClick(th);
1799
	Paint(PaintWNull | PaintWNow, th);
1800
}
1801
 
1802
void MenuetOnKeyPress(TThreadData th)
1803
{
1804
	int ch;
1805
	while ((ch = GetKey()) >= 0)
1806
	{
1807
		if (mpar.hit_type > 0)
1808
		{
1809
			mpar.hit_type = 0;
1810
			generate.paint |= PaintWPole | PaintWFast;
1811
			SetMenuPressed(-1, th);
1812
			if (generate.paint) Paint(PaintWNull, th);
1813
		}
1814
		else if (menu.pressed >= 0) SetMenuPressed(-1, th);
1815
		else if (menu.edit >= 0) MenuEditPressKey(ch, th);
1816
		else
1817
		{
1818
			switch (ch)
1819
			{
1820
			case 'm':
1821
			case 'M':
1822
				SetMenuDraw(!menu.draw, th);
1823
				break;
1824
			case 'c':
1825
			case 'C':
1826
				MenuClearClick(th);
1827
				break;
1828
			case 'o':
1829
			case 'O':
1830
				if (OpenFileGetState(open_file_str) < 0) break;
1831
				OpenFileDialog(open_file_str);
1832
				break;
1833
			case 'a':
1834
			case 'A':
1835
				MenuAboutClick(th);
1836
				break;
1837
			case 'q':
1838
			case 'Q':
1839
				CloseWindow(th);
1840
				break;
1841
			case 'w':
1842
			case 'W':
1843
				MenuWinSizeClick(th);
1844
				break;
1845
			case 'g':
1846
			case 'G':
1847
				MenuGenerateClick(th);
1848
				break;
1849
			case 'r':
1850
			case 'R':
1851
				menu.button[MenuIRandom].check = !menu.button[MenuIRandom].check;
1852
				Paint(PaintWMenuBorder | PaintWFast, th);
1853
				break;
1854
			case 'v':
1855
			case 'V':
1856
				menu.button[MenuIVCircle].check = !menu.button[MenuIVCircle].check;
1857
				Paint(PaintWMenuBorder | PaintWFast, th);
1858
				break;
1859
			case 'h':
1860
			case 'H':
1861
				menu.button[MenuIHCircle].check = !menu.button[MenuIHCircle].check;
1862
				Paint(PaintWMenuBorder | PaintWFast, th);
1863
				break;
1864
			case 'l':
1865
			case 'L':
1866
				SetMenuCurrent(MenuILine, th);
1867
				break;
1868
			case 's':
1869
			case 'S':
1870
				SetMenuCurrent(MenuIScroll, th);
1871
				break;
1872
			case 'x':
1873
			case 'X':
1874
				if (!menu.draw) SetMenuDraw(true, th);
1875
				SetMenuEdit(MenuISize, 0, th);
1876
				break;
1877
			case 'y':
1878
			case 'Y':
1879
				if (!menu.draw) SetMenuDraw(true, th);
1880
				SetMenuEdit(MenuISize, 1, th);
1881
				break;
1882
			case 'f':
1883
			case 'F':
1884
				if (!menu.draw) SetMenuDraw(true, th);
1885
				SetMenuEdit(MenuISpeed, 0, th);
1886
				break;
1887
			case ' ':
1888
			case '\\':
1889
			case '|':
1890
				if (menu.button[MenuIGenerate].check && !generate.stop)
1891
				{
1892
					menu.button[MenuIGenerate].check = false;
1893
					Paint(PaintWMenuBorder | PaintWSpeed | PaintWFast, th);
1894
				}
1895
				else AddGenerateCount((ch == ' ') ? 1 : 15);
1896
				break;
1897
			}
1898
		}
1899
	}
1900
}
1901
 
1902
void MenuetOnMouse(TThreadData th)
1903
{
1904
	short xp = 0, yp = 0;
1905
	int w, h, x, y, xx, yy, m;
1906
	GetMousePosPicture(xp, yp);
1907
	m = GetMouseButton();
1908
	GetPaintOrigin(w, h, x, y, xx, yy);
1909
	x += xp - xx;
1910
	y += yp - yy;
1911
	if (mpar.hit_type > 0)
1912
	{
1913
		if (mpar.last_x != x || mpar.last_y != y)
1914
		{
1915
			mpar.last_x = x; mpar.last_y = y;
1916
			generate.paint |= PaintWPole | PaintWFast;
1917
		}
1918
		if (m != mpar.button)
1919
		{
1920
			if ((m & ~mpar.button) == 0) ApplyHit();
1921
			mpar.hit_type = 0;
1922
			generate.paint |= PaintWPole | PaintWFast;
1923
			SetMenuPressed(-1, th);
1924
			if (generate.paint) Paint(PaintWNull, th);
1925
		}
1926
	}
1927
	else if (menu.pressed >= 0)
1928
	{
1929
		if (mpar.last_x != x || mpar.last_y != y)
1930
		{
1931
			MenuMouseClick(xp, yp, -1, th);
1932
		}
1933
		if (m != mpar.button)
1934
		{
1935
			if ((m & ~mpar.button) == 0) MenuMouseClick(xp, yp, 0, th);
1936
			SetMenuPressed(-1, th);
1937
		}
1938
	}
1939
	else if (mpar.button == 0 && (m == 1 || m == 2))
1940
	{
1941
		if (xp >= 0 && xp < xpar.win && yp >= 0 && yp < ypar.win)
1942
		{
1943
			mpar.hit_x = x; mpar.hit_y = y; mpar.last_x = x; mpar.last_y = y;
1944
			yy = GetMenuYPos();
1945
			if (menu.edit >= 0 || (yp >= yy && yp < yy + GetMenuHeight()))
1946
			{
1947
				MenuMouseClick(xp, yp, m, th);
1948
			}
1949
			else PoleMouseClick(m, th);
1950
		}
1951
	}
1952
	mpar.button = m;
1953
}
1954
 
1955
#ifndef __MENUET__
1956
 
1957
#include 
1958
 
1959
void __stdcall (*DllOneGeneration)(int w, int h, void *dest, const void *src, int flag) = 0;
1960
 
1961
void DllInit()
1962
{
1963
	HINSTANCE hLib = LoadLibrary("LifeGen.dll");
1964
	if (!hLib)
1965
	{
1966
		DebugPutString("Can't load the library.\n");
1967
		Menuet::Abort();
1968
	}
1969
	DllOneGeneration = (void(__stdcall*)(int, int, void*, const void*, int))GetProcAddress(hLib, "OneGeneration");
1970
	if (!DllOneGeneration)
1971
	{
1972
		DebugPutString("Can't get a library function.\n");
1973
		Menuet::Abort();
1974
	}
1975
}
1976
 
1977
void __stdcall OneGeneration(int w, int h, void *dest, const void *src, int flag)
1978
{
1979
	if (!DllOneGeneration) DllInit();
1980
	DllOneGeneration(w, h, dest, src, flag);
1981
}
1982
 
1983
#endif
1984