1 //------------------------------------------------------------------------------
2 // emMinesPanel.cpp
3 //
4 // Copyright (C) 2005-2008,2016 Oliver Hamann.
5 //
6 // Homepage: http://eaglemode.sourceforge.net/
7 //
8 // This program is free software: you can redistribute it and/or modify it under
9 // the terms of the GNU General Public License version 3 as published by the
10 // Free Software Foundation.
11 //
12 // This program is distributed in the hope that it will be useful, but WITHOUT
13 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 // FOR A PARTICULAR PURPOSE. See the GNU General Public License version 3 for
15 // more details.
16 //
17 // You should have received a copy of the GNU General Public License version 3
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 //------------------------------------------------------------------------------
20 
21 #include <emMines/emMinesControlPanel.h>
22 #include <emMines/emMinesPanel.h>
23 
24 
emMinesPanel(ParentArg parent,const emString & name,emMinesFileModel * fileModel)25 emMinesPanel::emMinesPanel(
26 	ParentArg parent, const emString & name, emMinesFileModel * fileModel
27 )
28 	: emFilePanel(parent,name,fileModel,true)
29 {
30 	Mdl=fileModel;
31 	HaveControlPanel=IsVFSGood();
32 	CursorX=-1;
33 	CursorY=-1;
34 	CursorZ=-1;
35 	AddWakeUpSignal(Mdl->GetChangeSignal());
36 	AddWakeUpSignal(GetVirFileStateSignal());
37 	PrepareTransformation();
38 }
39 
40 
~emMinesPanel()41 emMinesPanel::~emMinesPanel()
42 {
43 }
44 
45 
GetTitle() const46 emString emMinesPanel::GetTitle() const
47 {
48 	return "Mines";
49 }
50 
51 
GetIconFileName() const52 emString emMinesPanel::GetIconFileName() const
53 {
54 	return "mines.tga";
55 }
56 
57 
GetEssenceRect(double * pX,double * pY,double * pW,double * pH) const58 void emMinesPanel::GetEssenceRect(
59 	double * pX, double * pY, double * pW, double * pH
60 ) const
61 {
62 	*pX=EssenceX;
63 	*pY=EssenceY;
64 	*pW=EssenceW;
65 	*pH=EssenceH;
66 }
67 
68 
Cycle()69 bool emMinesPanel::Cycle()
70 {
71 	bool vfsGood;
72 
73 	if (IsSignaled(GetVirFileStateSignal())) {
74 		vfsGood=IsVFSGood();
75 		if (HaveControlPanel!=vfsGood) {
76 			HaveControlPanel=vfsGood;
77 			InvalidateControlPanel();
78 		}
79 	}
80 
81 	if (
82 		IsSignaled(GetVirFileStateSignal()) ||
83 		IsSignaled(Mdl->GetChangeSignal())
84 	) {
85 		PrepareTransformation();
86 		InvalidatePainting();
87 	}
88 
89 	return emFilePanel::Cycle();
90 }
91 
92 
Notice(NoticeFlags flags)93 void emMinesPanel::Notice(NoticeFlags flags)
94 {
95 	emFilePanel::Notice(flags);
96 	if ((flags&NF_VIEWING_CHANGED)!=0) {
97 		CursorX=-1;
98 		CursorY=-1;
99 		CursorZ=-1;
100 		PrepareTransformation();
101 	}
102 }
103 
104 
Input(emInputEvent & event,const emInputState & state,double mx,double my)105 void emMinesPanel::Input(
106 	emInputEvent & event, const emInputState & state, double mx, double my
107 )
108 {
109 	int x,y,z,cx,cy,cz;
110 	double dx,dy,d,dmin;
111 
112 	if (!IsViewed() || !IsVFSGood()) {
113 		CursorX=-1;
114 		CursorY=-1;
115 		CursorZ=-1;
116 		emFilePanel::Input(event,state,mx,my);
117 		return;
118 	}
119 
120 	cx=-1;
121 	cy=-1;
122 	cz=-1;
123 	if (
124 		mx>=0 && mx<1.0 && my>=0 && my<GetHeight() &&
125 		IsViewed() &&
126 		PanelToViewX(mx)>=GetClipX1() && PanelToViewX(mx)<GetClipX2() &&
127 		PanelToViewY(my)>=GetClipY1() && PanelToViewY(my)<GetClipY2() &&
128 		!Mdl->IsGameWon() && !Mdl->IsGameLost()
129 	) {
130 		dmin=(TransX(1,0)-TransX(0,0))*0.5;
131 		dmin*=dmin;
132 		for (z=Mdl->GetSizeZ()-1; z>=0 && z>CameraZ+0.5; z--) {
133 			for (y=Mdl->GetSizeY()-1; y>=0; y--) {
134 				for (x=Mdl->GetSizeX()-1; x>=0; x--) {
135 					dx=mx-TransX(x,z);
136 					dy=my-TransY(y,z);
137 					d=dx*dx+dy*dy;
138 					if (d<dmin) {
139 						dmin=d; cx=x; cy=y; cz=z;
140 					}
141 				}
142 			}
143 		}
144 	}
145 	if (CursorX!=cx || CursorY!=cy || CursorZ!=cz) {
146 		CursorX=cx;
147 		CursorY=cy;
148 		CursorZ=cz;
149 		InvalidatePainting();
150 	}
151 
152 	switch (event.GetKey()) {
153 	case EM_KEY_LEFT_BUTTON:
154 		if (state.IsNoMod()) {
155 			if (IsCursorValid() && !Mdl->IsGameWon() && !Mdl->IsGameLost()) {
156 				Mdl->OpenField(CursorX,CursorY,CursorZ);
157 			}
158 			Focus();
159 			event.Eat();
160 		}
161 		break;
162 	case EM_KEY_RIGHT_BUTTON:
163 		if (state.IsNoMod()) {
164 			if (IsCursorValid() && !Mdl->IsGameWon() && !Mdl->IsGameLost()) {
165 				Mdl->InvertMark(CursorX,CursorY,CursorZ);
166 			}
167 			Focus();
168 			event.Eat();
169 		}
170 		break;
171 	case EM_KEY_N:
172 		if (state.IsCtrlMod()) {
173 			Mdl->StartGame(
174 				Mdl->GetSizeX(),
175 				Mdl->GetSizeY(),
176 				Mdl->GetSizeZ(),
177 				Mdl->GetMineCount()
178 			);
179 			event.Eat();
180 		}
181 		break;
182 	case EM_KEY_1:
183 		if (state.IsCtrlMod()) {
184 			Mdl->StartGame(1);
185 			event.Eat();
186 		}
187 		break;
188 	case EM_KEY_2:
189 		if (state.IsCtrlMod()) {
190 			Mdl->StartGame(2);
191 			event.Eat();
192 		}
193 		break;
194 	case EM_KEY_3:
195 		if (state.IsCtrlMod()) {
196 			Mdl->StartGame(3);
197 			event.Eat();
198 		}
199 		break;
200 	case EM_KEY_4:
201 		if (state.IsCtrlMod()) {
202 			Mdl->StartGame(4);
203 			event.Eat();
204 		}
205 		break;
206 	case EM_KEY_5:
207 		if (state.IsCtrlMod()) {
208 			Mdl->StartGame(5);
209 			event.Eat();
210 		}
211 		break;
212 	default:
213 		break;
214 	}
215 
216 	emFilePanel::Input(event,state,mx,my);
217 }
218 
219 
IsOpaque() const220 bool emMinesPanel::IsOpaque() const
221 {
222 	if (IsVFSGood()) return true;
223 	else return emFilePanel::IsOpaque();
224 }
225 
226 
Paint(const emPainter & painter,emColor canvasColor) const227 void emMinesPanel::Paint(const emPainter & painter, emColor canvasColor) const
228 {
229 	emColor color;
230 	double tx,ty,tz,tw,th;
231 	int x,y,z,cx,cy,sx,sy,sz;
232 
233 	if (!IsVFSGood()) {
234 		emFilePanel::Paint(painter,canvasColor);
235 		return;
236 	}
237 
238 	painter.Clear(
239 		Mdl->IsGameWon()?emColor(34,34,102):
240 			Mdl->IsGameLost()?emColor(102,17,0):
241 				emColor(emColor::BLACK),
242 		canvasColor
243 	);
244 
245 	sx=Mdl->GetSizeX();
246 	sy=Mdl->GetSizeY();
247 	sz=Mdl->GetSizeZ();
248 	cx=(int)ceil(CameraX);
249 	cy=(int)ceil(CameraY);
250 	if (cx<0) cx=0; else if (cx>sx-1) cx=sx-1;
251 	if (cy<0) cy=0; else if (cy>sy-1) cy=sy-1;
252 
253 	for (z=sz-1; z>=0 && z>CameraZ+0.5; z--) {
254 		color.SetHSVA(
255 			60.0F*(z%6),
256 			55.0F,
257 			400.0F/(z+4),
258 			255
259 		);
260 		for (y=0; y<cy; y++) {
261 			for (x=0; x<cx; x++) {
262 				PaintField(painter,x,y,z,color);
263 			}
264 		}
265 		for (y=0; y<cy; y++) {
266 			for (x=sx-1; x>=cx; x--) {
267 				PaintField(painter,x,y,z,color);
268 			}
269 		}
270 		for (y=sy-1; y>=cy; y--) {
271 			for (x=0; x<cx; x++) {
272 				PaintField(painter,x,y,z,color);
273 			}
274 		}
275 		for (y=sy-1; y>=cy; y--) {
276 			for (x=sx-1; x>=cx; x--) {
277 				PaintField(painter,x,y,z,color);
278 			}
279 		}
280 	}
281 
282 	if (IsCursorValid()) {
283 		color=emColor(255,255,255,192);
284 		PaintField(painter,CursorX,CursorY,CursorZ,color);
285 	}
286 
287 	if (Mdl->IsGameWon() || Mdl->IsGameLost()) {
288 		tz=-1.0;
289 		if (tz>CameraZ+0.5) {
290 			tx=TransX(0,tz);
291 			ty=TransY(0,tz);
292 			tw=TransX(Mdl->GetSizeX()-1,tz)-tx;
293 			th=TransY(Mdl->GetSizeY()-1,tz)-ty;
294 			tx+=0.125*tw;
295 			ty+=0.125*th;
296 			tw*=0.75;
297 			th*=0.75;
298 			painter.PaintTextBoxed(
299 				tx,
300 				ty,
301 				tw,
302 				th,
303 				Mdl->IsGameLost() ? "Game over" : "Success!",
304 				th,
305 				Mdl->IsGameLost() ? emColor(255,0,0,128) : emColor(0,0,255,128),
306 				0,
307 				EM_ALIGN_CENTER,
308 				EM_ALIGN_CENTER,
309 				1.0
310 			);
311 		}
312 	}
313 }
314 
315 
CreateControlPanel(ParentArg parent,const emString & name)316 emPanel * emMinesPanel::CreateControlPanel(
317 	ParentArg parent, const emString & name
318 )
319 {
320 	if (HaveControlPanel) {
321 		return new emMinesControlPanel(parent,name,Mdl);
322 	}
323 	else {
324 		return emFilePanel::CreateControlPanel(parent,name);
325 	}
326 }
327 
328 
PaintField(const emPainter & painter,int x,int y,int z,emColor color) const329 void emMinesPanel::PaintField(
330 	const emPainter & painter, int x, int y, int z, emColor color
331 ) const
332 {
333 	static const double br=0.002;
334 	static const double fr=0.08;
335 	int sizeX,sizeY,sizeZ,surroundings,xybeams;
336 	bool isOpen,isMine,isMarked;
337 
338 	sizeX=Mdl->GetSizeX();
339 	sizeY=Mdl->GetSizeY();
340 	sizeZ=Mdl->GetSizeZ();
341 	surroundings=Mdl->GetSurroundings(x,y,z);
342 	isOpen=Mdl->IsOpen(x,y,z);
343 	isMine=Mdl->IsMine(x,y,z);
344 	isMarked=Mdl->IsMarked(x,y,z);
345 
346 	painter.LeaveUserSpace();
347 
348 	if (z+1<sizeZ) PaintZBeam(painter,x,y,z+fr,z+0.5,br,color);
349 
350 	xybeams=0;
351 	if (x>0) {
352 		if (x-fr<=CameraX) PaintXBeam(painter,x-0.5,y,z,x-fr,br,color);
353 		else xybeams|=1;
354 	}
355 	if (x+1<sizeX) {
356 		if (x+fr>=CameraX) PaintXBeam(painter,x+fr,y,z,x+0.5,br,color);
357 		else xybeams|=2;
358 	}
359 	if (y>0) {
360 		if (y-fr<=CameraY) PaintYBeam(painter,x,y-0.5,z,y-fr,br,color);
361 		else xybeams|=4;
362 	}
363 	if (y+1<sizeY) {
364 		if (y+fr>=CameraY) PaintYBeam(painter,x,y+fr,z,y+0.5,br,color);
365 		else xybeams|=8;
366 	}
367 
368 	if (isOpen) {
369 		if (isMine) PaintExplodingField(painter,x,y,z,fr);
370 		else PaintOpenField(painter,x,y,z,fr,surroundings,color);
371 	}
372 	else if (isMarked) PaintMarkedField(painter,x,y,z,fr,color);
373 	else PaintClosedField(painter,x,y,z,fr,color);
374 
375 	if ((xybeams&1)!=0) PaintXBeam(painter,x-0.5,y,z,x-fr,br,color);
376 	if ((xybeams&2)!=0) PaintXBeam(painter,x+fr,y,z,x+0.5,br,color);
377 	if ((xybeams&4)!=0) PaintYBeam(painter,x,y-0.5,z,y-fr,br,color);
378 	if ((xybeams&8)!=0) PaintYBeam(painter,x,y+fr,z,y+0.5,br,color);
379 	if (z>0) PaintZBeam(painter,x,y,z-0.5,z-fr,br,color);
380 
381 	painter.EnterUserSpace();
382 }
383 
384 
PaintClosedField(const emPainter & painter,double x,double y,double z,double r,emColor color) const385 void emMinesPanel::PaintClosedField(
386 	const emPainter & painter, double x, double y, double z, double r,
387 	emColor color
388 ) const
389 {
390 	double x11,y11,x12,y12,x21,y21,x22,y22;
391 	double xy[4*2];
392 	emColor cl,cr,ct,cb;
393 
394 	cl=color.GetLighted(-20.0f);
395 	cr=color.GetLighted(-30.0f);
396 	ct=color.GetLighted(-10.0f);
397 	cb=color.GetLighted(-40.0f);
398 
399 	x11=TransX(x-r,z-r);
400 	y11=TransY(y-r,z-r);
401 	x12=TransX(x-r,z+r);
402 	y12=TransY(y-r,z+r);
403 	x21=TransX(x+r,z-r);
404 	y21=TransY(y+r,z-r);
405 	x22=TransX(x+r,z+r);
406 	y22=TransY(y+r,z+r);
407 
408 	painter.PaintRect(x11,y11,x21-x11,y21-y11,color);
409 	if (x12<x11) {
410 		xy[0]=x11; xy[1]=y11;
411 		xy[2]=x11; xy[3]=y21;
412 		xy[4]=x12; xy[5]=y22;
413 		xy[6]=x12; xy[7]=y12;
414 		painter.PaintPolygon(xy,4,cl);
415 		painter.PaintEdgeCorrection(x11,y11,x11,y21,color,cl);
416 	}
417 	else if (x22>x21) {
418 		xy[0]=x21; xy[1]=y11;
419 		xy[2]=x21; xy[3]=y21;
420 		xy[4]=x22; xy[5]=y22;
421 		xy[6]=x22; xy[7]=y12;
422 		painter.PaintPolygon(xy,4,cr);
423 		painter.PaintEdgeCorrection(x21,y21,x21,y11,color,cr);
424 	}
425 	if (y12<y11) {
426 		xy[0]=x11; xy[1]=y11;
427 		xy[2]=x21; xy[3]=y11;
428 		xy[4]=x22; xy[5]=y12;
429 		xy[6]=x12; xy[7]=y12;
430 		painter.PaintPolygon(xy,4,ct);
431 		painter.PaintEdgeCorrection(x21,y11,x11,y11,color,ct);
432 		if (x12<x11) painter.PaintEdgeCorrection(x11,y11,x12,y12,cl,ct);
433 		else if (x22>x21) painter.PaintEdgeCorrection(x22,y12,x21,y11,cr,ct);
434 	}
435 	else if (y22>y21) {
436 		xy[0]=x11; xy[1]=y21;
437 		xy[2]=x21; xy[3]=y21;
438 		xy[4]=x22; xy[5]=y22;
439 		xy[6]=x12; xy[7]=y22;
440 		painter.PaintPolygon(xy,4,cb);
441 		painter.PaintEdgeCorrection(x11,y21,x21,y21,color,cb);
442 		if (x12<x11) painter.PaintEdgeCorrection(x12,y22,x11,y21,cl,cb);
443 		else if (x22>x21) painter.PaintEdgeCorrection(x21,y21,x22,y22,cr,cb);
444 	}
445 }
446 
447 
PaintMarkedField(const emPainter & painter,double x,double y,double z,double r,emColor color) const448 void emMinesPanel::PaintMarkedField(
449 	const emPainter & painter, double x, double y, double z, double r,
450 	emColor color
451 ) const
452 {
453 	static const float light[8]={-45,-40,-30,-20,-5,-10,-20,-30};
454 	double x1[8],y1[8],x2[8],y2[8],x3[8],y3[8];
455 	double xy[8*2];
456 	double nx,ny;
457 	int i,k,v1,v2;
458 	emColor c1[8],c2[8];
459 	emColor cwarn;
460 
461 	cwarn=color.GetBlended(emColor(255,0,0,color.GetAlpha()),25.0f);
462 
463 	for (i=0; i<8; i++) {
464 		nx=r*cos((i+0.5)*(M_PI*0.25));
465 		ny=r*sin((i+0.5)*(M_PI*0.25));
466 		x1[i]=TransX(x+nx*0.448,z-r      );
467 		y1[i]=TransY(y+ny*0.448,z-r      );
468 		x2[i]=TransX(x+nx*1.082,z-r*0.414);
469 		y2[i]=TransY(y+ny*1.082,z-r*0.414);
470 		x3[i]=TransX(x+nx*1.082,z+r*0.414);
471 		y3[i]=TransY(y+ny*1.082,z+r*0.414);
472 		if ((i&1)!=0) {
473 			c1[i]=color.GetLighted(light[i]*0.5F);
474 			c2[i]=cwarn.GetLighted(light[i]);
475 		}
476 		else {
477 			c1[i]=cwarn.GetLighted(light[i]*0.5F);
478 			c2[i]=color.GetLighted(light[i]);
479 		}
480 	}
481 
482 	v1=0;
483 	v2=0;
484 	for (i=0; i<8; i++) {
485 		k=(i+1)&7;
486 		xy[0]=x2[i]; xy[1]=y2[i];
487 		xy[2]=x2[k]; xy[3]=y2[k];
488 		xy[4]=x3[k]; xy[5]=y3[k];
489 		xy[6]=x3[i]; xy[7]=y3[i];
490 		if ((xy[0]-xy[2])*(xy[7]-xy[1])+(xy[3]-xy[1])*(xy[6]-xy[0])>0.0) {
491 			painter.PaintPolygon(xy,4,c2[i]);
492 			v2|=1<<i;
493 		}
494 		xy[0]=x1[i]; xy[1]=y1[i];
495 		xy[2]=x1[k]; xy[3]=y1[k];
496 		xy[4]=x2[k]; xy[5]=y2[k];
497 		xy[6]=x2[i]; xy[7]=y2[i];
498 		if ((xy[0]-xy[2])*(xy[7]-xy[1])+(xy[3]-xy[1])*(xy[6]-xy[0])>0.0) {
499 			painter.PaintPolygon(xy,4,c1[i]);
500 			v1|=1<<i;
501 		}
502 	}
503 	for (i=0; i<8; i++) {
504 		xy[i*2]=x1[i];
505 		xy[i*2+1]=y1[i];
506 	}
507 	painter.PaintPolygon(xy,8,color);
508 
509 	for (i=0; i<8; i++) {
510 		k=(i+1)&7;
511 		if ((v2&(1<<i))!=0 && (v2&(1<<k))!=0) {
512 			if (!k) painter.PaintEdgeCorrection(x3[k],y3[k],x2[k],y2[k],c2[k],c2[i]);
513 			else painter.PaintEdgeCorrection(x2[k],y2[k],x3[k],y3[k],c2[i],c2[k]);
514 		}
515 		if ((v1&(1<<i))!=0) {
516 			if ((v1&(1<<k))!=0) {
517 				if (!k) painter.PaintEdgeCorrection(x2[k],y2[k],x1[k],y1[k],c1[k],c1[i]);
518 				else painter.PaintEdgeCorrection(x1[k],y1[k],x2[k],y2[k],c1[i],c1[k]);
519 			}
520 			painter.PaintEdgeCorrection(x1[i],y1[i],x1[k],y1[k],c1[i],color);
521 			if ((v2&(1<<i))!=0) {
522 				painter.PaintEdgeCorrection(x2[i],y2[i],x2[k],y2[k],c2[i],c1[i]);
523 			}
524 		}
525 	}
526 }
527 
528 
PaintOpenField(const emPainter & painter,double x,double y,double z,double r,int number,emColor color) const529 void emMinesPanel::PaintOpenField(
530 	const emPainter & painter, double x, double y, double z, double r,
531 	int number, emColor color
532 ) const
533 {
534 	double x1,y1,x2,y2;
535 	char numstr[64];
536 
537 	x1=TransX(x-r*1.2,z+r*0.1);
538 	y1=TransY(y-r*1.2,z+r*0.1);
539 	x2=TransX(x+r*1.2,z+r*0.1);
540 	y2=TransY(y+r*1.4,z+r*0.1);
541 	sprintf(numstr,"%d",number);
542 	painter.PaintTextBoxed(
543 		x1,y1,x2-x1,y2-y1,
544 		numstr,
545 		y2-y1,
546 		color.GetLighted(-25.0f)
547 	);
548 
549 	x1=TransX(x-r*1.2,z-r*0.1);
550 	y1=TransY(y-r*1.2,z-r*0.1);
551 	x2=TransX(x+r*1.2,z-r*0.1);
552 	y2=TransY(y+r*1.4,z-r*0.1);
553 	painter.PaintTextBoxed(
554 		x1,y1,x2-x1,y2-y1,
555 		numstr,
556 		y2-y1,
557 		color
558 	);
559 }
560 
561 
PaintExplodingField(const emPainter & painter,double x,double y,double z,double r) const562 void emMinesPanel::PaintExplodingField(
563 	const emPainter & painter, double x, double y, double z, double r
564 ) const
565 {
566 	static const struct { double x, y, z; } vertex[18]={
567 		{1347.62,-575.08,-864.97},
568 		{364.42,263.00,-316.07},
569 		{129.39,1088.80,-881.94},
570 		{-460.32,176.19,-316.07},
571 		{-1427.27,-577.16,-896.03},
572 		{-257.24,-525.68,-316.07},
573 		{-62.15,-1552.24,-896.03},
574 		{222.94,-491.38,-316.07},
575 		{0.00,0.00,0.00},
576 		{2190.00,-734.54,-426.79},
577 		{588.33,433.44,-179.60},
578 		{284.21,1851.23,-432.53},
579 		{-601.94,512.80,-179.60},
580 		{-2446.35,-754.52,-459.44},
581 		{-493.83,-856.07,-179.60},
582 		{-102.35,-2555.93,-459.44},
583 		{489.14,-875.85,-179.60},
584 		{0.00,0.00,0.00}
585 	};
586 	static const emColor colors[2]={
587 		emColor(255,255,0,192),
588 		emColor(255,0,0,255)
589 	};
590 	static const struct { int vi[3]; int ci; } poly[16]={
591 		{{15,16,17},0},
592 		{{17,16,9},0},
593 		{{17,9,10},0},
594 		{{11,17,10},0},
595 		{{11,12,17},0},
596 		{{13,17,12},0},
597 		{{17,13,14},0},
598 		{{14,15,17},0},
599 		{{6,7,8},1},
600 		{{8,7,0},1},
601 		{{8,0,1},1},
602 		{{2,8,1},1},
603 		{{2,3,8},1},
604 		{{4,8,3},1},
605 		{{8,4,5},1},
606 		{{5,6,8},1}
607 	};
608 	double xy[3*2];
609 	int i,j;
610 
611 	for (i=0; i<16; i++) {
612 		for (j=0; j<3; j++) {
613 			xy[j*2]=TransX(
614 				x+r*vertex[poly[i].vi[j]].x*0.004,
615 				z+r*vertex[poly[i].vi[j]].z*0.004
616 			);
617 			xy[j*2+1]=TransY(
618 				y+r*vertex[poly[i].vi[j]].y*0.004,
619 				z+r*vertex[poly[i].vi[j]].z*0.004
620 			);
621 		}
622 		painter.PaintPolygon(xy,3,colors[poly[i].ci]);
623 	}
624 }
625 
626 
PaintXBeam(const emPainter & painter,double x,double y,double z,double x2,double r,emColor color) const627 void emMinesPanel::PaintXBeam(
628 	const emPainter & painter, double x, double y, double z, double x2,
629 	double r, emColor color
630 ) const
631 {
632 	double x11,y11,x12,y12,x21,y21,x22,y22;
633 	double xy[4*2];
634 
635 	x11=TransX(x  ,z-r);
636 	y11=TransY(y-r,z-r);
637 	x12=TransX(x  ,z+r);
638 	y12=TransY(y-r,z+r);
639 	x21=TransX(x2 ,z-r);
640 	y21=TransY(y+r,z-r);
641 	x22=TransX(x2 ,z+r);
642 	y22=TransY(y+r,z+r);
643 	painter.PaintRect(x11,y11,x21-x11,y21-y11,color);
644 	if (y12<y11) {
645 		xy[0]=x11; xy[1]=y11;
646 		xy[2]=x21; xy[3]=y11;
647 		xy[4]=x22; xy[5]=y12;
648 		xy[6]=x12; xy[7]=y12;
649 		painter.PaintPolygon(xy,4,color.GetLighted(-10.0f));
650 	}
651 	else if (y22>y21) {
652 		xy[0]=x11; xy[1]=y21;
653 		xy[2]=x21; xy[3]=y21;
654 		xy[4]=x22; xy[5]=y22;
655 		xy[6]=x12; xy[7]=y22;
656 		painter.PaintPolygon(xy,4,color.GetLighted(-40.0f));
657 	}
658 }
659 
660 
PaintYBeam(const emPainter & painter,double x,double y,double z,double y2,double r,emColor color) const661 void emMinesPanel::PaintYBeam(
662 	const emPainter & painter, double x, double y, double z, double y2,
663 	double r, emColor color
664 ) const
665 {
666 	double x11,y11,x12,y12,x21,y21,x22,y22;
667 	double xy[4*2];
668 
669 	x11=TransX(x-r,z-r);
670 	y11=TransY(y  ,z-r);
671 	x12=TransX(x-r,z+r);
672 	y12=TransY(y  ,z+r);
673 	x21=TransX(x+r,z-r);
674 	y21=TransY(y2 ,z-r);
675 	x22=TransX(x+r,z+r);
676 	y22=TransY(y2 ,z+r);
677 	painter.PaintRect(x11,y11,x21-x11,y21-y11,color);
678 	if (x12<x11) {
679 		xy[0]=x11; xy[1]=y11;
680 		xy[2]=x11; xy[3]=y21;
681 		xy[4]=x12; xy[5]=y22;
682 		xy[6]=x12; xy[7]=y12;
683 		painter.PaintPolygon(xy,4,color.GetLighted(-20.0f));
684 	}
685 	else if (x22>x21) {
686 		xy[0]=x21; xy[1]=y11;
687 		xy[2]=x21; xy[3]=y21;
688 		xy[4]=x22; xy[5]=y22;
689 		xy[6]=x22; xy[7]=y12;
690 		painter.PaintPolygon(xy,4,color.GetLighted(-30.0f));
691 	}
692 }
693 
694 
PaintZBeam(const emPainter & painter,double x,double y,double z,double z2,double r,emColor color) const695 void emMinesPanel::PaintZBeam(
696 	const emPainter & painter, double x, double y, double z, double z2,
697 	double r, emColor color
698 ) const
699 {
700 	double x11,y11,x12,y12,x21,y21,x22,y22;
701 	double xy[4*2];
702 
703 	x11=TransX(x-r,z );
704 	y11=TransY(y-r,z );
705 	x12=TransX(x-r,z2);
706 	y12=TransY(y-r,z2);
707 	x21=TransX(x+r,z );
708 	y21=TransY(y+r,z );
709 	x22=TransX(x+r,z2);
710 	y22=TransY(y+r,z2);
711 	if (x12<x11) {
712 		xy[0]=x11; xy[1]=y11;
713 		xy[2]=x11; xy[3]=y21;
714 		xy[4]=x12; xy[5]=y22;
715 		xy[6]=x12; xy[7]=y12;
716 		painter.PaintPolygon(xy,4,color.GetLighted(-20.0f));
717 	}
718 	else if (x22>x21) {
719 		xy[0]=x21; xy[1]=y11;
720 		xy[2]=x21; xy[3]=y21;
721 		xy[4]=x22; xy[5]=y22;
722 		xy[6]=x22; xy[7]=y12;
723 		painter.PaintPolygon(xy,4,color.GetLighted(-30.0f));
724 	}
725 	if (y12<y11) {
726 		xy[0]=x11; xy[1]=y11;
727 		xy[2]=x21; xy[3]=y11;
728 		xy[4]=x22; xy[5]=y12;
729 		xy[6]=x12; xy[7]=y12;
730 		painter.PaintPolygon(xy,4,color.GetLighted(-10.0f));
731 	}
732 	else if (y22>y21) {
733 		xy[0]=x11; xy[1]=y21;
734 		xy[2]=x21; xy[3]=y21;
735 		xy[4]=x22; xy[5]=y22;
736 		xy[6]=x12; xy[7]=y22;
737 		painter.PaintPolygon(xy,4,color.GetLighted(-40.0f));
738 	}
739 }
740 
741 
IsCursorValid() const742 bool emMinesPanel::IsCursorValid() const
743 {
744 	return
745 		CursorX>=0 && CursorX<Mdl->GetSizeX() &&
746 		CursorY>=0 && CursorY<Mdl->GetSizeY() &&
747 		CursorZ>=0 && CursorZ<Mdl->GetSizeZ()
748 	;
749 }
750 
751 
TransX(double fieldX,double fieldZ) const752 double emMinesPanel::TransX(double fieldX, double fieldZ) const
753 {
754 	return (fieldX-CameraX)/(fieldZ-CameraZ)*TrScale+TrX0;
755 }
756 
757 
TransY(double fieldY,double fieldZ) const758 double emMinesPanel::TransY(double fieldY, double fieldZ) const
759 {
760 	return (fieldY-CameraY)/(fieldZ-CameraZ)*TrScale+TrY0;
761 }
762 
763 
PrepareTransformation()764 void emMinesPanel::PrepareTransformation()
765 {
766 	double h,k,s;
767 
768 	if (!IsViewed() || !IsVFSGood()) {
769 		EssenceX=0.0;
770 		EssenceY=0.0;
771 		EssenceW=1.0;
772 		EssenceH=GetHeight();
773 		CameraX=0;
774 		CameraY=0;
775 		CameraZ=1000;
776 		TrX0=0;
777 		TrY0=0;
778 		TrScale=1.0;
779 		return;
780 	}
781 
782 	h=GetHeight();
783 	s=emMin(h/Mdl->GetSizeY(),1.0/Mdl->GetSizeX())*0.9;
784 
785 	EssenceW=(Mdl->GetSizeX()-0.6)*s;
786 	EssenceH=(Mdl->GetSizeY()-0.6)*s;
787 	EssenceX=(1.0-EssenceW)*0.5;
788 	EssenceY=(h-EssenceH)*0.5;
789 
790 	TrX0=ViewToPanelX(GetView().GetCurrentX()+GetView().GetCurrentWidth()*0.5);
791 	TrY0=ViewToPanelY(GetView().GetCurrentY()+GetView().GetCurrentHeight()*0.5);
792 
793 	CameraX=TrX0/s+(Mdl->GetSizeX()-1-1.0/s)*0.5;
794 	CameraY=TrY0/s+(Mdl->GetSizeY()-1-h/s)*0.5;
795 	k=emMax(
796 		PanelToViewDeltaX(EssenceW)/GetView().GetCurrentWidth(),
797 		PanelToViewDeltaY(EssenceH)/GetView().GetCurrentHeight()
798 	);
799 	CameraZ=(Mdl->GetSizeX()*Mdl->GetSizeY())*0.5/k*0.21;
800 	TrScale=CameraZ*s;
801 	if (k>1.0) {
802 		TrScale*=k/(2.0-1.0/k);
803 		CameraZ*=1.0-(1.0-1.0/k)*log(k)*0.5;
804 	}
805 	CameraZ=-CameraZ;
806 }
807