Subversion Repositories Kolibri OS

Rev

Rev 1769 | Rev 8133 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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